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