diff --git a/rap/src/analysis/utils/def_path.rs b/rap/src/analysis/utils/def_path.rs index 03ba549..753a8f1 100644 --- a/rap/src/analysis/utils/def_path.rs +++ b/rap/src/analysis/utils/def_path.rs @@ -2,28 +2,57 @@ use rustc_middle::ty::TyCtxt; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::PrimTy; +use rustc_errors; use rustc_span::symbol::{Ident, Symbol}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_hir::{ImplItemRef, ItemKind, Mutability, Node, OwnerId, TraitItemRef}; use rustc_middle::ty::{FloatTy, IntTy, UintTy}; -/* pub fn def_path_last_def_id<'tcx>(tcx: &TyCtxt<'tcx>, path: &[&str]) -> DefId { def_path_def_ids(tcx, path).last().unwrap() } + +pub struct DefPath { + def_ids: Vec, +} +impl DefPath { + //path like "std::vec::Vec" + pub fn new(raw: &str, tcx: &TyCtxt<'_>) -> Self { + let path: Vec<&str> = raw.split("::").collect(); + let def_ids: Vec = def_path_def_ids(tcx, &path).collect(); + if def_ids.len() == 0 { + panic!("Fail to parse def path {}", raw); + } + DefPath {def_ids} + } + + pub fn last_def_id(&self) -> DefId { + *self.def_ids.last().unwrap() + } +} -/* Copied from Clippy - * https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs +/* Modified from Clippy + * https://github.com/rust-lang/rust-clippy/blob/6d61bd/clippy_utils/src/lib.rs + * Note: Commit 6b61bd matches rustc nightly 2024-06-30 * */ /// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`]. -pub fn def_path_def_ids<'tcx>(tcx: &TyCtxt<'tcx>, path: &[&str]) -> impl Iterator { +pub fn def_path_def_ids(tcx: &TyCtxt<'_>, path: &[&str]) -> impl Iterator { def_path_res(tcx, path).into_iter().filter_map(|res| res.opt_def_id()) } + pub fn def_path_res(tcx: &TyCtxt<'_>, path: &[&str]) -> Vec { - let (base, path) = match *path { + fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator + '_ { + tcx.crates(()) + .iter() + .copied() + .filter(move |&num| tcx.crate_name(num) == name) + .map(CrateNum::as_def_id) + } + + let (base, mut path) = match *path { [primitive] => { return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)]; }, @@ -39,16 +68,40 @@ pub fn def_path_res(tcx: &TyCtxt<'_>, path: &[&str]) -> Vec { None }; - let crates = find_primitive_impls(tcx, base) + let starts = find_primitive_impls(tcx, base) + .chain(find_crates(*tcx, base_sym)) .chain(local_crate) - .map(|id| Res::Def(tcx.def_kind(id), id)) - .chain(find_crates(tcx, base_sym)) - .collect(); + .map(|id| Res::Def(tcx.def_kind(id), id)); + + let mut resolutions: Vec = starts.collect(); + + while let [segment, rest @ ..] = path { + path = rest; + let segment = Symbol::intern(segment); + + resolutions = resolutions + .into_iter() + .filter_map(|res| res.opt_def_id()) + .flat_map(|def_id| { + // When the current def_id is e.g. `struct S`, check the impl items in + // `impl S { ... }` + let inherent_impl_children = tcx + .inherent_impls(def_id) + .into_iter() + .flatten() + .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment)); + + let direct_children = item_children_by_name(tcx, def_id, segment); - def_path_res_with_base(tcx, crates, path) + inherent_impl_children.chain(direct_children) + }) + .collect(); + } + + resolutions } -fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { +fn find_primitive_impls<'tcx>(tcx: &TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let ty = match name { "bool" => SimplifiedType::Bool, "char" => SimplifiedType::Char, @@ -75,13 +128,17 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), _ => { - return [].iter().copied(); + return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]) + .into_iter() + .flatten() + .copied(); }, }; - tcx.incoherent_impls(ty).iter().copied() + + tcx.incoherent_impls(ty).into_iter().flatten().copied() } -*/ -fn non_local_item_children_by_name<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId, name: Symbol) -> Vec { + +fn non_local_item_children_by_name(tcx: &TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { match tcx.def_kind(def_id) { DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx .module_children(def_id) @@ -100,7 +157,7 @@ fn non_local_item_children_by_name<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId, name } } -fn local_item_children_by_name<'tcx>(tcx: &TyCtxt<'tcx>, local_id: LocalDefId, name: Symbol) -> Vec { +fn local_item_children_by_name(tcx: &TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec { let hir = tcx.hir(); let root_mod; @@ -141,7 +198,7 @@ fn local_item_children_by_name<'tcx>(tcx: &TyCtxt<'tcx>, local_id: LocalDefId, n } } -fn item_children_by_name<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId, name: Symbol) -> Vec { +fn item_children_by_name(tcx: &TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { if let Some(local_id) = def_id.as_local() { local_item_children_by_name(tcx, local_id, name) } else { diff --git a/rap/src/lib.rs b/rap/src/lib.rs index 6ca0306..253bffb 100644 --- a/rap/src/lib.rs +++ b/rap/src/lib.rs @@ -15,6 +15,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_hir; +extern crate rustc_errors; use rustc_middle::ty::TyCtxt; use rustc_driver::{Compilation, Callbacks};