From 5768d8e50129960737dfdc3f5da7532e6b6e1d66 Mon Sep 17 00:00:00 2001 From: davidsemakula Date: Wed, 1 Jan 2025 15:37:19 +0300 Subject: [PATCH] More robust "KnownNames" resolution --- Cargo.lock | 57 +- binaries/summary_store.tar | Bin 3656192 -> 3648000 bytes checker/src/block_visitor.rs | 5 +- checker/src/callbacks.rs | 3 +- checker/src/crate_visitor.rs | 2 +- checker/src/known_names.rs | 855 +++++++++--------- .../tests/run-pass/known_name_resolution.rs | 19 + 7 files changed, 489 insertions(+), 452 deletions(-) create mode 100644 checker/tests/run-pass/known_name_resolution.rs diff --git a/Cargo.lock b/Cargo.lock index 83f0c5fa..b3efcced 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,13 +93,13 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools", + "itertools 0.13.0", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.5" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" dependencies = [ "shlex", ] @@ -374,9 +374,9 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "fnv" @@ -416,15 +416,15 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "humantime" @@ -440,9 +440,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.7.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -472,6 +472,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -567,7 +576,7 @@ dependencies = [ "contracts", "env_logger", "fs2", - "itertools", + "itertools 0.14.0", "lazy_static", "log", "log-derive", @@ -643,9 +652,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.5" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "e2b1374ec32450264534c67d1ccb5ca09818c4db8fd87cf97478d0df2fa44c65" dependencies = [ "fixedbitset", "indexmap", @@ -848,22 +857,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -949,9 +958,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.92" +version = "2.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" dependencies = [ "proc-macro2", "quote", @@ -1013,7 +1022,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -1229,5 +1238,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] diff --git a/binaries/summary_store.tar b/binaries/summary_store.tar index 70f0b421fce59139331b61dd4e7754d6b69c7256..1687125b2dbde173a8b8fe3cf8163748fff094f8 100644 GIT binary patch delta 427 zcmajby-vbV0EXe#9|RN>te`@%_5b*T=d?Yi7vPnUu(&E1$0iIcE)^3O?}J@$fy7NN zfSd5`K*B;Cp7G6>e98ONPA0$hTmH48gHW3=@}$y1q%2RT{(UO_Qva#fd9S=iU=?dvM-Cgvqktkdv4s-K*v1Yj zsA3lm_E19|`#8WM8fYThY~ctVd>rEhr#QnoE^rBfD_r9Sw`k)I5()uAM9?r};l{Ji W59ceM-;o_|l!}($F&5wPPwo%9F>V(C delta 2311 zcmdVbO-~a+90u?$_JtPYMGJ_EZWWP=3^O~kJMMu)Atn$pRUk%A&C;%sq%XKFrk*76 zz(Fr7MmTtaPvD6!VuB|9e5>!i`g%x; z6jyRN%XyJ1mI{tdidj43#wK0b?q<|}O>mV7$vHQukW8gaQfeqF^)87;SBfReQ7C93wBi8bA)+WnN0pDch)3)MMl-J+ZetwU9{^9*1;nJh;-hl^J zdCImjwlj8IPQRCv(b}9E)wxjAa^svYIaPC|rJOy^B-b@vaLpu4W0aaw=n-A2Gt(1^ z*~zKtM|VltDwP~kFUol0VIr|KlAIb#F5J_Sg@`cKIovd}@VA?gzxCGwtbZJh*2X_r ziqW?%Q8!xduFlXf1hVN3v+adQYB5__EP7W4>lQ+zjLOqf2&_eCwG)To67?&<46dJ~ z0#s7YrPdr3cyna_62<(d`TI#Kv*-;!yph?Gb@u}<>8Tojdv*L?wvF_bjP>LH`r8J; z7{f;QzZ<|E-4w#)tU0FdubDowHk{b2cwj9a@Iecl0Y6mE1tA2j5QYe}K|7p<4(Nm~ z=!SD}9-`0#z0e02pdT*6CAbU&a0RY{3Ng3_*I^KDz!2PoVTi*m7=ha`3IxW00s{>= z2++aUi3jA~hagF%3;8ErxkJa6Tk^(B)ie(~>}?&@av!9dIE?mZy@h^)dNYlh+z@6{ VJm21L$(nxatnmYBC%!FrgZqvkiH`sP diff --git a/checker/src/block_visitor.rs b/checker/src/block_visitor.rs index 93ac2b2b..73892481 100644 --- a/checker/src/block_visitor.rs +++ b/checker/src/block_visitor.rs @@ -27,7 +27,7 @@ use rustc_span::source_map::Spanned; use rustc_target::abi::{FieldIdx, Primitive, TagEncoding, VariantIdx, Variants}; use rustc_trait_selection::infer::TyCtxtInferExt; -use crate::abstract_value::{AbstractValue, AbstractValueTrait, BOTTOM}; +use crate::abstract_value::{self, AbstractValue, AbstractValueTrait, BOTTOM}; use crate::body_visitor::BodyVisitor; use crate::call_visitor::CallVisitor; use crate::constant_domain::{ConstantDomain, FunctionReference}; @@ -43,7 +43,6 @@ use crate::summaries::Precondition; use crate::tag_domain::Tag; use crate::type_visitor::TypeVisitor; use crate::utils; -use crate::{abstract_value, known_names}; /// Holds the state for the basic block visitor pub struct BlockVisitor<'block, 'analysis, 'compilation, 'tcx> { @@ -722,7 +721,6 @@ impl<'block, 'analysis, 'compilation, 'tcx> BlockVisitor<'block, 'analysis, 'com .block_to_call .insert(current_location, callee_def_id); - let tcx = self.bv.tcx; let mut call_visitor = CallVisitor::new( self, callee_def_id, @@ -753,7 +751,6 @@ impl<'block, 'analysis, 'compilation, 'tcx> BlockVisitor<'block, 'analysis, 'com .already_reported_errors_for_call_to .insert(call_visitor.callee_fun_val.clone()) { - let _kn = known_names::KnownNamesCache::get_known_name_for(tcx, callee_def_id); call_visitor.block_visitor.report_missing_summary(); if known_name != KnownNames::StdCloneClone && !call_visitor.block_visitor.bv.analysis_is_incomplete diff --git a/checker/src/callbacks.rs b/checker/src/callbacks.rs index fe95c5b3..8b9d05a6 100644 --- a/checker/src/callbacks.rs +++ b/checker/src/callbacks.rs @@ -151,6 +151,7 @@ impl MiraiCallbacks { self.file_name, summary_store_path ); let call_graph_config = self.options.call_graph_config.to_owned(); + let lang_items = tcx.lang_items(); let mut crate_visitor = CrateVisitor { buffered_diagnostics: Vec::new(), constant_time_tag_cache: None, @@ -158,7 +159,7 @@ impl MiraiCallbacks { constant_value_cache: ConstantValueCache::default(), diagnostics_for: HashMap::new(), file_name: self.file_name.as_str(), - known_names_cache: KnownNamesCache::create_cache_from_language_items(), + known_names_cache: KnownNamesCache::create_cache_from_language_items(lang_items), options: &std::mem::take(&mut self.options), session: &compiler.sess, generic_args_cache: HashMap::new(), diff --git a/checker/src/crate_visitor.rs b/checker/src/crate_visitor.rs index 25530ffa..1c777e3d 100644 --- a/checker/src/crate_visitor.rs +++ b/checker/src/crate_visitor.rs @@ -49,7 +49,7 @@ pub struct CrateVisitor<'compilation, 'tcx> { pub diagnostics_for: HashMap>>, pub file_name: &'compilation str, pub generic_args_cache: HashMap>, - pub known_names_cache: KnownNamesCache, + pub known_names_cache: KnownNamesCache<'tcx>, pub options: &'compilation Options, pub session: &'compilation Session, pub summary_cache: SummaryCache<'tcx>, diff --git a/checker/src/known_names.rs b/checker/src/known_names.rs index 53891e63..500ce5f3 100644 --- a/checker/src/known_names.rs +++ b/checker/src/known_names.rs @@ -5,10 +5,13 @@ use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::LanguageItems; use rustc_middle::ty::TyCtxt; -use serde::{Deserialize, Serialize}; + use std::collections::HashMap; +use serde::{Deserialize, Serialize}; + /// Well known definitions (language provided items) that are treated in special ways. #[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialOrd, PartialEq, Hash, Ord)] pub enum KnownNames { @@ -167,18 +170,22 @@ pub enum KnownNames { } /// An analysis lifetime cache that contains a map from def ids to known names. -pub struct KnownNamesCache { +pub struct KnownNamesCache<'tcx> { name_cache: HashMap, + lang_items: &'tcx LanguageItems, } -type Iter<'a> = std::slice::Iter<'a, rustc_hir::definitions::DisambiguatedDefPathData>; - -impl KnownNamesCache { +impl<'tcx> KnownNamesCache<'tcx> { /// Create an empty known names cache. /// This cache is re-used by every successive MIR visitor instance. - pub fn create_cache_from_language_items() -> KnownNamesCache { + pub fn create_cache_from_language_items( + lang_items: &'tcx LanguageItems, + ) -> KnownNamesCache<'tcx> { let name_cache = HashMap::new(); - KnownNamesCache { name_cache } + KnownNamesCache { + name_cache, + lang_items, + } } /// Get the well known name for the given def id and cache the association. @@ -186,443 +193,447 @@ impl KnownNamesCache { /// subsequent calls will be cheap. If the def_id does not have an actual well /// known name, this returns KnownNames::None. pub fn get(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> KnownNames { - *self - .name_cache - .entry(def_id) - .or_insert_with(|| Self::get_known_name_for(tcx, def_id)) + match self.name_cache.get(&def_id) { + Some(known_name) => *known_name, + None => { + let known_name = self.get_known_name_for(tcx, def_id); + self.name_cache.insert(def_id, known_name); + known_name + } + } } /// Uses information obtained from tcx to figure out which well known name (if any) /// this def id corresponds to. - pub fn get_known_name_for(tcx: TyCtxt<'_>, def_id: DefId) -> KnownNames { - use DefPathData::*; + pub fn get_known_name_for(&self, tcx: TyCtxt<'_>, def_id: DefId) -> KnownNames { + // Use `rustc` lang items (if available) for the most precise `DefId` matching. + if let Some(known_name) = known_name_for_lang_item(def_id, self.lang_items) { + return known_name; + } + // Fallback to def path comparisons for other items. + // Ref: + // Ref: let def_path = &tcx.def_path(def_id); - let def_path_data_iter = def_path.data.iter(); + let path_segments = &def_path.data; + let crate_name = tcx.crate_name(def_id.krate); + match crate_name.as_str() { + "mirai_annotations" => known_name_for_mirai_annotations(path_segments), + "alloc" | "core" | "std" => known_name_for_std_lib(path_segments), + _ => None, + } + .unwrap_or(KnownNames::None) + } +} - // helper to get next elem from def path and return its name, if it has one - let get_path_data_elem_name = - |def_path_data_elem: Option<&rustc_hir::definitions::DisambiguatedDefPathData>| { - def_path_data_elem.and_then(|ref elem| { - let DisambiguatedDefPathData { data, .. } = elem; - match &data { - TypeNs(name) | ValueNs(name) => Some(*name), - _ => None, - } - }) - }; +// Convenience macro for match-like syntax that returns `Option` but: +// - transforms each match arm from `X => Y` to `X => Some(Y)` +// - auto adds a `_ => None` (i.e. wild card) arm +macro_rules! match_names { + ($scrutinee: expr, $($from: pat => $to: expr $(,)? )*) => { + match $scrutinee { + $($from => Some($to),)* + _ => None, + } + }; +} - let is_foreign_module = - |def_path_data_elem: Option<&rustc_hir::definitions::DisambiguatedDefPathData>| { - if let Some(elem) = def_path_data_elem { - let DisambiguatedDefPathData { data, .. } = elem; - matches!(&data, ForeignMod) - } else { - false - } - }; +fn known_name_for_lang_item(def_id: DefId, lang_items: &LanguageItems) -> Option { + let lang_item = lang_items.from_def_id(def_id)?; + match_names!( + lang_item, + rustc_hir::LangItem::CloneFn => KnownNames::StdCloneClone, + rustc_hir::LangItem::PhantomData => KnownNames::StdMarkerPhantomData, + // TODO: (@davidsemakula) Can we safely add more panic lang items? + rustc_hir::LangItem::BeginPanic | rustc_hir::LangItem::Panic => KnownNames::StdPanickingBeginPanic, + rustc_hir::LangItem::ConstPanicFmt | rustc_hir::LangItem::PanicFmt => KnownNames::StdPanickingBeginPanicFmt, + ) +} - let path_data_elem_as_disambiguator = |def_path_data_elem: Option< - &rustc_hir::definitions::DisambiguatedDefPathData, - >| { - def_path_data_elem.map(|DisambiguatedDefPathData { disambiguator, .. }| *disambiguator) - }; +fn known_name_for_mirai_annotations( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment] => match current_segment.data { + // Handles functions. + DefPathData::ValueNs(name) => match_names!( + name.as_str(), + "mirai_abstract_value" => KnownNames::MiraiAbstractValue, + "mirai_add_tag" => KnownNames::MiraiAddTag, + "mirai_assume" => KnownNames::MiraiAssume, + "mirai_assume_preconditions" => KnownNames::MiraiAssumePreconditions, + "mirai_does_not_have_tag" => KnownNames::MiraiDoesNotHaveTag, + "mirai_get_model_field" => KnownNames::MiraiGetModelField, + "mirai_has_tag" => KnownNames::MiraiHasTag, + "mirai_postcondition" => KnownNames::MiraiPostcondition, + "mirai_precondition_start" => KnownNames::MiraiPreconditionStart, + "mirai_precondition" => KnownNames::MiraiPrecondition, + "mirai_result" => KnownNames::MiraiResult, + "mirai_set_model_field" => KnownNames::MiraiSetModelField, + "mirai_verify" => KnownNames::MiraiVerify, + ), + // Handles macros. + DefPathData::MacroNs(name) => match_names!( + name.as_str(), + "abstract_value" => KnownNames::MiraiAbstractValue, + "add_tag" => KnownNames::MiraiAddTag, + "assume" => KnownNames::MiraiAssume, + "assume_preconditions" => KnownNames::MiraiAssumePreconditions, + "does_not_have_tag" => KnownNames::MiraiDoesNotHaveTag, + "get_model_field" => KnownNames::MiraiGetModelField, + "has_tag" => KnownNames::MiraiHasTag, + "postcondition" => KnownNames::MiraiPostcondition, + "precondition_start" => KnownNames::MiraiPreconditionStart, + "precondition" => KnownNames::MiraiPrecondition, + "result" => KnownNames::MiraiResult, + "set_model_field" => KnownNames::MiraiSetModelField, + "verify" => KnownNames::MiraiVerify, + ), + _ => None, + }, + _ => None, + } +} - let get_known_name_for_alloc_namespace = |mut def_path_data_iter: Iter<'_>| { - if is_foreign_module(def_path_data_iter.next()) { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "__rust_alloc" => KnownNames::RustAlloc, - "__rust_alloc_zeroed" => KnownNames::RustAllocZeroed, - "__rust_dealloc" => KnownNames::RustDealloc, - "__rust_realloc" => KnownNames::RustRealloc, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - } else { - KnownNames::None - } - }; +// Convenience macro for matching a single terminal path segment to a given item name, +// and returning the given `KnownName` (in case of a successful match). +macro_rules! known_name_for_terminal_from_ns { + ($path_segments: expr, $ns_variant: path, $item_name: literal, $known_name: expr) => { + match $path_segments { + [only_segment] => match &only_segment.data { + $ns_variant(name) => (name.as_str() == $item_name).then_some($known_name), + _ => None, + }, + _ => None, + } + }; +} - let get_known_name_for_clone_trait = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "clone" => KnownNames::StdCloneClone, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +fn known_name_for_std_lib(path_segments: &[DisambiguatedDefPathData]) -> Option { + match path_segments { + [current_segment, tail_segments @ ..] => match name_from_type_ns(current_segment)? { + "alloc" => get_known_name_for_alloc_namespace(tail_segments), + "clone" => get_known_name_for_clone_namespace(tail_segments), + "future" => known_name_for_terminal_from_ns!( + tail_segments, + DefPathData::ValueNs, + // TODO: (@davidsemakula) Was `from_generator` removed? + "from_generator", + KnownNames::StdFutureFromGenerator + ), + "intrinsics" => known_name_for_intrinsics_namespace(tail_segments), + "marker" => known_name_for_terminal_from_ns!( + tail_segments, + DefPathData::TypeNs, + // TODO: (@davidsemakula) Remove in favor of lang item? + "PhantomData", + KnownNames::StdMarkerPhantomData + ), + "mem" => known_name_for_terminal_from_ns!( + tail_segments, + DefPathData::ValueNs, + "replace", + KnownNames::StdMemReplace + ), + "ops" => known_name_for_ops_namespace(tail_segments), + "panicking" => known_name_for_panicking_namespace(tail_segments), + "ptr" => known_name_for_ptr_namespace(tail_segments), + "raw_vec" => known_name_for_raw_vec_namespace(tail_segments), + "rt" => known_name_for_panicking_namespace(tail_segments), + "slice" => known_name_for_slice_namespace(tail_segments), + "sync" => known_name_for_sync_namespace(tail_segments), + _ => None, + }, + _ => None, + } +} - let get_known_name_for_clone_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "Clone" => get_known_name_for_clone_trait(def_path_data_iter), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +fn get_known_name_for_alloc_namespace( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment, last_segment] if is_foreign_module(current_segment) => { + match_names!( + name_from_value_ns(last_segment)?, + "__rust_alloc" => KnownNames::RustAlloc, + "__rust_alloc_zeroed" => KnownNames::RustAllocZeroed, + "__rust_dealloc" => KnownNames::RustDealloc, + "__rust_realloc" => KnownNames::RustRealloc, + ) + } + _ => None, + } +} - let get_known_name_for_future_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "from_generator" => KnownNames::StdFutureFromGenerator, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +// TODO: (@davidsemakula) Remove in favor of lang item? +fn get_known_name_for_clone_namespace( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment, last_segment] => { + let current_name = name_from_type_ns(current_segment)?; + let last_name = name_from_value_ns(last_segment)?; + let is_clone_fn = current_name == "Clone" && last_name == "clone"; + is_clone_fn.then_some(KnownNames::StdCloneClone) + } + _ => None, + } +} - let get_known_name_for_instrinsics_foreign_namespace = - |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "float_to_int_unchecked" => KnownNames::StdIntrinsicsFloatToIntUnchecked, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +fn known_name_for_intrinsics_namespace( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment] => match_names! ( + name_from_value_ns(current_segment)?, + "arith_offset" => KnownNames::StdIntrinsicsArithOffset, + "bitreverse" => KnownNames::StdIntrinsicsBitreverse, + "bswap" => KnownNames::StdIntrinsicsBswap, + "ceilf16" => KnownNames::StdIntrinsicsCeilf16, + "ceilf32" => KnownNames::StdIntrinsicsCeilf32, + "ceilf64" => KnownNames::StdIntrinsicsCeilf64, + "ceilf128" => KnownNames::StdIntrinsicsCeilf128, + "compare_bytes" => KnownNames::StdSliceCmpMemcmp, + "const_eval_select" => KnownNames::StdIntrinsicsConstEvalSelect, + "copy" => KnownNames::StdIntrinsicsCopy, + "copy_nonoverlapping" => KnownNames::StdIntrinsicsCopyNonOverlapping, + "copysignf16" => KnownNames::StdIntrinsicsCopysignf16, + "copysignf32" => KnownNames::StdIntrinsicsCopysignf32, + "copysignf64" => KnownNames::StdIntrinsicsCopysignf64, + "copysignf128" => KnownNames::StdIntrinsicsCopysignf128, + "cosf16" => KnownNames::StdIntrinsicsCosf16, + "cosf32" => KnownNames::StdIntrinsicsCosf32, + "cosf64" => KnownNames::StdIntrinsicsCosf64, + "cosf128" => KnownNames::StdIntrinsicsCosf128, + "ctlz" => KnownNames::StdIntrinsicsCtlz, + "ctlz_nonzero" => KnownNames::StdIntrinsicsCtlzNonzero, + "ctpop" => KnownNames::StdIntrinsicsCtpop, + "cttz" => KnownNames::StdIntrinsicsCttz, + "cttz_nonzero" => KnownNames::StdIntrinsicsCttzNonzero, + "discriminant_value" => KnownNames::StdIntrinsicsDiscriminantValue, + "exp2f16" => KnownNames::StdIntrinsicsExp2f16, + "exp2f32" => KnownNames::StdIntrinsicsExp2f32, + "exp2f64" => KnownNames::StdIntrinsicsExp2f64, + "exp2f128" => KnownNames::StdIntrinsicsExp2f128, + "expf16" => KnownNames::StdIntrinsicsExpf16, + "expf32" => KnownNames::StdIntrinsicsExpf32, + "expf64" => KnownNames::StdIntrinsicsExpf64, + "expf128" => KnownNames::StdIntrinsicsExpf128, + "fabsf16" => KnownNames::StdIntrinsicsFabsf16, + "fabsf32" => KnownNames::StdIntrinsicsFabsf32, + "fabsf64" => KnownNames::StdIntrinsicsFabsf64, + "fabsf128" => KnownNames::StdIntrinsicsFabsf128, + "fadd_algebraic" => KnownNames::StdIntrinsicsFaddAlgebraic, + "fadd_fast" => KnownNames::StdIntrinsicsFaddFast, + "fdiv_algebraic" => KnownNames::StdIntrinsicsFdivAlgebraic, + "fdiv_fast" => KnownNames::StdIntrinsicsFdivFast, + "floorf16" => KnownNames::StdIntrinsicsFloorf16, + "floorf32" => KnownNames::StdIntrinsicsFloorf32, + "floorf64" => KnownNames::StdIntrinsicsFloorf64, + "floorf128" => KnownNames::StdIntrinsicsFloorf128, + "fmul_algebraic" => KnownNames::StdIntrinsicsFmulAlgebraic, + "fmul_fast" => KnownNames::StdIntrinsicsFmulFast, + "frem_algebraic" => KnownNames::StdIntrinsicsFremAlgebraic, + "frem_fast" => KnownNames::StdIntrinsicsFremFast, + "fsub_algebraic" => KnownNames::StdIntrinsicsFsubAlgebraic, + "fsub_fast" => KnownNames::StdIntrinsicsFsubFast, + "is_val_statically_known" => KnownNames::StdIntrinsicsIsValStaticallyKnown, + "log10f16" => KnownNames::StdIntrinsicsLog10f16, + "log10f32" => KnownNames::StdIntrinsicsLog10f32, + "log10f64" => KnownNames::StdIntrinsicsLog10f64, + "log10f128" => KnownNames::StdIntrinsicsLog10f128, + "log2f16" => KnownNames::StdIntrinsicsLog2f16, + "log2f32" => KnownNames::StdIntrinsicsLog2f32, + "log2f64" => KnownNames::StdIntrinsicsLog2f64, + "log2f128" => KnownNames::StdIntrinsicsLog2f128, + "logf16" => KnownNames::StdIntrinsicsLogf16, + "logf32" => KnownNames::StdIntrinsicsLogf32, + "logf64" => KnownNames::StdIntrinsicsLogf64, + "logf128" => KnownNames::StdIntrinsicsLogf128, + "maxnumf16" => KnownNames::StdIntrinsicsMaxnumf16, + "maxnumf32" => KnownNames::StdIntrinsicsMaxnumf32, + "maxnumf64" => KnownNames::StdIntrinsicsMaxnumf64, + "maxnumf128" => KnownNames::StdIntrinsicsMaxnumf128, + "min_align_of_val" => KnownNames::StdIntrinsicsMinAlignOfVal, + "minnumf16" => KnownNames::StdIntrinsicsMinnumf16, + "minnumf32" => KnownNames::StdIntrinsicsMinnumf32, + "minnumf64" => KnownNames::StdIntrinsicsMinnumf64, + "minnumf128" => KnownNames::StdIntrinsicsMinnumf128, + "mul_with_overflow" => KnownNames::StdIntrinsicsMulWithOverflow, + "nearbyintf16" => KnownNames::StdIntrinsicsNearbyintf16, + "nearbyintf32" => KnownNames::StdIntrinsicsNearbyintf32, + "nearbyintf64" => KnownNames::StdIntrinsicsNearbyintf64, + "nearbyintf128" => KnownNames::StdIntrinsicsNearbyintf128, + "needs_drop" => KnownNames::StdIntrinsicsNeedsDrop, + "offset" => KnownNames::StdIntrinsicsOffset, + "powf16" => KnownNames::StdIntrinsicsPowf16, + "powf32" => KnownNames::StdIntrinsicsPowf32, + "powf64" => KnownNames::StdIntrinsicsPowf64, + "powf128" => KnownNames::StdIntrinsicsPowf128, + "powif16" => KnownNames::StdIntrinsicsPowif16, + "powif32" => KnownNames::StdIntrinsicsPowif32, + "powif64" => KnownNames::StdIntrinsicsPowif64, + "powif128" => KnownNames::StdIntrinsicsPowif128, + "pref_align_of_val" => KnownNames::StdIntrinsicsPrefAlignOfVal, + "raw_eq" => KnownNames::StdIntrinsicsRawEq, + "rintf16" => KnownNames::StdIntrinsicsRintf16, + "rintf32" => KnownNames::StdIntrinsicsRintf32, + "rintf64" => KnownNames::StdIntrinsicsRintf64, + "rintf128" => KnownNames::StdIntrinsicsRintf128, + "roundf16" => KnownNames::StdIntrinsicsRoundf16, + "roundf32" => KnownNames::StdIntrinsicsRoundf32, + "roundf64" => KnownNames::StdIntrinsicsRoundf64, + "roundf128" => KnownNames::StdIntrinsicsRoundf128, + "roundevenf16" => KnownNames::StdIntrinsicsRevenf16, + "roundevenf32" => KnownNames::StdIntrinsicsRevenf32, + "roundevenf64" => KnownNames::StdIntrinsicsRevenf64, + "roundevenf128" => KnownNames::StdIntrinsicsRevenf128, + "sinf16" => KnownNames::StdIntrinsicsSinf16, + "sinf32" => KnownNames::StdIntrinsicsSinf32, + "sinf64" => KnownNames::StdIntrinsicsSinf64, + "sinf128" => KnownNames::StdIntrinsicsSinf64, + "size_of" => KnownNames::StdIntrinsicsSizeOf, + "size_of_val" => KnownNames::StdIntrinsicsSizeOfVal, + "sqrtf16" => KnownNames::StdIntrinsicsSqrtf16, + "sqrtf32" => KnownNames::StdIntrinsicsSqrtf32, + "sqrtf64" => KnownNames::StdIntrinsicsSqrtf64, + "sqrtf128" => KnownNames::StdIntrinsicsSqrtf128, + "three_way_compare" => KnownNames::StdIntrinsicsThreeWayCompare, + "transmute" => KnownNames::StdIntrinsicsTransmute, + "transmute_unchecked" => KnownNames::StdIntrinsicsTransmute, + "truncf16" => KnownNames::StdIntrinsicsTruncf16, + "truncf32" => KnownNames::StdIntrinsicsTruncf32, + "truncf64" => KnownNames::StdIntrinsicsTruncf64, + "truncf128" => KnownNames::StdIntrinsicsTruncf128, + "variant_count" => KnownNames::StdIntrinsicsVariantCount, + "write_bytes" => KnownNames::StdIntrinsicsWriteBytes, + ), + [current_segment, last_segment] if is_foreign_module(current_segment) => { + let name = name_from_value_ns(last_segment)?; + (name == "float_to_int_unchecked") + .then_some(KnownNames::StdIntrinsicsFloatToIntUnchecked) + } + _ => None, + } +} - let get_known_name_for_intrinsics_namespace = |mut def_path_data_iter: Iter<'_>| { - let current_elem = def_path_data_iter.next(); - match path_data_elem_as_disambiguator(current_elem) { - Some(0) => { - if is_foreign_module(current_elem) { - get_known_name_for_instrinsics_foreign_namespace(def_path_data_iter) - } else { - get_path_data_elem_name(current_elem) - .map(|n| match n.as_str() { - "arith_offset" => KnownNames::StdIntrinsicsArithOffset, - "bitreverse" => KnownNames::StdIntrinsicsBitreverse, - "bswap" => KnownNames::StdIntrinsicsBswap, - "ceilf16" => KnownNames::StdIntrinsicsCeilf16, - "ceilf32" => KnownNames::StdIntrinsicsCeilf32, - "ceilf64" => KnownNames::StdIntrinsicsCeilf64, - "ceilf128" => KnownNames::StdIntrinsicsCeilf128, - "compare_bytes" => KnownNames::StdSliceCmpMemcmp, - "const_eval_select" => KnownNames::StdIntrinsicsConstEvalSelect, - "copy" => KnownNames::StdIntrinsicsCopy, - "copy_nonoverlapping" => { - if def_path_data_iter.next().is_some() { - KnownNames::None - } else { - KnownNames::StdIntrinsicsCopyNonOverlapping - } - } - "copysignf16" => KnownNames::StdIntrinsicsCopysignf16, - "copysignf32" => KnownNames::StdIntrinsicsCopysignf32, - "copysignf64" => KnownNames::StdIntrinsicsCopysignf64, - "copysignf128" => KnownNames::StdIntrinsicsCopysignf128, - "cosf16" => KnownNames::StdIntrinsicsCosf16, - "cosf32" => KnownNames::StdIntrinsicsCosf32, - "cosf64" => KnownNames::StdIntrinsicsCosf64, - "cosf128" => KnownNames::StdIntrinsicsCosf128, - "ctlz" => KnownNames::StdIntrinsicsCtlz, - "ctlz_nonzero" => KnownNames::StdIntrinsicsCtlzNonzero, - "ctpop" => KnownNames::StdIntrinsicsCtpop, - "cttz" => KnownNames::StdIntrinsicsCttz, - "cttz_nonzero" => KnownNames::StdIntrinsicsCttzNonzero, - "discriminant_value" => KnownNames::StdIntrinsicsDiscriminantValue, - "exp2f16" => KnownNames::StdIntrinsicsExp2f16, - "exp2f32" => KnownNames::StdIntrinsicsExp2f32, - "exp2f64" => KnownNames::StdIntrinsicsExp2f64, - "exp2f128" => KnownNames::StdIntrinsicsExp2f128, - "expf16" => KnownNames::StdIntrinsicsExpf16, - "expf32" => KnownNames::StdIntrinsicsExpf32, - "expf64" => KnownNames::StdIntrinsicsExpf64, - "expf128" => KnownNames::StdIntrinsicsExpf128, - "fabsf16" => KnownNames::StdIntrinsicsFabsf16, - "fabsf32" => KnownNames::StdIntrinsicsFabsf32, - "fabsf64" => KnownNames::StdIntrinsicsFabsf64, - "fabsf128" => KnownNames::StdIntrinsicsFabsf128, - "fadd_algebraic" => KnownNames::StdIntrinsicsFaddAlgebraic, - "fadd_fast" => KnownNames::StdIntrinsicsFaddFast, - "fdiv_algebraic" => KnownNames::StdIntrinsicsFdivAlgebraic, - "fdiv_fast" => KnownNames::StdIntrinsicsFdivFast, - "floorf16" => KnownNames::StdIntrinsicsFloorf16, - "floorf32" => KnownNames::StdIntrinsicsFloorf32, - "floorf64" => KnownNames::StdIntrinsicsFloorf64, - "floorf128" => KnownNames::StdIntrinsicsFloorf128, - "fmul_algebraic" => KnownNames::StdIntrinsicsFmulAlgebraic, - "fmul_fast" => KnownNames::StdIntrinsicsFmulFast, - "frem_algebraic" => KnownNames::StdIntrinsicsFremAlgebraic, - "frem_fast" => KnownNames::StdIntrinsicsFremFast, - "fsub_algebraic" => KnownNames::StdIntrinsicsFsubAlgebraic, - "fsub_fast" => KnownNames::StdIntrinsicsFsubFast, - "is_val_statically_known" => { - KnownNames::StdIntrinsicsIsValStaticallyKnown - } - "log10f16" => KnownNames::StdIntrinsicsLog10f16, - "log10f32" => KnownNames::StdIntrinsicsLog10f32, - "log10f64" => KnownNames::StdIntrinsicsLog10f64, - "log10f128" => KnownNames::StdIntrinsicsLog10f128, - "log2f16" => KnownNames::StdIntrinsicsLog2f16, - "log2f32" => KnownNames::StdIntrinsicsLog2f32, - "log2f64" => KnownNames::StdIntrinsicsLog2f64, - "log2f128" => KnownNames::StdIntrinsicsLog2f128, - "logf16" => KnownNames::StdIntrinsicsLogf16, - "logf32" => KnownNames::StdIntrinsicsLogf32, - "logf64" => KnownNames::StdIntrinsicsLogf64, - "logf128" => KnownNames::StdIntrinsicsLogf128, - "maxnumf16" => KnownNames::StdIntrinsicsMaxnumf16, - "maxnumf32" => KnownNames::StdIntrinsicsMaxnumf32, - "maxnumf64" => KnownNames::StdIntrinsicsMaxnumf64, - "maxnumf128" => KnownNames::StdIntrinsicsMaxnumf128, - "min_align_of_val" => KnownNames::StdIntrinsicsMinAlignOfVal, - "minnumf16" => KnownNames::StdIntrinsicsMinnumf16, - "minnumf32" => KnownNames::StdIntrinsicsMinnumf32, - "minnumf64" => KnownNames::StdIntrinsicsMinnumf64, - "minnumf128" => KnownNames::StdIntrinsicsMinnumf128, - "mul_with_overflow" => KnownNames::StdIntrinsicsMulWithOverflow, - "nearbyintf16" => KnownNames::StdIntrinsicsNearbyintf16, - "nearbyintf32" => KnownNames::StdIntrinsicsNearbyintf32, - "nearbyintf64" => KnownNames::StdIntrinsicsNearbyintf64, - "nearbyintf128" => KnownNames::StdIntrinsicsNearbyintf128, - "needs_drop" => KnownNames::StdIntrinsicsNeedsDrop, - "offset" => KnownNames::StdIntrinsicsOffset, - "powf16" => KnownNames::StdIntrinsicsPowf16, - "powf32" => KnownNames::StdIntrinsicsPowf32, - "powf64" => KnownNames::StdIntrinsicsPowf64, - "powf128" => KnownNames::StdIntrinsicsPowf128, - "powif16" => KnownNames::StdIntrinsicsPowif16, - "powif32" => KnownNames::StdIntrinsicsPowif32, - "powif64" => KnownNames::StdIntrinsicsPowif64, - "powif128" => KnownNames::StdIntrinsicsPowif128, - "pref_align_of_val" => KnownNames::StdIntrinsicsPrefAlignOfVal, - "raw_eq" => KnownNames::StdIntrinsicsRawEq, - "rintf16" => KnownNames::StdIntrinsicsRintf16, - "rintf32" => KnownNames::StdIntrinsicsRintf32, - "rintf64" => KnownNames::StdIntrinsicsRintf64, - "rintf128" => KnownNames::StdIntrinsicsRintf128, - "roundf16" => KnownNames::StdIntrinsicsRoundf16, - "roundf32" => KnownNames::StdIntrinsicsRoundf32, - "roundf64" => KnownNames::StdIntrinsicsRoundf64, - "roundf128" => KnownNames::StdIntrinsicsRoundf128, - "roundevenf16" => KnownNames::StdIntrinsicsRevenf16, - "roundevenf32" => KnownNames::StdIntrinsicsRevenf32, - "roundevenf64" => KnownNames::StdIntrinsicsRevenf64, - "roundevenf128" => KnownNames::StdIntrinsicsRevenf128, - "sinf16" => KnownNames::StdIntrinsicsSinf16, - "sinf32" => KnownNames::StdIntrinsicsSinf32, - "sinf64" => KnownNames::StdIntrinsicsSinf64, - "sinf128" => KnownNames::StdIntrinsicsSinf64, - "size_of" => KnownNames::StdIntrinsicsSizeOf, - "size_of_val" => KnownNames::StdIntrinsicsSizeOfVal, - "sqrtf16" => KnownNames::StdIntrinsicsSqrtf16, - "sqrtf32" => KnownNames::StdIntrinsicsSqrtf32, - "sqrtf64" => KnownNames::StdIntrinsicsSqrtf64, - "sqrtf128" => KnownNames::StdIntrinsicsSqrtf128, - "three_way_compare" => KnownNames::StdIntrinsicsThreeWayCompare, - "transmute" => KnownNames::StdIntrinsicsTransmute, - "transmute_unchecked" => KnownNames::StdIntrinsicsTransmute, - "truncf16" => KnownNames::StdIntrinsicsTruncf16, - "truncf32" => KnownNames::StdIntrinsicsTruncf32, - "truncf64" => KnownNames::StdIntrinsicsTruncf64, - "truncf128" => KnownNames::StdIntrinsicsTruncf128, - "variant_count" => KnownNames::StdIntrinsicsVariantCount, - "write_bytes" => { - if def_path_data_iter.next().is_some() { - KnownNames::None - } else { - KnownNames::StdIntrinsicsWriteBytes - } - } - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - } - } - _ => { - if is_foreign_module(current_elem) { - get_known_name_for_instrinsics_foreign_namespace(def_path_data_iter) - } else { - KnownNames::None - } - } +fn known_name_for_ops_namespace(path_segments: &[DisambiguatedDefPathData]) -> Option { + // TODO: (@davidsemakula) Handle as assoc lang items? + // TODO: (@davidsemakula) was `call_once_force` removed, + // or did it actually resolve to a different (perhaps nested) path before? + // See https://github.com/endorlabs/MIRAI/issues/26#issuecomment-2566638406 for details. + // See also [`get_known_name_for_sync_namespace`]? + match path_segments { + [current_segment, middle_segment, last_segment] => match_names! ( + ( + name_from_type_ns(current_segment)?, + name_from_type_ns(middle_segment)?, + name_from_value_ns(last_segment)?, + ), + ("function", "Fn", "call") => KnownNames::StdOpsFunctionFnCall, + ("function", "FnMut", "call_mut") => KnownNames::StdOpsFunctionFnMutCallMut, + ("function", "FnOnce", "call_once" | "call_once_force") => { + KnownNames::StdOpsFunctionFnOnceCallOnce } - }; - - let get_known_name_for_marker_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "PhantomData" => KnownNames::StdMarkerPhantomData, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; - - let get_known_name_for_mem_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "replace" => KnownNames::StdMemReplace, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; - - let get_known_name_for_ops_function_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "Fn" | "FnMut" | "FnOnce" => get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "call" => KnownNames::StdOpsFunctionFnCall, - "call_mut" => KnownNames::StdOpsFunctionFnMutCallMut, - "call_once" | "call_once_force" => { - KnownNames::StdOpsFunctionFnOnceCallOnce - } - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; - - let get_known_name_for_ops_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "function" => get_known_name_for_ops_function_namespace(def_path_data_iter), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; - - let get_known_name_for_panicking_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "assert_failed" => KnownNames::StdPanickingAssertFailed, - "begin_panic" | "panic" => KnownNames::StdPanickingBeginPanic, - "begin_panic_fmt" | "panic_fmt" => KnownNames::StdPanickingBeginPanicFmt, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; - - let get_known_name_for_ptr_mut_ptr_namespace = - |mut def_path_data_iter: Iter<'_>| match path_data_elem_as_disambiguator( - def_path_data_iter.next(), - ) { - Some(0) => get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "write_bytes" => { - if def_path_data_iter.next().is_some() { - KnownNames::None - } else { - KnownNames::StdIntrinsicsWriteBytes - } - } - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None), - _ => KnownNames::None, - }; - - let get_known_name_for_ptr_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "swap_nonoverlapping" => KnownNames::StdPtrSwapNonOverlapping, - "mut_ptr" => get_known_name_for_ptr_mut_ptr_namespace(def_path_data_iter), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; + ), + _ => None, + } +} - let get_known_name_for_slice_cmp_namespace = - |mut def_path_data_iter: Iter<'_>| match path_data_elem_as_disambiguator( - def_path_data_iter.next(), - ) { - Some(0) => get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "memcmp" => KnownNames::StdSliceCmpMemcmp, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None), - _ => KnownNames::None, - }; +// TODO: (@davidsemakula) Remove in favor of lang items (where possible)? +fn known_name_for_panicking_namespace( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment] => match_names!( + name_from_value_ns(current_segment)?, + "assert_failed" => KnownNames::StdPanickingAssertFailed, + "begin_panic" | "panic" => KnownNames::StdPanickingBeginPanic, + "begin_panic_fmt" | "panic_fmt" => KnownNames::StdPanickingBeginPanicFmt + ), + _ => None, + } +} - let get_known_name_for_sync_once_namespace = - |mut def_path_data_iter: Iter<'_>| match path_data_elem_as_disambiguator( - def_path_data_iter.next(), - ) { - Some(2) => get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "call_once" | "call_once_force" => KnownNames::StdOpsFunctionFnOnceCallOnce, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None), - _ => KnownNames::None, - }; +fn known_name_for_ptr_namespace(path_segments: &[DisambiguatedDefPathData]) -> Option { + match path_segments { + [current_segment] => { + let name = name_from_value_ns(current_segment)?; + (name == "swap_nonoverlapping").then_some(KnownNames::StdPtrSwapNonOverlapping) + } + [current_segment, middle_segment, last_segment] => { + let current_name = name_from_type_ns(current_segment)?; + let last_name = name_from_value_ns(last_segment)?; + let is_write_bytes_method = current_name == "mut_ptr" + && matches!(middle_segment.data, DefPathData::Impl) + && last_name == "write_bytes"; + is_write_bytes_method.then_some(KnownNames::StdIntrinsicsWriteBytes) + } + _ => None, + } +} - let get_known_name_for_raw_vec_namespace = - |mut def_path_data_iter: Iter<'_>| match path_data_elem_as_disambiguator( - def_path_data_iter.next(), - ) { - Some(1) => get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "MIN_NON_ZERO_CAP" => KnownNames::AllocRawVecMinNonZeroCap, - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None), - _ => KnownNames::None, - }; +fn known_name_for_raw_vec_namespace( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment, last_segment] => { + let name = name_from_type_ns(last_segment)?; + let is_min_non_zero_cap_assoc_const = + matches!(current_segment.data, DefPathData::Impl) && name == "MIN_NON_ZERO_CAP"; + is_min_non_zero_cap_assoc_const.then_some(KnownNames::AllocRawVecMinNonZeroCap) + } + _ => None, + } +} - let get_known_name_for_slice_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "cmp" => get_known_name_for_slice_cmp_namespace(def_path_data_iter), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +fn known_name_for_slice_namespace( + path_segments: &[DisambiguatedDefPathData], +) -> Option { + match path_segments { + [current_segment, middle_segment, last_segment] => { + let current_name = name_from_type_ns(current_segment)?; + let last_name = name_from_value_ns(last_segment)?; + let is_extern_c_memcmp = + current_name == "cmp" && is_foreign_module(middle_segment) && last_name == "memcmp"; + is_extern_c_memcmp.then_some(KnownNames::StdSliceCmpMemcmp) + } + _ => None, + } +} - //get_known_name_for_sync_namespace - let get_known_name_for_sync_namespace = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "once" => get_known_name_for_sync_once_namespace(def_path_data_iter), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +fn known_name_for_sync_namespace(path_segments: &[DisambiguatedDefPathData]) -> Option { + match path_segments { + [current_segment, middle_segment, last_segment] => { + let current_name = name_from_type_ns(current_segment)?; + let last_name = name_from_value_ns(last_segment)?; + let is_call_once_method = current_name == "once" + && matches!(middle_segment.data, DefPathData::Impl) + && matches!(last_name, "call_once" | "call_once_force"); + is_call_once_method.then_some(KnownNames::StdOpsFunctionFnOnceCallOnce) + } + _ => None, + } +} - let get_known_name_for_known_crate = |mut def_path_data_iter: Iter<'_>| { - get_path_data_elem_name(def_path_data_iter.next()) - .map(|n| match n.as_str() { - "alloc" => get_known_name_for_alloc_namespace(def_path_data_iter), - "clone" => get_known_name_for_clone_namespace(def_path_data_iter), - "future" => get_known_name_for_future_namespace(def_path_data_iter), - "intrinsics" => get_known_name_for_intrinsics_namespace(def_path_data_iter), - "marker" => get_known_name_for_marker_namespace(def_path_data_iter), - "mem" => get_known_name_for_mem_namespace(def_path_data_iter), - "ops" => get_known_name_for_ops_namespace(def_path_data_iter), - "panicking" => get_known_name_for_panicking_namespace(def_path_data_iter), - "ptr" => get_known_name_for_ptr_namespace(def_path_data_iter), - "mirai_abstract_value" => KnownNames::MiraiAbstractValue, - "mirai_add_tag" => KnownNames::MiraiAddTag, - "mirai_assume" => KnownNames::MiraiAssume, - "mirai_assume_preconditions" => KnownNames::MiraiAssumePreconditions, - "mirai_does_not_have_tag" => KnownNames::MiraiDoesNotHaveTag, - "mirai_get_model_field" => KnownNames::MiraiGetModelField, - "mirai_has_tag" => KnownNames::MiraiHasTag, - "mirai_postcondition" => KnownNames::MiraiPostcondition, - "mirai_precondition_start" => KnownNames::MiraiPreconditionStart, - "mirai_precondition" => KnownNames::MiraiPrecondition, - "mirai_result" => KnownNames::MiraiResult, - "mirai_set_model_field" => KnownNames::MiraiSetModelField, - "mirai_verify" => KnownNames::MiraiVerify, - "raw_vec" => get_known_name_for_raw_vec_namespace(def_path_data_iter), - "rt" => get_known_name_for_panicking_namespace(def_path_data_iter), - "slice" => get_known_name_for_slice_namespace(def_path_data_iter), - "sync" => get_known_name_for_sync_namespace(def_path_data_iter), - _ => KnownNames::None, - }) - .unwrap_or(KnownNames::None) - }; +fn name_from_type_ns( + def_path_data: &rustc_hir::definitions::DisambiguatedDefPathData, +) -> Option<&str> { + match &def_path_data.data { + DefPathData::TypeNs(name) => Some(name.as_str()), + _ => None, + } +} - let crate_name = tcx.crate_name(def_id.krate); - match crate_name.as_str() { - "alloc" | "core" | "mirai_annotations" | "std" => { - get_known_name_for_known_crate(def_path_data_iter) - } - _ => KnownNames::None, - } +fn name_from_value_ns( + def_path_data: &rustc_hir::definitions::DisambiguatedDefPathData, +) -> Option<&str> { + match &def_path_data.data { + DefPathData::ValueNs(name) => Some(name.as_str()), + _ => None, } } + +fn is_foreign_module(def_path_data: &rustc_hir::definitions::DisambiguatedDefPathData) -> bool { + matches!(def_path_data.data, DefPathData::ForeignMod) +} diff --git a/checker/tests/run-pass/known_name_resolution.rs b/checker/tests/run-pass/known_name_resolution.rs new file mode 100644 index 00000000..baa82217 --- /dev/null +++ b/checker/tests/run-pass/known_name_resolution.rs @@ -0,0 +1,19 @@ +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +// A test that visits `KnownNamesCache::get_known_name_for` with a `DefId` for a function +// that's defined inside the body a `KnownName` function, but has a different signature. +// See https://github.com/endorlabs/MIRAI/issues/26#issuecomment-2566638406 for details. + +fn try_remove(v: &mut Vec, idx: usize) -> Option { + if idx < v.len() { + Some(v.remove(idx)) + } else { + None + } +} + +pub fn main() { + let mut data = vec![1, 2, 3]; + try_remove(&mut data, 0); +} \ No newline at end of file