1use rustc_hir::HirId;
2use rustc_hir::PrimTy;
3use rustc_hir::def::{DefKind, Res};
4use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
5use rustc_hir::{ImplItemId, ItemKind, Mutability, Node, OwnerId, TraitItemId};
6use rustc_middle::ty::TyCtxt;
7use rustc_middle::ty::fast_reject::SimplifiedType;
8use rustc_middle::ty::{FloatTy, IntTy, UintTy};
9use rustc_span::symbol::{Ident, Symbol};
10
11pub fn path_str_def_id<'tcx>(tcx: TyCtxt<'tcx>, path_str: &str) -> DefId {
12 let path: Vec<&str> = path_str.split("::").collect();
13 def_path_last_def_id(&tcx, &path)
14}
15
16pub fn def_path_last_def_id<'tcx>(tcx: &TyCtxt<'tcx>, path: &[&str]) -> DefId {
17 def_path_def_ids(tcx, path)
18 .last()
19 .expect(&format!("can not resolve {:?}", path))
20}
21
22pub struct DefPath {
23 def_ids: Vec<DefId>,
24}
25
26impl DefPath {
27 pub fn new(raw: &str, tcx: &TyCtxt<'_>) -> Self {
29 let path: Vec<&str> = raw.split("::").collect();
30 let def_ids: Vec<DefId> = def_path_def_ids(tcx, &path).collect();
31 if def_ids.len() == 0 {
32 panic!("Fail to parse def path {}", raw);
33 }
34 DefPath { def_ids }
35 }
36
37 pub fn last_def_id(&self) -> DefId {
38 *self.def_ids.last().unwrap()
39 }
40}
41
42pub fn def_path_def_ids(tcx: &TyCtxt<'_>, path: &[&str]) -> impl Iterator<Item = DefId> {
49 def_path_res(tcx, path)
50 .into_iter()
51 .filter_map(|res| res.opt_def_id())
52}
53
54pub fn def_path_res(tcx: &TyCtxt<'_>, path: &[&str]) -> Vec<Res> {
55 let (base, path) = match path {
56 [primitive] => {
57 return vec![
58 PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy),
59 ];
60 }
61 [base, path @ ..] => (base, path),
62 _ => return Vec::new(),
63 };
64
65 let base_sym = Symbol::intern(base);
66
67 let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
68 Some(LOCAL_CRATE.as_def_id())
69 } else {
70 None
71 };
72
73 let crates = find_primitive_impls(tcx, base)
74 .chain(local_crate)
75 .map(|id| Res::Def(tcx.def_kind(id), id))
76 .chain(find_crates(tcx, base_sym))
77 .collect();
78
79 def_path_res_with_base(tcx, crates, path)
80}
81
82pub fn def_path_res_with_base(tcx: &TyCtxt<'_>, mut base: Vec<Res>, mut path: &[&str]) -> Vec<Res> {
83 while let [segment, rest @ ..] = path {
84 path = rest;
85 let segment = Symbol::intern(segment);
86
87 base = base
88 .into_iter()
89 .filter_map(|res| res.opt_def_id())
90 .flat_map(|def_id| {
91 let inherent_impl_children = tcx
94 .inherent_impls(def_id)
95 .iter()
96 .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
97
98 let direct_children = item_children_by_name(tcx, def_id, segment);
99
100 inherent_impl_children.chain(direct_children)
101 })
102 .collect();
103 }
104
105 base
106}
107
108fn find_primitive_impls<'tcx>(
109 tcx: &TyCtxt<'tcx>,
110 name: &str,
111) -> impl Iterator<Item = DefId> + 'tcx {
112 let ty = match name {
113 "bool" => SimplifiedType::Bool,
114 "char" => SimplifiedType::Char,
115 "str" => SimplifiedType::Str,
116 "array" => SimplifiedType::Array,
117 "slice" => SimplifiedType::Slice,
118 "const_ptr" => SimplifiedType::Ptr(Mutability::Not),
122 "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
123 "isize" => SimplifiedType::Int(IntTy::Isize),
124 "i8" => SimplifiedType::Int(IntTy::I8),
125 "i16" => SimplifiedType::Int(IntTy::I16),
126 "i32" => SimplifiedType::Int(IntTy::I32),
127 "i64" => SimplifiedType::Int(IntTy::I64),
128 "i128" => SimplifiedType::Int(IntTy::I128),
129 "usize" => SimplifiedType::Uint(UintTy::Usize),
130 "u8" => SimplifiedType::Uint(UintTy::U8),
131 "u16" => SimplifiedType::Uint(UintTy::U16),
132 "u32" => SimplifiedType::Uint(UintTy::U32),
133 "u64" => SimplifiedType::Uint(UintTy::U64),
134 "u128" => SimplifiedType::Uint(UintTy::U128),
135 "f32" => SimplifiedType::Float(FloatTy::F32),
136 "f64" => SimplifiedType::Float(FloatTy::F64),
137 _ => {
138 return [].iter().copied();
139 }
140 };
141
142 tcx.incoherent_impls(ty).iter().copied()
143}
144
145fn non_local_item_children_by_name(tcx: &TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
146 match tcx.def_kind(def_id) {
147 DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
148 .module_children(def_id)
149 .iter()
150 .filter(|item| item.ident.name == name)
151 .map(|child| child.res.expect_non_local())
152 .collect(),
153 DefKind::Impl { .. } => tcx
154 .associated_item_def_ids(def_id)
155 .iter()
156 .copied()
157 .filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
158 .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
159 .collect(),
160 _ => Vec::new(),
161 }
162}
163
164fn local_item_children_by_name(tcx: &TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
165 let root_mod;
166 let hir_node = tcx.hir_node_by_def_id(local_id);
167 let item_kind = match hir_node {
168 Node::Crate(module) => {
169 root_mod = ItemKind::Mod(hir_node.ident().unwrap(), module);
170 &root_mod
171 }
172 Node::Item(item) => &item.kind,
173 _ => return Vec::new(),
174 };
175
176 let res = |ident: Ident, owner_id: OwnerId| {
177 if ident.name == name {
178 let def_id = owner_id.to_def_id();
179 Some(Res::Def(tcx.def_kind(def_id), def_id))
180 } else {
181 None
182 }
183 };
184
185 match item_kind {
186 ItemKind::Mod(_ident, module) => module
187 .item_ids
188 .iter()
189 .filter_map(|&item_id| res(tcx.hir_ident(item_id.hir_id()), item_id.owner_id))
190 .collect(),
191 ItemKind::Impl(r#impl) => r#impl
192 .items
193 .iter()
194 .filter_map(|&ImplItemId { owner_id }| {
195 res(tcx.hir_ident(HirId::from(owner_id)), owner_id)
196 })
197 .collect(),
198 ItemKind::Trait(.., trait_item_refs) => trait_item_refs
199 .iter()
200 .filter_map(|&TraitItemId { owner_id }| {
201 res(tcx.hir_ident(HirId::from(owner_id)), owner_id)
202 })
203 .collect(),
204 _ => Vec::new(),
205 }
206}
207
208fn item_children_by_name(tcx: &TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
209 if let Some(local_id) = def_id.as_local() {
210 local_item_children_by_name(tcx, local_id, name)
211 } else {
212 non_local_item_children_by_name(tcx, def_id, name)
213 }
214}
215
216pub fn find_crates(tcx: &TyCtxt<'_>, name: Symbol) -> Vec<Res> {
217 tcx.crates(())
218 .iter()
219 .copied()
220 .filter(move |&num| tcx.crate_name(num) == name)
221 .map(CrateNum::as_def_id)
222 .map(|id| Res::Def(tcx.def_kind(id), id))
223 .collect()
224}