]>
Commit | Line | Data |
---|---|---|
3c0e092e | 1 | use crate::hir::{ModuleItems, Owner}; |
49aad941 | 2 | use crate::middle::debugger_visualizer::DebuggerVisualizerFile; |
353b0b11 FG |
3 | use crate::query::LocalCrate; |
4 | use crate::ty::TyCtxt; | |
3dfed10e | 5 | use rustc_ast as ast; |
17df50a5 XL |
6 | use rustc_data_structures::fingerprint::Fingerprint; |
7 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
b7449926 | 8 | use rustc_data_structures::svh::Svh; |
49aad941 | 9 | use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; |
dfeec247 | 10 | use rustc_hir::def::{DefKind, Res}; |
353b0b11 FG |
11 | use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; |
12 | use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; | |
c295e0f8 | 13 | use rustc_hir::intravisit::{self, Visitor}; |
dfeec247 | 14 | use rustc_hir::*; |
49aad941 | 15 | use rustc_index::Idx; |
5099ac24 | 16 | use rustc_middle::hir::nested_filter; |
136023e0 | 17 | use rustc_span::def_id::StableCrateId; |
136023e0 | 18 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
9c376795 | 19 | use rustc_span::Span; |
60c5eb7d | 20 | use rustc_target::spec::abi::Abi; |
e9174d1e | 21 | |
064997fb | 22 | #[inline] |
9ffffee4 | 23 | pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { |
ba9703b0 XL |
24 | match node { |
25 | Node::Item(Item { | |
9ffffee4 | 26 | owner_id, |
ba9703b0 XL |
27 | kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), |
28 | .. | |
29 | }) | |
30 | | Node::TraitItem(TraitItem { | |
9ffffee4 | 31 | owner_id, |
ba9703b0 XL |
32 | kind: |
33 | TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), | |
34 | .. | |
35 | }) | |
36 | | Node::ImplItem(ImplItem { | |
9ffffee4 | 37 | owner_id, |
ba9703b0 XL |
38 | kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), |
39 | .. | |
9ffffee4 FG |
40 | }) => Some((owner_id.def_id, *body)), |
41 | ||
42 | Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { | |
43 | Some((*def_id, *body)) | |
44 | } | |
94b46f34 | 45 | |
9ffffee4 | 46 | Node::AnonConst(constant) => Some((constant.def_id, constant.body)), |
32a655c1 | 47 | |
ba9703b0 | 48 | _ => None, |
8bb4bdeb | 49 | } |
ba9703b0 | 50 | } |
8bb4bdeb | 51 | |
9c376795 | 52 | fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool { |
ba9703b0 | 53 | match associated_body(node) { |
9ffffee4 | 54 | Some((_, b)) => b.hir_id == hir_id, |
ba9703b0 | 55 | None => false, |
32a655c1 | 56 | } |
1a4d82fc JJ |
57 | } |
58 | ||
ba9703b0 XL |
59 | #[derive(Copy, Clone)] |
60 | pub struct Map<'hir> { | |
61 | pub(super) tcx: TyCtxt<'hir>, | |
1a4d82fc JJ |
62 | } |
63 | ||
74b04a01 XL |
64 | /// An iterator that walks up the ancestor tree of a given `HirId`. |
65 | /// Constructed using `tcx.hir().parent_iter(hir_id)`. | |
c295e0f8 | 66 | pub struct ParentHirIterator<'hir> { |
e74abb32 | 67 | current_id: HirId, |
c295e0f8 | 68 | map: Map<'hir>, |
e74abb32 XL |
69 | } |
70 | ||
c295e0f8 | 71 | impl<'hir> Iterator for ParentHirIterator<'hir> { |
2b03887a | 72 | type Item = HirId; |
e74abb32 XL |
73 | |
74 | fn next(&mut self) -> Option<Self::Item> { | |
75 | if self.current_id == CRATE_HIR_ID { | |
76 | return None; | |
77 | } | |
e74abb32 | 78 | |
353b0b11 FG |
79 | // There are nodes that do not have entries, so we need to skip them. |
80 | let parent_id = self.map.parent_id(self.current_id); | |
e74abb32 | 81 | |
353b0b11 FG |
82 | if parent_id == self.current_id { |
83 | self.current_id = CRATE_HIR_ID; | |
84 | return None; | |
17df50a5 | 85 | } |
353b0b11 FG |
86 | |
87 | self.current_id = parent_id; | |
88 | return Some(parent_id); | |
17df50a5 XL |
89 | } |
90 | } | |
91 | ||
92 | /// An iterator that walks up the ancestor tree of a given `HirId`. | |
93 | /// Constructed using `tcx.hir().parent_owner_iter(hir_id)`. | |
c295e0f8 | 94 | pub struct ParentOwnerIterator<'hir> { |
17df50a5 | 95 | current_id: HirId, |
c295e0f8 | 96 | map: Map<'hir>, |
17df50a5 XL |
97 | } |
98 | ||
c295e0f8 | 99 | impl<'hir> Iterator for ParentOwnerIterator<'hir> { |
2b03887a | 100 | type Item = (OwnerId, OwnerNode<'hir>); |
17df50a5 XL |
101 | |
102 | fn next(&mut self) -> Option<Self::Item> { | |
103 | if self.current_id.local_id.index() != 0 { | |
104 | self.current_id.local_id = ItemLocalId::new(0); | |
94222f64 | 105 | if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) { |
5099ac24 | 106 | return Some((self.current_id.owner, node.node)); |
17df50a5 XL |
107 | } |
108 | } | |
109 | if self.current_id == CRATE_HIR_ID { | |
110 | return None; | |
111 | } | |
112 | loop { | |
113 | // There are nodes that do not have entries, so we need to skip them. | |
2b03887a | 114 | let parent_id = self.map.def_key(self.current_id.owner.def_id).parent; |
17df50a5 | 115 | |
2b03887a | 116 | let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| { |
17df50a5 XL |
117 | let def_id = LocalDefId { local_def_index }; |
118 | self.map.local_def_id_to_hir_id(def_id).owner | |
119 | }); | |
2b03887a | 120 | self.current_id = HirId::make_owner(parent_id.def_id); |
17df50a5 XL |
121 | |
122 | // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. | |
94222f64 | 123 | if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) { |
5099ac24 | 124 | return Some((self.current_id.owner, node.node)); |
e74abb32 | 125 | } |
e74abb32 XL |
126 | } |
127 | } | |
128 | } | |
129 | ||
32a655c1 | 130 | impl<'hir> Map<'hir> { |
f2b60f7d | 131 | #[inline] |
5099ac24 | 132 | pub fn krate(self) -> &'hir Crate<'hir> { |
17df50a5 | 133 | self.tcx.hir_crate(()) |
74b04a01 XL |
134 | } |
135 | ||
f2b60f7d | 136 | #[inline] |
5099ac24 | 137 | pub fn root_module(self) -> &'hir Mod<'hir> { |
2b03887a | 138 | match self.tcx.hir_owner(CRATE_OWNER_ID).map(|o| o.node) { |
c295e0f8 XL |
139 | Some(OwnerNode::Crate(item)) => item, |
140 | _ => bug!(), | |
141 | } | |
142 | } | |
143 | ||
f2b60f7d | 144 | #[inline] |
04454e1e FG |
145 | pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir { |
146 | self.tcx.hir_crate_items(()).items.iter().copied() | |
147 | } | |
148 | ||
f2b60f7d | 149 | #[inline] |
923072b8 FG |
150 | pub fn module_items(self, module: LocalDefId) -> impl Iterator<Item = ItemId> + 'hir { |
151 | self.tcx.hir_module_items(module).items() | |
152 | } | |
153 | ||
5099ac24 | 154 | pub fn def_key(self, def_id: LocalDefId) -> DefKey { |
136023e0 | 155 | // Accessing the DefKey is ok, since it is part of DefPathHash. |
923072b8 | 156 | self.tcx.definitions_untracked().def_key(def_id) |
b039eaaf SL |
157 | } |
158 | ||
5099ac24 | 159 | pub fn def_path(self, def_id: LocalDefId) -> DefPath { |
136023e0 | 160 | // Accessing the DefPath is ok, since it is part of DefPathHash. |
923072b8 | 161 | self.tcx.definitions_untracked().def_path(def_id) |
136023e0 XL |
162 | } |
163 | ||
164 | #[inline] | |
165 | pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash { | |
166 | // Accessing the DefPathHash is ok, it is incr. comp. stable. | |
923072b8 | 167 | self.tcx.definitions_untracked().def_path_hash(def_id) |
b039eaaf SL |
168 | } |
169 | ||
abe05a73 | 170 | #[inline] |
5099ac24 FG |
171 | pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId { |
172 | self.tcx.local_def_id_to_hir_id(def_id) | |
ba9703b0 XL |
173 | } |
174 | ||
064997fb FG |
175 | /// Do not call this function directly. The query should be called. |
176 | pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> { | |
f9f354fc | 177 | let hir_id = self.local_def_id_to_hir_id(local_def_id); |
353b0b11 FG |
178 | let node = match self.find(hir_id) { |
179 | Some(node) => node, | |
180 | None => match self.def_key(local_def_id).disambiguated_data.data { | |
181 | // FIXME: Some anonymous constants do not have corresponding HIR nodes, | |
182 | // so many local queries will panic on their def ids. `None` is currently | |
183 | // returned here instead of `DefKind::{Anon,Inline}Const` to avoid such panics. | |
184 | // Ideally all def ids should have `DefKind`s, we need to create the missing | |
185 | // HIR nodes or feed relevant query results to achieve that. | |
186 | DefPathData::AnonConst => return None, | |
187 | _ => bug!("no HIR node for def id {local_def_id:?}"), | |
188 | }, | |
189 | }; | |
190 | let def_kind = match node { | |
60c5eb7d | 191 | Node::Item(item) => match item.kind { |
5e7ed085 | 192 | ItemKind::Static(_, mt, _) => DefKind::Static(mt), |
60c5eb7d XL |
193 | ItemKind::Const(..) => DefKind::Const, |
194 | ItemKind::Fn(..) => DefKind::Fn, | |
5e7ed085 | 195 | ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), |
60c5eb7d | 196 | ItemKind::Mod(..) => DefKind::Mod, |
f2b60f7d | 197 | ItemKind::OpaqueTy(ref opaque) => { |
353b0b11 | 198 | if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { |
f2b60f7d FG |
199 | DefKind::ImplTraitPlaceholder |
200 | } else { | |
201 | DefKind::OpaqueTy | |
202 | } | |
203 | } | |
60c5eb7d XL |
204 | ItemKind::TyAlias(..) => DefKind::TyAlias, |
205 | ItemKind::Enum(..) => DefKind::Enum, | |
206 | ItemKind::Struct(..) => DefKind::Struct, | |
207 | ItemKind::Union(..) => DefKind::Union, | |
208 | ItemKind::Trait(..) => DefKind::Trait, | |
209 | ItemKind::TraitAlias(..) => DefKind::TraitAlias, | |
f9f354fc XL |
210 | ItemKind::ExternCrate(_) => DefKind::ExternCrate, |
211 | ItemKind::Use(..) => DefKind::Use, | |
fc512014 | 212 | ItemKind::ForeignMod { .. } => DefKind::ForeignMod, |
f9f354fc | 213 | ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, |
9ffffee4 | 214 | ItemKind::Impl(impl_) => DefKind::Impl { of_trait: impl_.of_trait.is_some() }, |
60c5eb7d XL |
215 | }, |
216 | Node::ForeignItem(item) => match item.kind { | |
217 | ForeignItemKind::Fn(..) => DefKind::Fn, | |
5e7ed085 | 218 | ForeignItemKind::Static(_, mt) => DefKind::Static(mt), |
60c5eb7d XL |
219 | ForeignItemKind::Type => DefKind::ForeignTy, |
220 | }, | |
221 | Node::TraitItem(item) => match item.kind { | |
222 | TraitItemKind::Const(..) => DefKind::AssocConst, | |
ba9703b0 | 223 | TraitItemKind::Fn(..) => DefKind::AssocFn, |
60c5eb7d XL |
224 | TraitItemKind::Type(..) => DefKind::AssocTy, |
225 | }, | |
226 | Node::ImplItem(item) => match item.kind { | |
227 | ImplItemKind::Const(..) => DefKind::AssocConst, | |
ba9703b0 | 228 | ImplItemKind::Fn(..) => DefKind::AssocFn, |
2b03887a | 229 | ImplItemKind::Type(..) => DefKind::AssocTy, |
60c5eb7d | 230 | }, |
48663c56 | 231 | Node::Variant(_) => DefKind::Variant, |
532ac7d7 | 232 | Node::Ctor(variant_data) => { |
9c376795 | 233 | let ctor_of = match self.find_parent(hir_id) { |
532ac7d7 XL |
234 | Some(Node::Item(..)) => def::CtorOf::Struct, |
235 | Some(Node::Variant(..)) => def::CtorOf::Variant, | |
236 | _ => unreachable!(), | |
237 | }; | |
487cf647 FG |
238 | match variant_data.ctor_kind() { |
239 | Some(kind) => DefKind::Ctor(ctor_of, kind), | |
240 | None => bug!("constructor node without a constructor"), | |
241 | } | |
9fa01778 | 242 | } |
3c0e092e | 243 | Node::AnonConst(_) => { |
9c376795 | 244 | let inline = match self.find_parent(hir_id) { |
3c0e092e XL |
245 | Some(Node::Expr(&Expr { |
246 | kind: ExprKind::ConstBlock(ref anon_const), .. | |
247 | })) if anon_const.hir_id == hir_id => true, | |
248 | _ => false, | |
249 | }; | |
250 | if inline { DefKind::InlineConst } else { DefKind::AnonConst } | |
251 | } | |
f9f354fc XL |
252 | Node::Field(_) => DefKind::Field, |
253 | Node::Expr(expr) => match expr.kind { | |
064997fb FG |
254 | ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure, |
255 | ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator, | |
f9f354fc XL |
256 | _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)), |
257 | }, | |
f9f354fc XL |
258 | Node::GenericParam(param) => match param.kind { |
259 | GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam, | |
260 | GenericParamKind::Type { .. } => DefKind::TyParam, | |
261 | GenericParamKind::Const { .. } => DefKind::ConstParam, | |
262 | }, | |
5869c6ff | 263 | Node::Crate(_) => DefKind::Mod, |
f9f354fc | 264 | Node::Stmt(_) |
60c5eb7d XL |
265 | | Node::PathSegment(_) |
266 | | Node::Ty(_) | |
923072b8 | 267 | | Node::TypeBinding(_) |
94222f64 | 268 | | Node::Infer(_) |
60c5eb7d XL |
269 | | Node::TraitRef(_) |
270 | | Node::Pat(_) | |
f2b60f7d FG |
271 | | Node::PatField(_) |
272 | | Node::ExprField(_) | |
60c5eb7d XL |
273 | | Node::Local(_) |
274 | | Node::Param(_) | |
275 | | Node::Arm(_) | |
276 | | Node::Lifetime(_) | |
353b0b11 FG |
277 | | Node::Block(_) => span_bug!( |
278 | self.span(hir_id), | |
279 | "unexpected node with def id {local_def_id:?}: {node:?}" | |
280 | ), | |
5869c6ff XL |
281 | }; |
282 | Some(def_kind) | |
283 | } | |
284 | ||
f2b60f7d FG |
285 | /// Finds the id of the parent node to this one. |
286 | /// | |
287 | /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. | |
9c376795 | 288 | pub fn opt_parent_id(self, id: HirId) -> Option<HirId> { |
ba9703b0 | 289 | if id.local_id == ItemLocalId::from_u32(0) { |
17df50a5 | 290 | Some(self.tcx.hir_owner_parent(id.owner)) |
ba9703b0 | 291 | } else { |
5099ac24 | 292 | let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?; |
17df50a5 XL |
293 | let node = owner.nodes[id.local_id].as_ref()?; |
294 | let hir_id = HirId { owner: id.owner, local_id: node.parent }; | |
f2b60f7d FG |
295 | // HIR indexing should have checked that. |
296 | debug_assert_ne!(id.local_id, node.parent); | |
17df50a5 XL |
297 | Some(hir_id) |
298 | } | |
299 | } | |
300 | ||
9c376795 FG |
301 | #[track_caller] |
302 | pub fn parent_id(self, hir_id: HirId) -> HirId { | |
303 | self.opt_parent_id(hir_id) | |
9ffffee4 | 304 | .unwrap_or_else(|| bug!("No parent for node {}", self.node_to_string(hir_id))) |
17df50a5 XL |
305 | } |
306 | ||
9c376795 FG |
307 | pub fn get_parent(self, hir_id: HirId) -> Node<'hir> { |
308 | self.get(self.parent_id(hir_id)) | |
309 | } | |
310 | ||
311 | pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> { | |
312 | self.find(self.opt_parent_id(hir_id)?) | |
313 | } | |
314 | ||
17df50a5 | 315 | /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. |
5099ac24 | 316 | pub fn find(self, id: HirId) -> Option<Node<'hir>> { |
17df50a5 XL |
317 | if id.local_id == ItemLocalId::from_u32(0) { |
318 | let owner = self.tcx.hir_owner(id.owner)?; | |
94222f64 | 319 | Some(owner.node.into()) |
17df50a5 | 320 | } else { |
5099ac24 | 321 | let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?; |
17df50a5 XL |
322 | let node = owner.nodes[id.local_id].as_ref()?; |
323 | Some(node.node) | |
ba9703b0 | 324 | } |
1a4d82fc JJ |
325 | } |
326 | ||
5099ac24 FG |
327 | /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. |
328 | #[inline] | |
329 | pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> { | |
353b0b11 | 330 | self.find(self.tcx.opt_local_def_id_to_hir_id(id)?) |
5099ac24 FG |
331 | } |
332 | ||
17df50a5 | 333 | /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. |
9c376795 | 334 | #[track_caller] |
5099ac24 | 335 | pub fn get(self, id: HirId) -> Node<'hir> { |
17df50a5 XL |
336 | self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id)) |
337 | } | |
338 | ||
5099ac24 FG |
339 | /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. |
340 | #[inline] | |
9c376795 | 341 | #[track_caller] |
5099ac24 FG |
342 | pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> { |
343 | self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id)) | |
344 | } | |
345 | ||
346 | pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> { | |
353b0b11 | 347 | id.as_local().and_then(|id| self.find(self.tcx.opt_local_def_id_to_hir_id(id)?)) |
17df50a5 XL |
348 | } |
349 | ||
5099ac24 | 350 | pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> { |
2b03887a | 351 | let node = self.tcx.hir_owner(OwnerId { def_id: id })?; |
923072b8 | 352 | node.node.generics() |
ba9703b0 | 353 | } |
dfeec247 | 354 | |
487cf647 FG |
355 | pub fn owner(self, id: OwnerId) -> OwnerNode<'hir> { |
356 | self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node | |
357 | } | |
358 | ||
5099ac24 | 359 | pub fn item(self, id: ItemId) -> &'hir Item<'hir> { |
2b03887a | 360 | self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item() |
dfeec247 XL |
361 | } |
362 | ||
5099ac24 | 363 | pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> { |
2b03887a | 364 | self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item() |
32a655c1 SL |
365 | } |
366 | ||
5099ac24 | 367 | pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> { |
2b03887a | 368 | self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item() |
476ff2be SL |
369 | } |
370 | ||
5099ac24 | 371 | pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { |
2b03887a | 372 | self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item() |
fc512014 XL |
373 | } |
374 | ||
5099ac24 | 375 | pub fn body(self, id: BodyId) -> &'hir Body<'hir> { |
3c0e092e | 376 | self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id] |
32a655c1 SL |
377 | } |
378 | ||
9c376795 | 379 | #[track_caller] |
5099ac24 | 380 | pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { |
ba9703b0 | 381 | if let Some(node) = self.find(hir_id) { |
f2b60f7d | 382 | node.fn_decl() |
48663c56 | 383 | } else { |
ba9703b0 | 384 | bug!("no node for hir_id `{}`", hir_id) |
48663c56 | 385 | } |
9fa01778 XL |
386 | } |
387 | ||
9c376795 | 388 | #[track_caller] |
5099ac24 | 389 | pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> { |
ba9703b0 | 390 | if let Some(node) = self.find(hir_id) { |
f2b60f7d | 391 | node.fn_sig() |
60c5eb7d | 392 | } else { |
ba9703b0 | 393 | bug!("no node for hir_id `{}`", hir_id) |
60c5eb7d XL |
394 | } |
395 | } | |
396 | ||
9c376795 | 397 | #[track_caller] |
064997fb | 398 | pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { |
2b03887a | 399 | for (_, node) in self.parent_iter(hir_id) { |
9ffffee4 FG |
400 | if let Some((def_id, _)) = associated_body(node) { |
401 | return def_id; | |
f035d41b XL |
402 | } |
403 | } | |
404 | ||
405 | bug!("no `enclosing_body_owner` for hir_id `{}`", hir_id); | |
406 | } | |
407 | ||
dc9dc135 | 408 | /// Returns the `HirId` that corresponds to the definition of |
0731742a | 409 | /// which this is the body of, i.e., a `fn`, `const` or `static` |
94b46f34 | 410 | /// item (possibly associated), a closure, or a `hir::AnonConst`. |
5099ac24 | 411 | pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId { |
9c376795 | 412 | let parent = self.parent_id(hir_id); |
49aad941 | 413 | assert!(self.find(parent).is_some_and(|n| is_body_owner(n, hir_id)), "{hir_id:?}"); |
dc9dc135 | 414 | parent |
32a655c1 SL |
415 | } |
416 | ||
9ffffee4 FG |
417 | pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { |
418 | let parent = self.parent_id(hir_id); | |
419 | associated_body(self.get(parent)).unwrap().0 | |
32a655c1 SL |
420 | } |
421 | ||
064997fb | 422 | /// Given a `LocalDefId`, returns the `BodyId` associated with it, |
7cac9316 | 423 | /// if the node is a body owner, otherwise returns `None`. |
064997fb | 424 | pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> { |
9ffffee4 FG |
425 | let node = self.find_by_def_id(id)?; |
426 | let (_, body_id) = associated_body(node)?; | |
427 | Some(body_id) | |
cc61c64b XL |
428 | } |
429 | ||
7cac9316 | 430 | /// Given a body owner's id, returns the `BodyId` associated with it. |
9c376795 | 431 | #[track_caller] |
064997fb | 432 | pub fn body_owned_by(self, id: LocalDefId) -> BodyId { |
dc9dc135 | 433 | self.maybe_body_owned_by(id).unwrap_or_else(|| { |
064997fb | 434 | let hir_id = self.local_def_id_to_hir_id(id); |
60c5eb7d | 435 | span_bug!( |
064997fb | 436 | self.span(hir_id), |
60c5eb7d | 437 | "body_owned_by: {} has no associated body", |
064997fb | 438 | self.node_to_string(hir_id) |
60c5eb7d | 439 | ); |
7cac9316 XL |
440 | }) |
441 | } | |
442 | ||
5099ac24 | 443 | pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir { |
f035d41b XL |
444 | self.body(id).params.iter().map(|arg| match arg.pat.kind { |
445 | PatKind::Binding(_, _, ident, _) => ident, | |
3c0e092e | 446 | _ => Ident::empty(), |
f035d41b XL |
447 | }) |
448 | } | |
449 | ||
f9f354fc XL |
450 | /// Returns the `BodyOwnerKind` of this `LocalDefId`. |
451 | /// | |
452 | /// Panics if `LocalDefId` does not have an associated body. | |
5e7ed085 FG |
453 | pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind { |
454 | match self.tcx.def_kind(def_id) { | |
455 | DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => { | |
456 | BodyOwnerKind::Const | |
457 | } | |
458 | DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, | |
459 | DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure, | |
460 | DefKind::Static(mt) => BodyOwnerKind::Static(mt), | |
461 | dk => bug!("{:?} is not a body node: {:?}", def_id, dk), | |
abe05a73 XL |
462 | } |
463 | } | |
464 | ||
f9f354fc XL |
465 | /// Returns the `ConstContext` of the body associated with this `LocalDefId`. |
466 | /// | |
467 | /// Panics if `LocalDefId` does not have an associated body. | |
136023e0 XL |
468 | /// |
469 | /// This should only be used for determining the context of a body, a return | |
a2a8927a XL |
470 | /// value of `Some` does not always suggest that the owner of the body is `const`, |
471 | /// just that it has to be checked as if it were. | |
5e7ed085 FG |
472 | pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> { |
473 | let ccx = match self.body_owner_kind(def_id) { | |
f9f354fc XL |
474 | BodyOwnerKind::Const => ConstContext::Const, |
475 | BodyOwnerKind::Static(mt) => ConstContext::Static(mt), | |
476 | ||
5e7ed085 | 477 | BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None, |
9c376795 FG |
478 | BodyOwnerKind::Fn | BodyOwnerKind::Closure |
479 | if self.tcx.is_const_fn_raw(def_id.to_def_id()) => | |
480 | { | |
5e7ed085 FG |
481 | ConstContext::ConstFn |
482 | } | |
923072b8 | 483 | BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => { |
136023e0 XL |
484 | ConstContext::ConstFn |
485 | } | |
f9f354fc XL |
486 | BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, |
487 | }; | |
488 | ||
489 | Some(ccx) | |
490 | } | |
491 | ||
c295e0f8 XL |
492 | /// Returns an iterator of the `DefId`s for all body-owners in this |
493 | /// crate. If you would prefer to iterate over the bodies | |
494 | /// themselves, you can do `self.hir().krate().body_ids.iter()`. | |
f2b60f7d | 495 | #[inline] |
c295e0f8 | 496 | pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { |
064997fb | 497 | self.tcx.hir_crate_items(()).body_owners.iter().copied() |
c295e0f8 XL |
498 | } |
499 | ||
f2b60f7d | 500 | #[inline] |
49aad941 | 501 | pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { |
064997fb | 502 | par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); |
c295e0f8 XL |
503 | } |
504 | ||
04454e1e FG |
505 | pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { |
506 | let def_kind = self.tcx.def_kind(def_id); | |
507 | match def_kind { | |
508 | DefKind::Trait | DefKind::TraitAlias => def_id, | |
f2b60f7d FG |
509 | DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { |
510 | self.tcx.local_parent(def_id) | |
511 | } | |
04454e1e | 512 | _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind), |
8bb4bdeb XL |
513 | } |
514 | } | |
515 | ||
04454e1e FG |
516 | pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol { |
517 | let def_kind = self.tcx.def_kind(def_id); | |
518 | match def_kind { | |
519 | DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper, | |
f2b60f7d FG |
520 | DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { |
521 | self.tcx.item_name(def_id.to_def_id()) | |
522 | } | |
04454e1e | 523 | _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind), |
8bb4bdeb XL |
524 | } |
525 | } | |
526 | ||
5099ac24 | 527 | pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] { |
17df50a5 | 528 | self.tcx.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..]) |
8bb4bdeb XL |
529 | } |
530 | ||
9fa01778 | 531 | /// Gets the attributes on the crate. This is preferable to |
54a0048b SL |
532 | /// invoking `krate.attrs` because it registers a tighter |
533 | /// dep-graph access. | |
5099ac24 | 534 | pub fn krate_attrs(self) -> &'hir [ast::Attribute] { |
6a06907d | 535 | self.attrs(CRATE_HIR_ID) |
54a0048b SL |
536 | } |
537 | ||
5e7ed085 FG |
538 | pub fn rustc_coherence_is_core(self) -> bool { |
539 | self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core)) | |
540 | } | |
541 | ||
5099ac24 | 542 | pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) { |
94222f64 | 543 | let hir_id = HirId::make_owner(module); |
2b03887a | 544 | match self.tcx.hir_owner(hir_id.owner).map(|o| o.node) { |
94222f64 XL |
545 | Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => { |
546 | (m, span, hir_id) | |
547 | } | |
04454e1e | 548 | Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id), |
e1599b0c | 549 | node => panic!("not a module: {:?}", node), |
9fa01778 XL |
550 | } |
551 | } | |
552 | ||
064997fb | 553 | /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`. |
c295e0f8 XL |
554 | pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) { |
555 | let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID); | |
556 | visitor.visit_mod(top_mod, span, hir_id); | |
557 | } | |
558 | ||
559 | /// Walks the attributes in a crate. | |
560 | pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) { | |
561 | let krate = self.krate(); | |
923072b8 | 562 | for info in krate.owners.iter() { |
5099ac24 | 563 | if let MaybeOwner::Owner(info) = info { |
923072b8 | 564 | for attrs in info.attrs.map.values() { |
3c0e092e | 565 | for a in *attrs { |
923072b8 | 566 | visitor.visit_attribute(a) |
3c0e092e XL |
567 | } |
568 | } | |
c295e0f8 XL |
569 | } |
570 | } | |
571 | } | |
572 | ||
064997fb FG |
573 | /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you |
574 | /// need to process every item-like, and don't care about visiting nested items in a particular | |
9c376795 | 575 | /// order then this method is the best choice. If you do care about this nesting, you should |
064997fb FG |
576 | /// use the `tcx.hir().walk_toplevel_module`. |
577 | /// | |
9c376795 | 578 | /// Note that this function will access HIR for all the item-likes in the crate. If you only |
064997fb FG |
579 | /// need to access some of them, it is usually better to manually loop on the iterators |
580 | /// provided by `tcx.hir_crate_items(())`. | |
c295e0f8 | 581 | /// |
923072b8 | 582 | /// Please see the notes in `intravisit.rs` for more information. |
064997fb | 583 | pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V) |
c295e0f8 | 584 | where |
923072b8 | 585 | V: Visitor<'hir>, |
c295e0f8 | 586 | { |
064997fb FG |
587 | let krate = self.tcx.hir_crate_items(()); |
588 | ||
589 | for id in krate.items() { | |
590 | visitor.visit_item(self.item(id)); | |
c295e0f8 | 591 | } |
c295e0f8 | 592 | |
064997fb FG |
593 | for id in krate.trait_items() { |
594 | visitor.visit_trait_item(self.trait_item(id)); | |
595 | } | |
596 | ||
597 | for id in krate.impl_items() { | |
598 | visitor.visit_impl_item(self.impl_item(id)); | |
599 | } | |
600 | ||
601 | for id in krate.foreign_items() { | |
602 | visitor.visit_foreign_item(self.foreign_item(id)); | |
603 | } | |
c295e0f8 XL |
604 | } |
605 | ||
064997fb FG |
606 | /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to |
607 | /// item-likes in a single module. | |
608 | pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V) | |
60c5eb7d | 609 | where |
923072b8 | 610 | V: Visitor<'hir>, |
0731742a | 611 | { |
f035d41b | 612 | let module = self.tcx.hir_module_items(module); |
0731742a | 613 | |
064997fb FG |
614 | for id in module.items() { |
615 | visitor.visit_item(self.item(id)); | |
0731742a XL |
616 | } |
617 | ||
064997fb FG |
618 | for id in module.trait_items() { |
619 | visitor.visit_trait_item(self.trait_item(id)); | |
0731742a XL |
620 | } |
621 | ||
064997fb FG |
622 | for id in module.impl_items() { |
623 | visitor.visit_impl_item(self.impl_item(id)); | |
0731742a | 624 | } |
fc512014 | 625 | |
064997fb FG |
626 | for id in module.foreign_items() { |
627 | visitor.visit_foreign_item(self.foreign_item(id)); | |
fc512014 | 628 | } |
0731742a XL |
629 | } |
630 | ||
923072b8 | 631 | pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) { |
04454e1e FG |
632 | let crate_items = self.tcx.hir_crate_items(()); |
633 | for module in crate_items.submodules.iter() { | |
2b03887a | 634 | f(module.def_id) |
c295e0f8 XL |
635 | } |
636 | } | |
637 | ||
c295e0f8 | 638 | #[inline] |
49aad941 | 639 | pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { |
f2b60f7d | 640 | let crate_items = self.tcx.hir_crate_items(()); |
2b03887a | 641 | par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id)) |
c295e0f8 XL |
642 | } |
643 | ||
74b04a01 | 644 | /// Returns an iterator for the nodes in the ancestor tree of the `current_id` |
9c376795 | 645 | /// until the crate root is reached. Prefer this over your own loop using `parent_id`. |
f2b60f7d | 646 | #[inline] |
2b03887a | 647 | pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir { |
74b04a01 XL |
648 | ParentHirIterator { current_id, map: self } |
649 | } | |
650 | ||
2b03887a | 651 | /// Returns an iterator for the nodes in the ancestor tree of the `current_id` |
9c376795 | 652 | /// until the crate root is reached. Prefer this over your own loop using `parent_id`. |
2b03887a FG |
653 | #[inline] |
654 | pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> { | |
655 | self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.find(id)?))) | |
656 | } | |
657 | ||
17df50a5 | 658 | /// Returns an iterator for the nodes in the ancestor tree of the `current_id` |
9c376795 | 659 | /// until the crate root is reached. Prefer this over your own loop using `parent_id`. |
f2b60f7d | 660 | #[inline] |
c295e0f8 | 661 | pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> { |
17df50a5 XL |
662 | ParentOwnerIterator { current_id, map: self } |
663 | } | |
664 | ||
5869c6ff | 665 | /// Checks if the node is left-hand side of an assignment. |
5099ac24 | 666 | pub fn is_lhs(self, id: HirId) -> bool { |
9c376795 | 667 | match self.find_parent(id) { |
5869c6ff XL |
668 | Some(Node::Expr(expr)) => match expr.kind { |
669 | ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id, | |
670 | _ => false, | |
671 | }, | |
672 | _ => false, | |
673 | } | |
674 | } | |
675 | ||
e1599b0c XL |
676 | /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. |
677 | /// Used exclusively for diagnostics, to avoid suggestion function calls. | |
5099ac24 | 678 | pub fn is_inside_const_context(self, hir_id: HirId) -> bool { |
064997fb | 679 | self.body_const_context(self.enclosing_body_owner(hir_id)).is_some() |
e1599b0c XL |
680 | } |
681 | ||
dc9dc135 | 682 | /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a |
3b2f2976 | 683 | /// `while` or `loop` before reaching it, as block tail returns are not |
041b39d2 XL |
684 | /// available in them. |
685 | /// | |
686 | /// ``` | |
687 | /// fn foo(x: usize) -> bool { | |
688 | /// if x == 1 { | |
e1599b0c | 689 | /// true // If `get_return_block` gets passed the `id` corresponding |
dc9dc135 | 690 | /// } else { // to this, it will return `foo`'s `HirId`. |
041b39d2 XL |
691 | /// false |
692 | /// } | |
693 | /// } | |
694 | /// ``` | |
695 | /// | |
04454e1e | 696 | /// ```compile_fail,E0308 |
041b39d2 XL |
697 | /// fn foo(x: usize) -> bool { |
698 | /// loop { | |
e1599b0c | 699 | /// true // If `get_return_block` gets passed the `id` corresponding |
041b39d2 XL |
700 | /// } // to this, it will return `None`. |
701 | /// false | |
702 | /// } | |
703 | /// ``` | |
5099ac24 | 704 | pub fn get_return_block(self, id: HirId) -> Option<HirId> { |
74b04a01 | 705 | let mut iter = self.parent_iter(id).peekable(); |
e74abb32 | 706 | let mut ignore_tail = false; |
9c376795 FG |
707 | if let Some(Node::Expr(Expr { kind: ExprKind::Ret(_), .. })) = self.find(id) { |
708 | // When dealing with `return` statements, we don't care about climbing only tail | |
709 | // expressions. | |
710 | ignore_tail = true; | |
e74abb32 XL |
711 | } |
712 | while let Some((hir_id, node)) = iter.next() { | |
713 | if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) { | |
714 | match next_node { | |
715 | Node::Block(Block { expr: None, .. }) => return None, | |
ba9703b0 XL |
716 | // The current node is not the tail expression of its parent. |
717 | Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None, | |
e74abb32 XL |
718 | _ => {} |
719 | } | |
720 | } | |
721 | match node { | |
60c5eb7d XL |
722 | Node::Item(_) |
723 | | Node::ForeignItem(_) | |
724 | | Node::TraitItem(_) | |
923072b8 | 725 | | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. }) |
60c5eb7d | 726 | | Node::ImplItem(_) => return Some(hir_id), |
ba9703b0 XL |
727 | // Ignore `return`s on the first iteration |
728 | Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. }) | |
729 | | Node::Local(_) => { | |
730 | return None; | |
041b39d2 | 731 | } |
e74abb32 | 732 | _ => {} |
041b39d2 | 733 | } |
e74abb32 XL |
734 | } |
735 | None | |
041b39d2 XL |
736 | } |
737 | ||
2b03887a | 738 | /// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no |
c1a9b12d | 739 | /// parent item is in this map. The "parent item" is the closest parent node |
94b46f34 | 740 | /// in the HIR which is recorded by the map and is an item, either an item |
c1a9b12d | 741 | /// in a module, trait, or impl. |
2b03887a | 742 | pub fn get_parent_item(self, hir_id: HirId) -> OwnerId { |
5099ac24 FG |
743 | if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() { |
744 | def_id | |
94222f64 | 745 | } else { |
2b03887a | 746 | CRATE_OWNER_ID |
c1a9b12d SL |
747 | } |
748 | } | |
749 | ||
2b03887a | 750 | /// Returns the `OwnerId` of `id`'s nearest module parent, or `id` itself if no |
0bf4aa26 | 751 | /// module parent is in this map. |
2b03887a | 752 | pub(super) fn get_module_parent_node(self, hir_id: HirId) -> OwnerId { |
5099ac24 | 753 | for (def_id, node) in self.parent_owner_iter(hir_id) { |
94222f64 | 754 | if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node { |
5099ac24 | 755 | return def_id; |
e74abb32 XL |
756 | } |
757 | } | |
2b03887a | 758 | CRATE_OWNER_ID |
e74abb32 XL |
759 | } |
760 | ||
5869c6ff XL |
761 | /// When on an if expression, a match arm tail expression or a match arm, give back |
762 | /// the enclosing `if` or `match` expression. | |
e74abb32 | 763 | /// |
5869c6ff | 764 | /// Used by error reporting when there's a type error in an if or match arm caused by the |
e74abb32 | 765 | /// expression needing to be unit. |
5099ac24 | 766 | pub fn get_if_cause(self, hir_id: HirId) -> Option<&'hir Expr<'hir>> { |
74b04a01 | 767 | for (_, node) in self.parent_iter(hir_id) { |
e74abb32 | 768 | match node { |
ba9703b0 XL |
769 | Node::Item(_) |
770 | | Node::ForeignItem(_) | |
771 | | Node::TraitItem(_) | |
772 | | Node::ImplItem(_) | |
773 | | Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break, | |
5869c6ff XL |
774 | Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => { |
775 | return Some(expr); | |
776 | } | |
e74abb32 XL |
777 | _ => {} |
778 | } | |
0bf4aa26 | 779 | } |
e74abb32 | 780 | None |
54a0048b SL |
781 | } |
782 | ||
dc9dc135 | 783 | /// Returns the nearest enclosing scope. A scope is roughly an item or block. |
5099ac24 | 784 | pub fn get_enclosing_scope(self, hir_id: HirId) -> Option<HirId> { |
74b04a01 | 785 | for (hir_id, node) in self.parent_iter(hir_id) { |
ba9703b0 XL |
786 | if let Node::Item(Item { |
787 | kind: | |
60c5eb7d | 788 | ItemKind::Fn(..) |
f035d41b XL |
789 | | ItemKind::Const(..) |
790 | | ItemKind::Static(..) | |
60c5eb7d XL |
791 | | ItemKind::Mod(..) |
792 | | ItemKind::Enum(..) | |
793 | | ItemKind::Struct(..) | |
794 | | ItemKind::Union(..) | |
795 | | ItemKind::Trait(..) | |
ba9703b0 XL |
796 | | ItemKind::Impl { .. }, |
797 | .. | |
798 | }) | |
799 | | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(..), .. }) | |
800 | | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(..), .. }) | |
801 | | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(..), .. }) | |
802 | | Node::Block(_) = node | |
803 | { | |
e74abb32 XL |
804 | return Some(hir_id); |
805 | } | |
806 | } | |
807 | None | |
1a4d82fc JJ |
808 | } |
809 | ||
416331ca | 810 | /// Returns the defining scope for an opaque type definition. |
5099ac24 | 811 | pub fn get_defining_scope(self, id: HirId) -> HirId { |
dc9dc135 XL |
812 | let mut scope = id; |
813 | loop { | |
e74abb32 | 814 | scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID); |
5869c6ff XL |
815 | if scope == CRATE_HIR_ID || !matches!(self.get(scope), Node::Block(_)) { |
816 | return scope; | |
dc9dc135 XL |
817 | } |
818 | } | |
1a4d82fc JJ |
819 | } |
820 | ||
5099ac24 | 821 | pub fn get_foreign_abi(self, hir_id: HirId) -> Abi { |
48663c56 | 822 | let parent = self.get_parent_item(hir_id); |
5099ac24 | 823 | if let Some(node) = self.tcx.hir_owner(parent) { |
94222f64 XL |
824 | if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node |
825 | { | |
fc512014 | 826 | return *abi; |
7453a54e | 827 | } |
1a4d82fc | 828 | } |
5099ac24 FG |
829 | bug!( |
830 | "expected foreign mod or inlined parent, found {}", | |
2b03887a | 831 | self.node_to_string(HirId::make_owner(parent.def_id)) |
5099ac24 | 832 | ) |
1a4d82fc JJ |
833 | } |
834 | ||
487cf647 FG |
835 | pub fn expect_owner(self, def_id: LocalDefId) -> OwnerNode<'hir> { |
836 | self.tcx | |
837 | .hir_owner(OwnerId { def_id }) | |
838 | .unwrap_or_else(|| bug!("expected owner for {:?}", def_id)) | |
839 | .node | |
064997fb FG |
840 | } |
841 | ||
5099ac24 | 842 | pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> { |
2b03887a | 843 | match self.tcx.hir_owner(OwnerId { def_id: id }) { |
3c0e092e | 844 | Some(Owner { node: OwnerNode::Item(item), .. }) => item, |
a2a8927a | 845 | _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))), |
532ac7d7 | 846 | } |
9fa01778 XL |
847 | } |
848 | ||
5099ac24 | 849 | pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> { |
2b03887a | 850 | match self.tcx.hir_owner(OwnerId { def_id: id }) { |
3c0e092e | 851 | Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item, |
a2a8927a | 852 | _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))), |
9e0c209e SL |
853 | } |
854 | } | |
855 | ||
5099ac24 | 856 | pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> { |
2b03887a | 857 | match self.tcx.hir_owner(OwnerId { def_id: id }) { |
3c0e092e | 858 | Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item, |
a2a8927a | 859 | _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))), |
c1a9b12d SL |
860 | } |
861 | } | |
862 | ||
9ffffee4 FG |
863 | pub fn get_fn_output(self, def_id: LocalDefId) -> Option<&'hir FnRetTy<'hir>> { |
864 | match self.tcx.hir_owner(OwnerId { def_id }) { | |
865 | Some(Owner { node, .. }) => node.fn_decl().map(|fn_decl| &fn_decl.output), | |
866 | _ => None, | |
867 | } | |
868 | } | |
869 | ||
5099ac24 | 870 | pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> { |
dc9dc135 | 871 | match self.find(id) { |
b7449926 | 872 | Some(Node::Variant(variant)) => variant, |
dc9dc135 | 873 | _ => bug!("expected variant, found {}", self.node_to_string(id)), |
1a4d82fc JJ |
874 | } |
875 | } | |
876 | ||
2b03887a | 877 | pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> { |
a2a8927a | 878 | match self.tcx.hir_owner(id) { |
3c0e092e | 879 | Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item, |
a2a8927a | 880 | _ => { |
2b03887a FG |
881 | bug!( |
882 | "expected foreign item, found {}", | |
883 | self.node_to_string(HirId::make_owner(id.def_id)) | |
884 | ) | |
a2a8927a | 885 | } |
1a4d82fc JJ |
886 | } |
887 | } | |
888 | ||
5099ac24 | 889 | pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> { |
60c5eb7d | 890 | match self.find(id) { |
48663c56 | 891 | Some(Node::Expr(expr)) => expr, |
60c5eb7d | 892 | _ => bug!("expected expr, found {}", self.node_to_string(id)), |
48663c56 | 893 | } |
9fa01778 XL |
894 | } |
895 | ||
923072b8 FG |
896 | #[inline] |
897 | fn opt_ident(self, id: HirId) -> Option<Ident> { | |
898 | match self.get(id) { | |
064997fb | 899 | Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), |
923072b8 FG |
900 | // A `Ctor` doesn't have an identifier itself, but its parent |
901 | // struct/variant does. Compare with `hir::Map::opt_span`. | |
9c376795 | 902 | Node::Ctor(..) => match self.find_parent(id)? { |
923072b8 FG |
903 | Node::Item(item) => Some(item.ident), |
904 | Node::Variant(variant) => Some(variant.ident), | |
905 | _ => unreachable!(), | |
906 | }, | |
907 | node => node.ident(), | |
908 | } | |
909 | } | |
910 | ||
911 | #[inline] | |
912 | pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> { | |
913 | self.opt_ident(id).map(|ident| ident.span) | |
914 | } | |
915 | ||
9ffffee4 FG |
916 | #[inline] |
917 | pub fn ident(self, id: HirId) -> Ident { | |
918 | self.opt_ident(id).unwrap() | |
919 | } | |
920 | ||
923072b8 | 921 | #[inline] |
5099ac24 | 922 | pub fn opt_name(self, id: HirId) -> Option<Symbol> { |
923072b8 | 923 | self.opt_ident(id).map(|ident| ident.name) |
60c5eb7d XL |
924 | } |
925 | ||
5099ac24 | 926 | pub fn name(self, id: HirId) -> Symbol { |
923072b8 | 927 | self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id))) |
1a4d82fc JJ |
928 | } |
929 | ||
dc9dc135 XL |
930 | /// Given a node ID, gets a list of attributes associated with the AST |
931 | /// corresponding to the node-ID. | |
5099ac24 | 932 | pub fn attrs(self, id: HirId) -> &'hir [ast::Attribute] { |
6a06907d | 933 | self.tcx.hir_attrs(id.owner).get(id.local_id) |
1a4d82fc JJ |
934 | } |
935 | ||
3dfed10e | 936 | /// Gets the span of the definition of the specified HIR node. |
064997fb | 937 | /// This is used by `tcx.def_span`. |
5099ac24 | 938 | pub fn span(self, hir_id: HirId) -> Span { |
5869c6ff XL |
939 | self.opt_span(hir_id) |
940 | .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id)) | |
941 | } | |
942 | ||
5099ac24 | 943 | pub fn opt_span(self, hir_id: HirId) -> Option<Span> { |
064997fb FG |
944 | fn until_within(outer: Span, end: Span) -> Span { |
945 | if let Some(end) = end.find_ancestor_inside(outer) { | |
946 | outer.with_hi(end.hi()) | |
947 | } else { | |
948 | outer | |
949 | } | |
950 | } | |
951 | ||
952 | fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) -> Span { | |
953 | if ident.name != kw::Empty { | |
954 | let mut span = until_within(item_span, ident.span); | |
955 | if let Some(g) = generics | |
956 | && !g.span.is_dummy() | |
957 | && let Some(g_span) = g.span.find_ancestor_inside(item_span) | |
958 | { | |
959 | span = span.to(g_span); | |
960 | } | |
961 | span | |
962 | } else { | |
963 | item_span | |
964 | } | |
965 | } | |
966 | ||
17df50a5 | 967 | let span = match self.find(hir_id)? { |
064997fb | 968 | // Function-like. |
2b03887a FG |
969 | Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. }) |
970 | | Node::TraitItem(TraitItem { | |
971 | kind: TraitItemKind::Fn(sig, ..), | |
972 | span: outer_span, | |
973 | .. | |
974 | }) | |
975 | | Node::ImplItem(ImplItem { | |
976 | kind: ImplItemKind::Fn(sig, ..), span: outer_span, .. | |
977 | }) => { | |
978 | // Ensure that the returned span has the item's SyntaxContext, and not the | |
979 | // SyntaxContext of the visibility. | |
980 | sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span) | |
981 | } | |
064997fb FG |
982 | // Constants and Statics. |
983 | Node::Item(Item { | |
984 | kind: | |
985 | ItemKind::Const(ty, ..) | |
986 | | ItemKind::Static(ty, ..) | |
987 | | ItemKind::Impl(Impl { self_ty: ty, .. }), | |
988 | span: outer_span, | |
989 | .. | |
990 | }) | |
991 | | Node::TraitItem(TraitItem { | |
992 | kind: TraitItemKind::Const(ty, ..), | |
993 | span: outer_span, | |
994 | .. | |
995 | }) | |
996 | | Node::ImplItem(ImplItem { | |
997 | kind: ImplItemKind::Const(ty, ..), | |
998 | span: outer_span, | |
999 | .. | |
1000 | }) | |
1001 | | Node::ForeignItem(ForeignItem { | |
1002 | kind: ForeignItemKind::Static(ty, ..), | |
1003 | span: outer_span, | |
1004 | .. | |
1005 | }) => until_within(*outer_span, ty.span), | |
1006 | // With generics and bounds. | |
1007 | Node::Item(Item { | |
1008 | kind: ItemKind::Trait(_, _, generics, bounds, _), | |
1009 | span: outer_span, | |
1010 | .. | |
1011 | }) | |
1012 | | Node::TraitItem(TraitItem { | |
1013 | kind: TraitItemKind::Type(bounds, _), | |
1014 | generics, | |
1015 | span: outer_span, | |
1016 | .. | |
1017 | }) => { | |
1018 | let end = if let Some(b) = bounds.last() { b.span() } else { generics.span }; | |
1019 | until_within(*outer_span, end) | |
1020 | } | |
1021 | // Other cases. | |
5869c6ff | 1022 | Node::Item(item) => match &item.kind { |
2b03887a FG |
1023 | ItemKind::Use(path, _) => { |
1024 | // Ensure that the returned span has the item's SyntaxContext, and not the | |
1025 | // SyntaxContext of the path. | |
1026 | path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span) | |
1027 | } | |
064997fb | 1028 | _ => named_span(item.span, item.ident, item.kind.generics()), |
3dfed10e | 1029 | }, |
064997fb FG |
1030 | Node::Variant(variant) => named_span(variant.span, variant.ident, None), |
1031 | Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)), | |
1032 | Node::ForeignItem(item) => match item.kind { | |
1033 | ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), | |
1034 | _ => named_span(item.span, item.ident, None), | |
3dfed10e | 1035 | }, |
9c376795 | 1036 | Node::Ctor(_) => return self.opt_span(self.parent_id(hir_id)), |
2b03887a FG |
1037 | Node::Expr(Expr { |
1038 | kind: ExprKind::Closure(Closure { fn_decl_span, .. }), | |
1039 | span, | |
1040 | .. | |
1041 | }) => { | |
1042 | // Ensure that the returned span has the item's SyntaxContext. | |
487cf647 | 1043 | fn_decl_span.find_ancestor_inside(*span).unwrap_or(*span) |
064997fb FG |
1044 | } |
1045 | _ => self.span_with_body(hir_id), | |
1046 | }; | |
2b03887a | 1047 | debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt()); |
064997fb FG |
1048 | Some(span) |
1049 | } | |
1050 | ||
1051 | /// Like `hir.span()`, but includes the body of items | |
1052 | /// (instead of just the item header) | |
1053 | pub fn span_with_body(self, hir_id: HirId) -> Span { | |
1054 | match self.get(hir_id) { | |
1055 | Node::Param(param) => param.span, | |
1056 | Node::Item(item) => item.span, | |
1057 | Node::ForeignItem(foreign_item) => foreign_item.span, | |
1058 | Node::TraitItem(trait_item) => trait_item.span, | |
1059 | Node::ImplItem(impl_item) => impl_item.span, | |
5869c6ff XL |
1060 | Node::Variant(variant) => variant.span, |
1061 | Node::Field(field) => field.span, | |
1062 | Node::AnonConst(constant) => self.body(constant.body).value.span, | |
1063 | Node::Expr(expr) => expr.span, | |
f2b60f7d | 1064 | Node::ExprField(field) => field.span, |
5869c6ff | 1065 | Node::Stmt(stmt) => stmt.span, |
923072b8 FG |
1066 | Node::PathSegment(seg) => { |
1067 | let ident_span = seg.ident.span; | |
1068 | ident_span | |
1069 | .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi())) | |
1070 | } | |
5869c6ff | 1071 | Node::Ty(ty) => ty.span, |
923072b8 | 1072 | Node::TypeBinding(tb) => tb.span, |
5869c6ff | 1073 | Node::TraitRef(tr) => tr.path.span, |
5869c6ff | 1074 | Node::Pat(pat) => pat.span, |
f2b60f7d | 1075 | Node::PatField(field) => field.span, |
5869c6ff XL |
1076 | Node::Arm(arm) => arm.span, |
1077 | Node::Block(block) => block.span, | |
9c376795 | 1078 | Node::Ctor(..) => self.span_with_body(self.parent_id(hir_id)), |
487cf647 | 1079 | Node::Lifetime(lifetime) => lifetime.ident.span, |
5869c6ff | 1080 | Node::GenericParam(param) => param.span, |
94222f64 | 1081 | Node::Infer(i) => i.span, |
5869c6ff | 1082 | Node::Local(local) => local.span, |
04454e1e | 1083 | Node::Crate(item) => item.spans.inner_span, |
3dfed10e XL |
1084 | } |
1085 | } | |
1086 | ||
5099ac24 | 1087 | pub fn span_if_local(self, id: DefId) -> Option<Span> { |
9ffffee4 | 1088 | id.is_local().then(|| self.tcx.def_span(id)) |
b039eaaf SL |
1089 | } |
1090 | ||
5099ac24 | 1091 | pub fn res_span(self, res: Res) -> Option<Span> { |
e74abb32 XL |
1092 | match res { |
1093 | Res::Err => None, | |
1094 | Res::Local(id) => Some(self.span(id)), | |
1095 | res => self.span_if_local(res.opt_def_id()?), | |
1096 | } | |
1097 | } | |
1098 | ||
ba9703b0 XL |
1099 | /// Get a representation of this `id` for debugging purposes. |
1100 | /// NOTE: Do NOT use this in diagnostics! | |
5099ac24 | 1101 | pub fn node_to_string(self, id: HirId) -> String { |
ba9703b0 | 1102 | hir_id_to_string(self, id) |
9fa01778 | 1103 | } |
94222f64 XL |
1104 | |
1105 | /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when | |
1106 | /// called with the HirId for the `{ ... }` anon const | |
487cf647 | 1107 | pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> { |
9c376795 | 1108 | match self.get_parent(anon_const) { |
94222f64 | 1109 | Node::GenericParam(GenericParam { |
487cf647 | 1110 | def_id: param_id, |
94222f64 XL |
1111 | kind: GenericParamKind::Const { .. }, |
1112 | .. | |
1113 | }) => Some(*param_id), | |
1114 | _ => None, | |
1115 | } | |
1116 | } | |
1a4d82fc JJ |
1117 | } |
1118 | ||
dfeec247 | 1119 | impl<'hir> intravisit::Map<'hir> for Map<'hir> { |
ba9703b0 | 1120 | fn find(&self, hir_id: HirId) -> Option<Node<'hir>> { |
5099ac24 | 1121 | (*self).find(hir_id) |
ba9703b0 XL |
1122 | } |
1123 | ||
dfeec247 | 1124 | fn body(&self, id: BodyId) -> &'hir Body<'hir> { |
5099ac24 | 1125 | (*self).body(id) |
dfeec247 XL |
1126 | } |
1127 | ||
6a06907d | 1128 | fn item(&self, id: ItemId) -> &'hir Item<'hir> { |
5099ac24 | 1129 | (*self).item(id) |
dfeec247 XL |
1130 | } |
1131 | ||
1132 | fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { | |
5099ac24 | 1133 | (*self).trait_item(id) |
dfeec247 XL |
1134 | } |
1135 | ||
1136 | fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { | |
5099ac24 | 1137 | (*self).impl_item(id) |
dfeec247 | 1138 | } |
fc512014 XL |
1139 | |
1140 | fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { | |
5099ac24 | 1141 | (*self).foreign_item(id) |
fc512014 | 1142 | } |
dfeec247 XL |
1143 | } |
1144 | ||
353b0b11 | 1145 | pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { |
3c0e092e | 1146 | let krate = tcx.hir_crate(()); |
353b0b11 | 1147 | let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); |
17df50a5 | 1148 | |
136023e0 | 1149 | let upstream_crates = upstream_crates(tcx); |
17df50a5 | 1150 | |
923072b8 FG |
1151 | let resolutions = tcx.resolutions(()); |
1152 | ||
17df50a5 XL |
1153 | // We hash the final, remapped names of all local source files so we |
1154 | // don't have to include the path prefix remapping commandline args. | |
1155 | // If we included the full mapping in the SVH, we could only have | |
1156 | // reproducible builds by compiling from the same directory. So we just | |
1157 | // hash the result of the mapping instead of the mapping itself. | |
1158 | let mut source_file_names: Vec<_> = tcx | |
1159 | .sess | |
1160 | .source_map() | |
1161 | .files() | |
1162 | .iter() | |
1163 | .filter(|source_file| source_file.cnum == LOCAL_CRATE) | |
1164 | .map(|source_file| source_file.name_hash) | |
1165 | .collect(); | |
1166 | ||
1167 | source_file_names.sort_unstable(); | |
1168 | ||
49aad941 FG |
1169 | // We have to take care of debugger visualizers explicitly. The HIR (and |
1170 | // thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but | |
1171 | // these attributes only store the file path to the visualizer file, not | |
1172 | // their content. Yet that content is exported into crate metadata, so any | |
1173 | // changes to it need to be reflected in the crate hash. | |
1174 | let debugger_visualizers: Vec<_> = tcx | |
1175 | .debugger_visualizers(LOCAL_CRATE) | |
1176 | .iter() | |
1177 | // We ignore the path to the visualizer file since it's not going to be | |
1178 | // encoded in crate metadata and we already hash the full contents of | |
1179 | // the file. | |
1180 | .map(DebuggerVisualizerFile::path_erased) | |
1181 | .collect(); | |
1182 | ||
064997fb FG |
1183 | let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| { |
1184 | let mut stable_hasher = StableHasher::new(); | |
1185 | hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); | |
1186 | upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); | |
1187 | source_file_names.hash_stable(&mut hcx, &mut stable_hasher); | |
49aad941 | 1188 | debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); |
9c376795 | 1189 | if tcx.sess.opts.incremental_relative_spans() { |
064997fb FG |
1190 | let definitions = tcx.definitions_untracked(); |
1191 | let mut owner_spans: Vec<_> = krate | |
1192 | .owners | |
1193 | .iter_enumerated() | |
1194 | .filter_map(|(def_id, info)| { | |
1195 | let _ = info.as_owner()?; | |
1196 | let def_path_hash = definitions.def_path_hash(def_id); | |
9c376795 | 1197 | let span = tcx.source_span(def_id); |
064997fb FG |
1198 | debug_assert_eq!(span.parent(), None); |
1199 | Some((def_path_hash, span)) | |
1200 | }) | |
1201 | .collect(); | |
1202 | owner_spans.sort_unstable_by_key(|bn| bn.0); | |
1203 | owner_spans.hash_stable(&mut hcx, &mut stable_hasher); | |
1204 | } | |
1205 | tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); | |
1206 | tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); | |
1207 | // Hash visibility information since it does not appear in HIR. | |
1208 | resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher); | |
1209 | resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher); | |
1210 | stable_hasher.finish() | |
1211 | }); | |
17df50a5 | 1212 | |
49aad941 | 1213 | Svh::new(crate_hash) |
17df50a5 | 1214 | } |
1a4d82fc | 1215 | |
136023e0 XL |
1216 | fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { |
1217 | let mut upstream_crates: Vec<_> = tcx | |
1218 | .crates(()) | |
17df50a5 XL |
1219 | .iter() |
1220 | .map(|&cnum| { | |
923072b8 | 1221 | let stable_crate_id = tcx.stable_crate_id(cnum); |
136023e0 XL |
1222 | let hash = tcx.crate_hash(cnum); |
1223 | (stable_crate_id, hash) | |
17df50a5 XL |
1224 | }) |
1225 | .collect(); | |
136023e0 | 1226 | upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id); |
17df50a5 | 1227 | upstream_crates |
1a4d82fc JJ |
1228 | } |
1229 | ||
5099ac24 | 1230 | fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { |
49aad941 | 1231 | let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id); |
54a0048b | 1232 | |
ba9703b0 | 1233 | let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default(); |
9ffffee4 | 1234 | let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str()); |
ba9703b0 | 1235 | |
dc9dc135 | 1236 | match map.find(id) { |
b7449926 | 1237 | Some(Node::Item(item)) => { |
e74abb32 | 1238 | let item_str = match item.kind { |
8faf50e0 XL |
1239 | ItemKind::ExternCrate(..) => "extern crate", |
1240 | ItemKind::Use(..) => "use", | |
1241 | ItemKind::Static(..) => "static", | |
1242 | ItemKind::Const(..) => "const", | |
1243 | ItemKind::Fn(..) => "fn", | |
94222f64 | 1244 | ItemKind::Macro(..) => "macro", |
8faf50e0 | 1245 | ItemKind::Mod(..) => "mod", |
fc512014 | 1246 | ItemKind::ForeignMod { .. } => "foreign mod", |
8faf50e0 | 1247 | ItemKind::GlobalAsm(..) => "global asm", |
416331ca | 1248 | ItemKind::TyAlias(..) => "ty", |
f2b60f7d FG |
1249 | ItemKind::OpaqueTy(ref opaque) => { |
1250 | if opaque.in_trait { | |
1251 | "opaque type in trait" | |
1252 | } else { | |
1253 | "opaque type" | |
1254 | } | |
1255 | } | |
8faf50e0 XL |
1256 | ItemKind::Enum(..) => "enum", |
1257 | ItemKind::Struct(..) => "struct", | |
1258 | ItemKind::Union(..) => "union", | |
1259 | ItemKind::Trait(..) => "trait", | |
1260 | ItemKind::TraitAlias(..) => "trait alias", | |
dfeec247 | 1261 | ItemKind::Impl { .. } => "impl", |
1a4d82fc | 1262 | }; |
9ffffee4 | 1263 | format!("{id} ({item_str} {})", path_str(item.owner_id.def_id)) |
487cf647 FG |
1264 | } |
1265 | Some(Node::ForeignItem(item)) => { | |
9ffffee4 | 1266 | format!("{id} (foreign item {})", path_str(item.owner_id.def_id)) |
487cf647 FG |
1267 | } |
1268 | Some(Node::ImplItem(ii)) => { | |
1269 | let kind = match ii.kind { | |
1270 | ImplItemKind::Const(..) => "assoc const", | |
1271 | ImplItemKind::Fn(..) => "method", | |
1272 | ImplItemKind::Type(_) => "assoc type", | |
1273 | }; | |
9ffffee4 | 1274 | format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id)) |
1a4d82fc | 1275 | } |
b7449926 | 1276 | Some(Node::TraitItem(ti)) => { |
e74abb32 | 1277 | let kind = match ti.kind { |
32a655c1 | 1278 | TraitItemKind::Const(..) => "assoc constant", |
ba9703b0 | 1279 | TraitItemKind::Fn(..) => "trait method", |
32a655c1 | 1280 | TraitItemKind::Type(..) => "assoc type", |
c34b1796 AL |
1281 | }; |
1282 | ||
9ffffee4 | 1283 | format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id)) |
c34b1796 | 1284 | } |
b7449926 | 1285 | Some(Node::Variant(ref variant)) => { |
9ffffee4 | 1286 | format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id)) |
1a4d82fc | 1287 | } |
b7449926 | 1288 | Some(Node::Field(ref field)) => { |
9ffffee4 | 1289 | format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) |
1a4d82fc | 1290 | } |
ba9703b0 XL |
1291 | Some(Node::AnonConst(_)) => node_str("const"), |
1292 | Some(Node::Expr(_)) => node_str("expr"), | |
f2b60f7d | 1293 | Some(Node::ExprField(_)) => node_str("expr field"), |
ba9703b0 XL |
1294 | Some(Node::Stmt(_)) => node_str("stmt"), |
1295 | Some(Node::PathSegment(_)) => node_str("path segment"), | |
1296 | Some(Node::Ty(_)) => node_str("type"), | |
923072b8 | 1297 | Some(Node::TypeBinding(_)) => node_str("type binding"), |
ba9703b0 | 1298 | Some(Node::TraitRef(_)) => node_str("trait ref"), |
ba9703b0 | 1299 | Some(Node::Pat(_)) => node_str("pat"), |
f2b60f7d | 1300 | Some(Node::PatField(_)) => node_str("pattern field"), |
ba9703b0 XL |
1301 | Some(Node::Param(_)) => node_str("param"), |
1302 | Some(Node::Arm(_)) => node_str("arm"), | |
1303 | Some(Node::Block(_)) => node_str("block"), | |
94222f64 | 1304 | Some(Node::Infer(_)) => node_str("infer"), |
ba9703b0 | 1305 | Some(Node::Local(_)) => node_str("local"), |
487cf647 | 1306 | Some(Node::Ctor(ctor)) => format!( |
9ffffee4 | 1307 | "{id} (ctor {})", |
487cf647 | 1308 | ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)), |
487cf647 | 1309 | ), |
ba9703b0 | 1310 | Some(Node::Lifetime(_)) => node_str("lifetime"), |
487cf647 | 1311 | Some(Node::GenericParam(ref param)) => { |
9ffffee4 | 1312 | format!("{id} (generic_param {})", path_str(param.def_id)) |
487cf647 | 1313 | } |
9ffffee4 FG |
1314 | Some(Node::Crate(..)) => String::from("(root_crate)"), |
1315 | None => format!("{id} (unknown node)"), | |
1a4d82fc JJ |
1316 | } |
1317 | } | |
c295e0f8 XL |
1318 | |
1319 | pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems { | |
064997fb | 1320 | let mut collector = ItemCollector::new(tcx, false); |
c295e0f8 XL |
1321 | |
1322 | let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id); | |
1323 | collector.visit_mod(hir_mod, span, hir_id); | |
1324 | ||
064997fb FG |
1325 | let ItemCollector { |
1326 | submodules, | |
1327 | items, | |
1328 | trait_items, | |
1329 | impl_items, | |
1330 | foreign_items, | |
1331 | body_owners, | |
1332 | .. | |
1333 | } = collector; | |
c295e0f8 XL |
1334 | return ModuleItems { |
1335 | submodules: submodules.into_boxed_slice(), | |
1336 | items: items.into_boxed_slice(), | |
1337 | trait_items: trait_items.into_boxed_slice(), | |
1338 | impl_items: impl_items.into_boxed_slice(), | |
1339 | foreign_items: foreign_items.into_boxed_slice(), | |
064997fb | 1340 | body_owners: body_owners.into_boxed_slice(), |
c295e0f8 | 1341 | }; |
c295e0f8 | 1342 | } |
04454e1e FG |
1343 | |
1344 | pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { | |
064997fb | 1345 | let mut collector = ItemCollector::new(tcx, true); |
04454e1e | 1346 | |
064997fb FG |
1347 | // A "crate collector" and "module collector" start at a |
1348 | // module item (the former starts at the crate root) but only | |
1349 | // the former needs to collect it. ItemCollector does not do this for us. | |
2b03887a | 1350 | collector.submodules.push(CRATE_OWNER_ID); |
04454e1e FG |
1351 | tcx.hir().walk_toplevel_module(&mut collector); |
1352 | ||
064997fb FG |
1353 | let ItemCollector { |
1354 | submodules, | |
1355 | items, | |
1356 | trait_items, | |
1357 | impl_items, | |
1358 | foreign_items, | |
1359 | body_owners, | |
1360 | .. | |
1361 | } = collector; | |
04454e1e FG |
1362 | |
1363 | return ModuleItems { | |
1364 | submodules: submodules.into_boxed_slice(), | |
1365 | items: items.into_boxed_slice(), | |
1366 | trait_items: trait_items.into_boxed_slice(), | |
1367 | impl_items: impl_items.into_boxed_slice(), | |
1368 | foreign_items: foreign_items.into_boxed_slice(), | |
064997fb | 1369 | body_owners: body_owners.into_boxed_slice(), |
04454e1e | 1370 | }; |
064997fb | 1371 | } |
04454e1e | 1372 | |
064997fb FG |
1373 | struct ItemCollector<'tcx> { |
1374 | // When true, it collects all items in the create, | |
1375 | // otherwise it collects items in some module. | |
1376 | crate_collector: bool, | |
1377 | tcx: TyCtxt<'tcx>, | |
2b03887a | 1378 | submodules: Vec<OwnerId>, |
064997fb FG |
1379 | items: Vec<ItemId>, |
1380 | trait_items: Vec<TraitItemId>, | |
1381 | impl_items: Vec<ImplItemId>, | |
1382 | foreign_items: Vec<ForeignItemId>, | |
1383 | body_owners: Vec<LocalDefId>, | |
1384 | } | |
1385 | ||
1386 | impl<'tcx> ItemCollector<'tcx> { | |
1387 | fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> { | |
1388 | ItemCollector { | |
1389 | crate_collector, | |
1390 | tcx, | |
1391 | submodules: Vec::default(), | |
1392 | items: Vec::default(), | |
1393 | trait_items: Vec::default(), | |
1394 | impl_items: Vec::default(), | |
1395 | foreign_items: Vec::default(), | |
1396 | body_owners: Vec::default(), | |
1397 | } | |
04454e1e | 1398 | } |
064997fb FG |
1399 | } |
1400 | ||
1401 | impl<'hir> Visitor<'hir> for ItemCollector<'hir> { | |
1402 | type NestedFilter = nested_filter::All; | |
04454e1e | 1403 | |
064997fb FG |
1404 | fn nested_visit_map(&mut self) -> Self::Map { |
1405 | self.tcx.hir() | |
1406 | } | |
04454e1e | 1407 | |
064997fb FG |
1408 | fn visit_item(&mut self, item: &'hir Item<'hir>) { |
1409 | if associated_body(Node::Item(item)).is_some() { | |
2b03887a | 1410 | self.body_owners.push(item.owner_id.def_id); |
04454e1e FG |
1411 | } |
1412 | ||
064997fb FG |
1413 | self.items.push(item.item_id()); |
1414 | ||
1415 | // Items that are modules are handled here instead of in visit_mod. | |
1416 | if let ItemKind::Mod(module) = &item.kind { | |
2b03887a | 1417 | self.submodules.push(item.owner_id); |
064997fb FG |
1418 | // A module collector does not recurse inside nested modules. |
1419 | if self.crate_collector { | |
1420 | intravisit::walk_mod(self, module, item.hir_id()); | |
1421 | } | |
1422 | } else { | |
04454e1e FG |
1423 | intravisit::walk_item(self, item) |
1424 | } | |
064997fb | 1425 | } |
04454e1e | 1426 | |
064997fb FG |
1427 | fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { |
1428 | self.foreign_items.push(item.foreign_item_id()); | |
1429 | intravisit::walk_foreign_item(self, item) | |
1430 | } | |
04454e1e | 1431 | |
064997fb | 1432 | fn visit_anon_const(&mut self, c: &'hir AnonConst) { |
487cf647 | 1433 | self.body_owners.push(c.def_id); |
064997fb FG |
1434 | intravisit::walk_anon_const(self, c) |
1435 | } | |
1436 | ||
1437 | fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { | |
487cf647 FG |
1438 | if let ExprKind::Closure(closure) = ex.kind { |
1439 | self.body_owners.push(closure.def_id); | |
04454e1e | 1440 | } |
064997fb FG |
1441 | intravisit::walk_expr(self, ex) |
1442 | } | |
04454e1e | 1443 | |
064997fb FG |
1444 | fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { |
1445 | if associated_body(Node::TraitItem(item)).is_some() { | |
2b03887a | 1446 | self.body_owners.push(item.owner_id.def_id); |
04454e1e FG |
1447 | } |
1448 | ||
064997fb FG |
1449 | self.trait_items.push(item.trait_item_id()); |
1450 | intravisit::walk_trait_item(self, item) | |
1451 | } | |
1452 | ||
1453 | fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { | |
1454 | if associated_body(Node::ImplItem(item)).is_some() { | |
2b03887a | 1455 | self.body_owners.push(item.owner_id.def_id); |
04454e1e | 1456 | } |
064997fb FG |
1457 | |
1458 | self.impl_items.push(item.impl_item_id()); | |
1459 | intravisit::walk_impl_item(self, item) | |
04454e1e FG |
1460 | } |
1461 | } |