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