rust/compiler/rustc_middle/src/hir/map/mod.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1489 lines
56 KiB
Rust
Raw Normal View History

use crate::hir::{ModuleItems, Owner};
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
2023-03-13 22:22:59 +00:00
use crate::query::LocalCrate;
use crate::ty::TyCtxt;
2020-04-27 23:26:11 +05:30
use rustc_ast as ast;
2021-02-28 18:58:50 +01:00
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2018-08-03 12:22:22 -06:00
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync};
use rustc_hir::def::{DefKind, Res};
2023-04-26 20:53:51 +02:00
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
2021-08-26 18:42:08 +02:00
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::*;
use rustc_index::Idx;
use rustc_middle::hir::nested_filter;
use rustc_span::def_id::StableCrateId;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
2015-07-31 00:04:06 -07:00
#[inline]
pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> {
match node {
2020-03-24 06:17:44 +01:00
Node::Item(Item {
owner_id,
2023-05-04 16:40:57 +02:00
kind: ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
2020-03-24 06:17:44 +01:00
..
})
| Node::TraitItem(TraitItem {
owner_id,
2020-03-24 06:17:44 +01:00
kind:
TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)),
..
})
| Node::ImplItem(ImplItem {
owner_id,
2020-03-24 06:17:44 +01:00
kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
..
}) => Some((owner_id.def_id, *body)),
Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => {
Some((*def_id, *body))
}
Node::AnonConst(constant) => Some((constant.def_id, constant.body)),
Node::ConstBlock(constant) => Some((constant.def_id, constant.body)),
_ => None,
}
}
2022-12-20 22:10:40 +01:00
fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool {
match associated_body(node) {
Some((_, b)) => b.hir_id == hir_id,
None => false,
}
}
2020-02-09 15:32:00 +01:00
#[derive(Copy, Clone)]
2017-01-26 03:21:50 +02:00
pub struct Map<'hir> {
2020-02-07 13:13:35 +01:00
pub(super) tcx: TyCtxt<'hir>,
}
/// An iterator that walks up the ancestor tree of a given `HirId`.
/// Constructed using `tcx.hir().parent_iter(hir_id)`.
2021-09-18 15:48:07 -05:00
pub struct ParentHirIterator<'hir> {
current_id: HirId,
2021-09-18 15:48:07 -05:00
map: Map<'hir>,
}
2021-09-18 15:48:07 -05:00
impl<'hir> Iterator for ParentHirIterator<'hir> {
type Item = HirId;
fn next(&mut self) -> Option<Self::Item> {
if self.current_id == CRATE_HIR_ID {
return None;
}
2023-04-09 22:35:49 +02:00
// There are nodes that do not have entries, so we need to skip them.
let parent_id = self.map.parent_id(self.current_id);
2023-04-09 22:35:49 +02:00
if parent_id == self.current_id {
self.current_id = CRATE_HIR_ID;
return None;
}
2023-04-09 22:35:49 +02:00
self.current_id = parent_id;
return Some(parent_id);
}
}
/// An iterator that walks up the ancestor tree of a given `HirId`.
/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
2021-09-18 15:48:07 -05:00
pub struct ParentOwnerIterator<'hir> {
current_id: HirId,
2021-09-18 15:48:07 -05:00
map: Map<'hir>,
}
2021-09-18 15:48:07 -05:00
impl<'hir> Iterator for ParentOwnerIterator<'hir> {
type Item = (OwnerId, OwnerNode<'hir>);
fn next(&mut self) -> Option<Self::Item> {
if self.current_id.local_id.index() != 0 {
self.current_id.local_id = ItemLocalId::new(0);
if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
return Some((self.current_id.owner, node.node));
}
}
if self.current_id == CRATE_HIR_ID {
return None;
}
loop {
// There are nodes that do not have entries, so we need to skip them.
let parent_id = self.map.def_key(self.current_id.owner.def_id).parent;
let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| {
let def_id = LocalDefId { local_def_index };
self.map.local_def_id_to_hir_id(def_id).owner
});
self.current_id = HirId::make_owner(parent_id.def_id);
// If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
return Some((self.current_id.owner, node.node));
}
}
}
}
2017-01-26 03:21:50 +02:00
impl<'hir> Map<'hir> {
2022-07-30 22:44:49 +02:00
#[inline]
pub fn krate(self) -> &'hir Crate<'hir> {
2021-05-11 11:42:01 +02:00
self.tcx.hir_crate(())
2020-02-06 13:41:37 +01:00
}
2022-07-30 22:44:49 +02:00
#[inline]
pub fn root_module(self) -> &'hir Mod<'hir> {
match self.tcx.hir_owner(CRATE_OWNER_ID).map(|o| o.node) {
Some(OwnerNode::Crate(item)) => item,
_ => bug!(),
}
}
2022-07-30 22:44:49 +02:00
#[inline]
pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
self.tcx.hir_crate_items(()).items.iter().copied()
}
2022-07-30 22:44:49 +02:00
#[inline]
2023-04-26 20:53:51 +02:00
pub fn module_items(self, module: LocalModDefId) -> impl Iterator<Item = ItemId> + 'hir {
self.tcx.hir_module_items(module).items()
}
pub fn def_key(self, def_id: LocalDefId) -> DefKey {
// Accessing the DefKey is ok, since it is part of DefPathHash.
self.tcx.definitions_untracked().def_key(def_id)
}
pub fn def_path(self, def_id: LocalDefId) -> DefPath {
// Accessing the DefPath is ok, since it is part of DefPathHash.
self.tcx.definitions_untracked().def_path(def_id)
}
#[inline]
pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
// Accessing the DefPathHash is ok, it is incr. comp. stable.
self.tcx.definitions_untracked().def_path_hash(def_id)
}
#[inline]
2023-04-26 20:53:51 +02:00
pub fn local_def_id_to_hir_id(self, def_id: impl Into<LocalDefId>) -> HirId {
self.tcx.local_def_id_to_hir_id(def_id.into())
}
2022-07-06 17:02:58 +08:00
/// Do not call this function directly. The query should be called.
pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
let hir_id = self.local_def_id_to_hir_id(local_def_id);
let node = match self.find(hir_id) {
Some(node) => node,
None => match self.def_key(local_def_id).disambiguated_data.data {
// FIXME: Some anonymous constants do not have corresponding HIR nodes,
// so many local queries will panic on their def ids. `None` is currently
// returned here instead of `DefKind::{Anon,Inline}Const` to avoid such panics.
// Ideally all def ids should have `DefKind`s, we need to create the missing
// HIR nodes or feed relevant query results to achieve that.
DefPathData::AnonConst => return None,
_ => bug!("no HIR node for def id {local_def_id:?}"),
},
};
let def_kind = match node {
2018-08-25 15:56:16 +01:00
Node::Item(item) => match item.kind {
ItemKind::Static(_, mt, _) => DefKind::Static(mt),
ItemKind::Const(..) => DefKind::Const,
ItemKind::Fn(..) => DefKind::Fn,
ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
ItemKind::Mod(..) => DefKind::Mod,
ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
2023-09-26 02:15:32 +00:00
ItemKind::TyAlias(..) => DefKind::TyAlias,
ItemKind::Enum(..) => DefKind::Enum,
ItemKind::Struct(..) => DefKind::Struct,
ItemKind::Union(..) => DefKind::Union,
ItemKind::Trait(..) => DefKind::Trait,
ItemKind::TraitAlias(..) => DefKind::TraitAlias,
ItemKind::ExternCrate(_) => DefKind::ExternCrate,
ItemKind::Use(..) => DefKind::Use,
2020-11-11 22:40:09 +01:00
ItemKind::ForeignMod { .. } => DefKind::ForeignMod,
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
2023-02-12 18:26:47 +00:00
ItemKind::Impl(impl_) => DefKind::Impl { of_trait: impl_.of_trait.is_some() },
},
2018-08-25 15:56:16 +01:00
Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Fn(..) => DefKind::Fn,
ForeignItemKind::Static(_, mt) => DefKind::Static(mt),
ForeignItemKind::Type => DefKind::ForeignTy,
},
2018-08-25 15:56:16 +01:00
Node::TraitItem(item) => match item.kind {
TraitItemKind::Const(..) => DefKind::AssocConst,
2020-03-03 12:46:22 -06:00
TraitItemKind::Fn(..) => DefKind::AssocFn,
TraitItemKind::Type(..) => DefKind::AssocTy,
},
2018-08-25 15:56:16 +01:00
Node::ImplItem(item) => match item.kind {
ImplItemKind::Const(..) => DefKind::AssocConst,
2020-03-05 09:57:34 -06:00
ImplItemKind::Fn(..) => DefKind::AssocFn,
ImplItemKind::Type(..) => DefKind::AssocTy,
},
Node::Variant(_) => DefKind::Variant,
Node::Ctor(variant_data) => {
2023-01-03 17:30:35 +00:00
let ctor_of = match self.find_parent(hir_id) {
Some(Node::Item(..)) => def::CtorOf::Struct,
Some(Node::Variant(..)) => def::CtorOf::Variant,
_ => unreachable!(),
};
match variant_data.ctor_kind() {
Some(kind) => DefKind::Ctor(ctor_of, kind),
None => bug!("constructor node without a constructor"),
}
}
Node::AnonConst(_) => DefKind::AnonConst,
Node::ConstBlock(_) => DefKind::InlineConst,
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure,
ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator,
_ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
},
Node::GenericParam(param) => match param.kind {
GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
GenericParamKind::Type { .. } => DefKind::TyParam,
GenericParamKind::Const { .. } => DefKind::ConstParam,
},
2021-01-18 19:15:53 +01:00
Node::Crate(_) => DefKind::Mod,
Node::Stmt(_)
| Node::PathSegment(_)
2018-08-25 15:56:16 +01:00
| Node::Ty(_)
| Node::TypeBinding(_)
2021-04-26 18:19:23 +00:00
| Node::Infer(_)
2018-08-25 15:56:16 +01:00
| Node::TraitRef(_)
| Node::Pat(_)
| Node::PatField(_)
| Node::ExprField(_)
| Node::Local(_)
| Node::Param(_)
2019-03-30 22:54:29 +00:00
| Node::Arm(_)
2018-08-25 15:56:16 +01:00
| Node::Lifetime(_)
| Node::Block(_) => span_bug!(
self.span(hir_id),
"unexpected node with def id {local_def_id:?}: {node:?}"
),
2021-01-16 14:35:16 +01:00
};
Some(def_kind)
}
/// Finds the id of the parent node to this one.
///
/// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
2020-03-10 13:44:53 -07:00
if id.local_id == ItemLocalId::from_u32(0) {
2021-03-06 11:25:41 +01:00
Some(self.tcx.hir_owner_parent(id.owner))
2020-02-07 16:43:36 +01:00
} else {
let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
let node = owner.nodes[id.local_id].as_ref()?;
let hir_id = HirId { owner: id.owner, local_id: node.parent };
// HIR indexing should have checked that.
debug_assert_ne!(id.local_id, node.parent);
Some(hir_id)
2020-02-07 16:43:36 +01:00
}
}
2022-10-12 14:16:31 +00:00
#[track_caller]
2023-01-03 07:31:04 +00:00
pub fn parent_id(self, hir_id: HirId) -> HirId {
self.opt_parent_id(hir_id)
.unwrap_or_else(|| bug!("No parent for node {}", self.node_to_string(hir_id)))
}
2023-01-03 17:30:35 +00:00
pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
self.get(self.parent_id(hir_id))
}
pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> {
self.find(self.opt_parent_id(hir_id)?)
}
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
pub fn find(self, id: HirId) -> Option<Node<'hir>> {
if id.local_id == ItemLocalId::from_u32(0) {
let owner = self.tcx.hir_owner(id.owner)?;
2021-03-27 13:21:26 +01:00
Some(owner.node.into())
} else {
let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
let node = owner.nodes[id.local_id].as_ref()?;
Some(node.node)
}
}
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
#[inline]
pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> {
self.find(self.tcx.opt_local_def_id_to_hir_id(id)?)
}
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
2022-10-12 14:16:31 +00:00
#[track_caller]
pub fn get(self, id: HirId) -> Node<'hir> {
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
}
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
#[inline]
2022-10-12 14:16:31 +00:00
#[track_caller]
pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> {
self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id))
}
pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
id.as_local().and_then(|id| self.find(self.tcx.opt_local_def_id_to_hir_id(id)?))
}
pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
let node = self.tcx.hir_owner(OwnerId { def_id: id })?;
node.node.generics()
2020-03-16 19:17:40 +01:00
}
pub fn owner(self, id: OwnerId) -> OwnerNode<'hir> {
self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node
}
pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item()
2020-01-07 15:51:38 +01:00
}
pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item()
}
pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item()
}
pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item()
2020-11-11 21:57:54 +01:00
}
pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
2021-10-21 23:08:57 +02:00
self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
}
2022-10-12 14:16:31 +00:00
#[track_caller]
pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
if let Some(node) = self.find(hir_id) {
node.fn_decl()
} else {
bug!("no node for hir_id `{}`", hir_id)
}
2019-02-04 11:09:32 +01:00
}
2022-10-12 14:16:31 +00:00
#[track_caller]
pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
if let Some(node) = self.find(hir_id) {
node.fn_sig()
2019-11-06 11:43:33 -08:00
} else {
bug!("no node for hir_id `{}`", hir_id)
2019-11-06 11:43:33 -08:00
}
}
2022-10-12 14:16:31 +00:00
#[track_caller]
pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
for (_, node) in self.parent_iter(hir_id) {
if let Some((def_id, _)) = associated_body(node) {
return def_id;
2020-05-20 14:57:16 +02:00
}
}
bug!("no `enclosing_body_owner` for hir_id `{}`", hir_id);
}
/// Returns the `HirId` that corresponds to the definition of
/// which this is the body of, i.e., a `fn`, `const` or `static`
/// item (possibly associated), a closure, or a `hir::AnonConst`.
pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
2023-01-03 07:31:04 +00:00
let parent = self.parent_id(hir_id);
assert!(self.find(parent).is_some_and(|n| is_body_owner(n, hir_id)), "{hir_id:?}");
2019-06-14 12:28:47 +02:00
parent
}
pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
let parent = self.parent_id(hir_id);
associated_body(self.get(parent)).unwrap().0
}
/// Given a `LocalDefId`, returns the `BodyId` associated with it,
/// if the node is a body owner, otherwise returns `None`.
pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
let node = self.find_by_def_id(id)?;
let (_, body_id) = associated_body(node)?;
Some(body_id)
2017-04-04 12:06:35 -04:00
}
/// Given a body owner's id, returns the `BodyId` associated with it.
2022-10-12 14:16:31 +00:00
#[track_caller]
pub fn body_owned_by(self, id: LocalDefId) -> BodyId {
self.maybe_body_owned_by(id).unwrap_or_else(|| {
let hir_id = self.local_def_id_to_hir_id(id);
span_bug!(
self.span(hir_id),
"body_owned_by: {} has no associated body",
self.node_to_string(hir_id)
);
})
}
pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
_ => Ident::empty(),
})
}
2020-05-07 10:22:35 -07:00
/// Returns the `BodyOwnerKind` of this `LocalDefId`.
///
/// Panics if `LocalDefId` does not have an associated body.
pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
match self.tcx.def_kind(def_id) {
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
BodyOwnerKind::Const { inline: false }
}
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
DefKind::Static(mt) => BodyOwnerKind::Static(mt),
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
}
}
2020-05-07 10:22:35 -07:00
/// Returns the `ConstContext` of the body associated with this `LocalDefId`.
///
/// Panics if `LocalDefId` does not have an associated body.
///
/// This should only be used for determining the context of a body, a return
/// value of `Some` does not always suggest that the owner of the body is `const`,
/// just that it has to be checked as if it were.
pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
let ccx = match self.body_owner_kind(def_id) {
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
2020-05-07 10:22:35 -07:00
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
2022-12-22 18:15:15 +00:00
BodyOwnerKind::Fn | BodyOwnerKind::Closure
if self.tcx.is_const_fn_raw(def_id.to_def_id()) =>
{
ConstContext::ConstFn
}
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {
ConstContext::ConstFn
}
2020-05-07 10:22:35 -07:00
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
};
Some(ccx)
}
2021-09-12 11:33:16 +02:00
/// Returns an iterator of the `DefId`s for all body-owners in this
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
2022-07-30 22:44:49 +02:00
#[inline]
2021-09-12 11:33:16 +02:00
pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
self.tcx.hir_crate_items(()).body_owners.iter().copied()
2021-09-12 11:33:16 +02:00
}
2022-07-30 22:44:49 +02:00
#[inline]
pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) {
par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id));
2021-09-12 11:33:16 +02:00
}
pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
let def_kind = self.tcx.def_kind(def_id);
match def_kind {
DefKind::Trait | DefKind::TraitAlias => def_id,
DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
self.tcx.local_parent(def_id)
}
_ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
}
}
pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol {
let def_kind = self.tcx.def_kind(def_id);
match def_kind {
DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
self.tcx.item_name(def_id.to_def_id())
}
_ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
}
}
pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] {
2021-05-11 11:42:01 +02:00
self.tcx.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..])
}
2019-02-08 14:53:55 +01:00
/// Gets the attributes on the crate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
pub fn krate_attrs(self) -> &'hir [ast::Attribute] {
self.attrs(CRATE_HIR_ID)
}
pub fn rustc_coherence_is_core(self) -> bool {
self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
}
2023-04-26 20:53:51 +02:00
pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) {
let hir_id = HirId::make_owner(module.to_local_def_id());
match self.tcx.hir_owner(hir_id.owner).map(|o| o.node) {
Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
(m, span, hir_id)
}
Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id),
node => panic!("not a module: {node:?}"),
}
}
/// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
2021-09-02 19:22:24 +02:00
pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
2023-04-26 20:53:51 +02:00
let (top_mod, span, hir_id) = self.get_module(LocalModDefId::CRATE_DEF_ID);
2021-08-26 18:42:08 +02:00
visitor.visit_mod(top_mod, span, hir_id);
}
/// Walks the attributes in a crate.
pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
let krate = self.krate();
for info in krate.owners.iter() {
if let MaybeOwner::Owner(info) = info {
for attrs in info.attrs.map.values() {
2021-07-16 14:42:26 +02:00
for a in *attrs {
visitor.visit_attribute(a)
2021-07-16 14:42:26 +02:00
}
}
2021-08-26 18:42:08 +02:00
}
}
}
/// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
/// need to process every item-like, and don't care about visiting nested items in a particular
/// order then this method is the best choice. If you do care about this nesting, you should
/// use the `tcx.hir().walk_toplevel_module`.
///
/// Note that this function will access HIR for all the item-likes in the crate. If you only
/// need to access some of them, it is usually better to manually loop on the iterators
/// provided by `tcx.hir_crate_items(())`.
///
/// Please see the notes in `intravisit.rs` for more information.
pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V)
where
V: Visitor<'hir>,
{
let krate = self.tcx.hir_crate_items(());
for id in krate.items() {
visitor.visit_item(self.item(id));
}
for id in krate.trait_items() {
visitor.visit_trait_item(self.trait_item(id));
}
for id in krate.impl_items() {
visitor.visit_impl_item(self.impl_item(id));
}
for id in krate.foreign_items() {
visitor.visit_foreign_item(self.foreign_item(id));
}
}
/// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to
/// item-likes in a single module.
2023-04-26 20:53:51 +02:00
pub fn visit_item_likes_in_module<V>(self, module: LocalModDefId, visitor: &mut V)
2018-06-06 22:13:52 +02:00
where
V: Visitor<'hir>,
2018-06-06 22:13:52 +02:00
{
2020-06-27 13:09:54 +02:00
let module = self.tcx.hir_module_items(module);
2018-06-06 22:13:52 +02:00
for id in module.items() {
visitor.visit_item(self.item(id));
2018-06-06 22:13:52 +02:00
}
for id in module.trait_items() {
visitor.visit_trait_item(self.trait_item(id));
2018-06-06 22:13:52 +02:00
}
for id in module.impl_items() {
visitor.visit_impl_item(self.impl_item(id));
2018-06-06 22:13:52 +02:00
}
2020-11-11 21:57:54 +01:00
for id in module.foreign_items() {
visitor.visit_foreign_item(self.foreign_item(id));
2020-11-11 21:57:54 +01:00
}
2018-06-06 22:13:52 +02:00
}
2023-04-26 20:53:51 +02:00
pub fn for_each_module(self, mut f: impl FnMut(LocalModDefId)) {
let crate_items = self.tcx.hir_crate_items(());
for module in crate_items.submodules.iter() {
2023-04-26 20:53:51 +02:00
f(LocalModDefId::new_unchecked(module.def_id))
2021-07-18 18:12:17 +02:00
}
}
#[inline]
2023-04-26 20:53:51 +02:00
pub fn par_for_each_module(self, f: impl Fn(LocalModDefId) + DynSend + DynSync) {
let crate_items = self.tcx.hir_crate_items(());
2023-04-26 20:53:51 +02:00
par_for_each_in(&crate_items.submodules[..], |module| {
f(LocalModDefId::new_unchecked(module.def_id))
})
2021-07-18 18:12:17 +02:00
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
2023-01-03 07:31:04 +00:00
/// until the crate root is reached. Prefer this over your own loop using `parent_id`.
2022-07-30 22:44:49 +02:00
#[inline]
pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir {
ParentHirIterator { current_id, map: self }
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
2023-01-03 07:31:04 +00:00
/// until the crate root is reached. Prefer this over your own loop using `parent_id`.
#[inline]
pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> {
self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.find(id)?)))
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
2023-01-03 07:31:04 +00:00
/// until the crate root is reached. Prefer this over your own loop using `parent_id`.
2022-07-30 22:44:49 +02:00
#[inline]
2021-09-18 15:48:07 -05:00
pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
ParentOwnerIterator { current_id, map: self }
}
/// Checks if the node is left-hand side of an assignment.
pub fn is_lhs(self, id: HirId) -> bool {
2023-01-03 17:30:35 +00:00
match self.find_parent(id) {
Some(Node::Expr(expr)) => match expr.kind {
ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
_ => false,
},
_ => false,
}
}
2019-08-13 11:24:08 -07:00
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
/// Used exclusively for diagnostics, to avoid suggestion function calls.
pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
}
/// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
/// `while` or `loop` before reaching it, as block tail returns are not
/// available in them.
///
/// ```
/// fn foo(x: usize) -> bool {
/// if x == 1 {
/// true // If `get_return_block` gets passed the `id` corresponding
/// } else { // to this, it will return `foo`'s `HirId`.
/// false
/// }
/// }
/// ```
///
2022-04-15 15:04:34 -07:00
/// ```compile_fail,E0308
/// fn foo(x: usize) -> bool {
/// loop {
/// true // If `get_return_block` gets passed the `id` corresponding
/// } // to this, it will return `None`.
/// false
/// }
/// ```
pub fn get_return_block(self, id: HirId) -> Option<HirId> {
let mut iter = self.parent_iter(id).peekable();
let mut ignore_tail = false;
if let Some(Node::Expr(Expr { kind: ExprKind::Ret(_), .. })) = self.find(id) {
// When dealing with `return` statements, we don't care about climbing only tail
// expressions.
ignore_tail = true;
}
let mut prev_hir_id = None;
while let Some((hir_id, node)) = iter.next() {
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
match next_node {
Node::Block(Block { expr: None, .. }) => return None,
2020-03-24 06:17:44 +01:00
// The current node is not the tail expression of its parent.
Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
_ => {}
}
}
match node {
2018-08-25 15:56:16 +01:00
Node::Item(_)
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. })
| Node::ImplItem(_)
// The input node `id` must be enclosed in the method's body as opposed
// to some other place such as its return type (fixes #114918).
// We verify that indirectly by checking that the previous node is the
// current node's body
if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
return Some(hir_id)
}
2020-03-24 06:17:44 +01:00
// Ignore `return`s on the first iteration
Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
| Node::Local(_) => {
return None;
}
_ => {}
}
prev_hir_id = Some(hir_id);
}
None
}
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
2015-07-01 08:58:48 +12:00
/// parent item is in this map. The "parent item" is the closest parent node
2018-06-13 09:11:23 +02:00
/// in the HIR which is recorded by the map and is an item, either an item
2015-07-01 08:58:48 +12:00
/// in a module, trait, or impl.
pub fn get_parent_item(self, hir_id: HirId) -> OwnerId {
if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
def_id
2021-03-27 13:56:22 +01:00
} else {
CRATE_OWNER_ID
2015-07-01 08:58:48 +12:00
}
2015-06-16 21:56:33 +12:00
}
2021-01-01 15:38:11 -03:00
/// When on an if expression, a match arm tail expression or a match arm, give back
/// the enclosing `if` or `match` expression.
2019-09-27 18:35:34 -07:00
///
2021-01-01 15:38:11 -03:00
/// Used by error reporting when there's a type error in an if or match arm caused by the
2019-09-27 18:35:34 -07:00
/// expression needing to be unit.
pub fn get_if_cause(self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
for (_, node) in self.parent_iter(hir_id) {
match node {
2020-03-24 06:17:44 +01:00
Node::Item(_)
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::ImplItem(_)
| Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
2021-01-01 15:38:11 -03:00
Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
return Some(expr);
}
_ => {}
}
}
None
}
/// Returns the nearest enclosing scope. A scope is roughly an item or block.
pub fn get_enclosing_scope(self, hir_id: HirId) -> Option<HirId> {
for (hir_id, node) in self.parent_iter(hir_id) {
2020-03-24 06:17:44 +01:00
if let Node::Item(Item {
kind:
ItemKind::Fn(..)
2020-05-10 11:57:58 +01:00
| ItemKind::Const(..)
| ItemKind::Static(..)
| ItemKind::Mod(..)
| ItemKind::Enum(..)
| ItemKind::Struct(..)
| ItemKind::Union(..)
| ItemKind::Trait(..)
2020-03-24 06:17:44 +01:00
| ItemKind::Impl { .. },
..
})
| Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(..), .. })
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(..), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(..), .. })
| Node::Block(_) = node
{
return Some(hir_id);
}
}
None
}
2019-08-01 00:41:54 +01:00
/// Returns the defining scope for an opaque type definition.
pub fn get_defining_scope(self, id: HirId) -> HirId {
let mut scope = id;
loop {
scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
2021-01-10 14:38:14 +01:00
if scope == CRATE_HIR_ID || !matches!(self.get(scope), Node::Block(_)) {
return scope;
}
}
}
pub fn get_foreign_abi(self, hir_id: HirId) -> Abi {
let parent = self.get_parent_item(hir_id);
if let Some(node) = self.tcx.hir_owner(parent) {
2021-03-27 13:56:22 +01:00
if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
{
2020-11-11 22:40:09 +01:00
return *abi;
}
}
bug!(
"expected foreign mod or inlined parent, found {}",
self.node_to_string(HirId::make_owner(parent.def_id))
)
2019-02-04 11:09:32 +01:00
}
pub fn expect_owner(self, def_id: LocalDefId) -> OwnerNode<'hir> {
self.tcx
.hir_owner(OwnerId { def_id })
.unwrap_or_else(|| bug!("expected owner for {:?}", def_id))
.node
2022-06-12 00:47:21 +02:00
}
pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
match self.tcx.hir_owner(OwnerId { def_id: id }) {
Some(Owner { node: OwnerNode::Item(item), .. }) => item,
2021-10-20 22:38:10 +02:00
_ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
}
2019-02-03 09:14:31 +01:00
}
pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
match self.tcx.hir_owner(OwnerId { def_id: id }) {
Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
2021-10-20 22:38:10 +02:00
_ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
match self.tcx.hir_owner(OwnerId { def_id: id }) {
Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
2021-10-20 22:38:10 +02:00
_ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
pub fn get_fn_output(self, def_id: LocalDefId) -> Option<&'hir FnRetTy<'hir>> {
match self.tcx.hir_owner(OwnerId { def_id }) {
Some(Owner { node, .. }) => node.fn_decl().map(|fn_decl| &fn_decl.output),
_ => None,
}
}
pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> {
2019-06-24 09:58:49 +02:00
match self.find(id) {
2018-08-25 15:56:16 +01:00
Some(Node::Variant(variant)) => variant,
_ => bug!("expected variant, found {}", self.node_to_string(id)),
}
}
pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
2021-10-20 22:38:10 +02:00
match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
2021-10-20 22:38:10 +02:00
_ => {
bug!(
"expected foreign item, found {}",
self.node_to_string(HirId::make_owner(id.def_id))
)
2021-10-20 22:38:10 +02:00
}
}
}
pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
2019-06-24 09:58:49 +02:00
match self.find(id) {
Some(Node::Expr(expr)) => expr,
_ => bug!("expected expr, found {}", self.node_to_string(id)),
}
2019-02-04 11:09:32 +01:00
}
2022-04-19 21:25:26 +02:00
#[inline]
fn opt_ident(self, id: HirId) -> Option<Ident> {
match self.get(id) {
2022-06-28 13:15:30 -05:00
Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
// A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::opt_span`.
2023-01-03 17:30:35 +00:00
Node::Ctor(..) => match self.find_parent(id)? {
Node::Item(item) => Some(item.ident),
Node::Variant(variant) => Some(variant.ident),
_ => unreachable!(),
},
node => node.ident(),
2022-04-19 21:25:26 +02:00
}
}
2022-04-19 21:25:26 +02:00
#[inline]
pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> {
self.opt_ident(id).map(|ident| ident.span)
}
2022-10-25 17:59:18 +00:00
#[inline]
pub fn ident(self, id: HirId) -> Ident {
self.opt_ident(id).unwrap()
}
2022-04-19 21:25:26 +02:00
#[inline]
pub fn opt_name(self, id: HirId) -> Option<Symbol> {
2022-04-19 21:25:26 +02:00
self.opt_ident(id).map(|ident| ident.name)
2019-12-13 15:27:55 -08:00
}
pub fn name(self, id: HirId) -> Symbol {
self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id)))
}
/// Given a node ID, gets a list of attributes associated with the AST
/// corresponding to the node-ID.
pub fn attrs(self, id: HirId) -> &'hir [ast::Attribute] {
2021-01-24 17:14:17 +01:00
self.tcx.hir_attrs(id.owner).get(id.local_id)
}
Use smaller def span for functions Currently, the def span of a funtion encompasses the entire function signature and body. However, this is usually unnecessarily verbose - when we are pointing at an entire function in a diagnostic, we almost always want to point at the signature. The actual contents of the body tends to be irrelevant to the diagnostic we are emitting, and just takes up additional screen space. This commit changes the `def_span` of all function items (freestanding functions, `impl`-block methods, and `trait`-block methods) to be the span of the signature. For example, the function ```rust pub fn foo<T>(val: T) -> T { val } ``` now has a `def_span` corresponding to `pub fn foo<T>(val: T) -> T` (everything before the opening curly brace). Trait methods without a body have a `def_span` which includes the trailing semicolon. For example: ```rust trait Foo { fn bar(); }``` the function definition `Foo::bar` has a `def_span` of `fn bar();` This makes our diagnostic output much shorter, and emphasizes information that is relevant to whatever diagnostic we are reporting. We continue to use the full span (including the body) in a few of places: * MIR building uses the full span when building source scopes. * 'Outlives suggestions' use the full span to sort the diagnostics being emitted. * The `#[rustc_on_unimplemented(enclosing_scope="in this scope")]` attribute points the entire scope body. * The 'unconditional recursion' lint uses the full span to show additional context for the recursive call. All of these cases work only with local items, so we don't need to add anything extra to crate metadata.
2020-08-12 17:02:14 -04:00
/// Gets the span of the definition of the specified HIR node.
2022-02-13 16:27:59 +01:00
/// This is used by `tcx.def_span`.
pub fn span(self, hir_id: HirId) -> Span {
2020-12-23 10:32:00 +01:00
self.opt_span(hir_id)
.unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id))
}
pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
2022-02-13 16:27:59 +01:00
fn until_within(outer: Span, end: Span) -> Span {
if let Some(end) = end.find_ancestor_inside(outer) {
outer.with_hi(end.hi())
} else {
outer
}
}
fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) -> Span {
if ident.name != kw::Empty {
let mut span = until_within(item_span, ident.span);
if let Some(g) = generics
&& !g.span.is_dummy()
&& let Some(g_span) = g.span.find_ancestor_inside(item_span)
{
span = span.to(g_span);
}
span
} else {
item_span
}
}
let span = match self.find(hir_id)? {
2022-02-13 16:27:59 +01:00
// Function-like.
Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. })
| Node::TraitItem(TraitItem {
kind: TraitItemKind::Fn(sig, ..),
span: outer_span,
..
})
| Node::ImplItem(ImplItem {
kind: ImplItemKind::Fn(sig, ..), span: outer_span, ..
}) => {
// Ensure that the returned span has the item's SyntaxContext, and not the
// SyntaxContext of the visibility.
sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span)
}
// Impls, including their where clauses.
Node::Item(Item {
kind: ItemKind::Impl(Impl { generics, .. }),
span: outer_span,
..
}) => until_within(*outer_span, generics.where_clause_span),
2022-02-13 16:27:59 +01:00
// Constants and Statics.
Node::Item(Item {
kind: ItemKind::Const(ty, ..) | ItemKind::Static(ty, ..),
2022-02-13 16:27:59 +01:00
span: outer_span,
..
})
| Node::TraitItem(TraitItem {
kind: TraitItemKind::Const(ty, ..),
span: outer_span,
..
})
| Node::ImplItem(ImplItem {
kind: ImplItemKind::Const(ty, ..),
span: outer_span,
..
})
| Node::ForeignItem(ForeignItem {
kind: ForeignItemKind::Static(ty, ..),
span: outer_span,
..
}) => until_within(*outer_span, ty.span),
// With generics and bounds.
Node::Item(Item {
kind: ItemKind::Trait(_, _, generics, bounds, _),
span: outer_span,
..
})
| Node::TraitItem(TraitItem {
kind: TraitItemKind::Type(bounds, _),
generics,
span: outer_span,
..
}) => {
let end = if let Some(b) = bounds.last() { b.span() } else { generics.span };
until_within(*outer_span, end)
}
// Other cases.
2020-12-23 10:32:00 +01:00
Node::Item(item) => match &item.kind {
ItemKind::Use(path, _) => {
// Ensure that the returned span has the item's SyntaxContext, and not the
// SyntaxContext of the path.
path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span)
}
2022-02-13 16:27:59 +01:00
_ => named_span(item.span, item.ident, item.kind.generics()),
Use smaller def span for functions Currently, the def span of a funtion encompasses the entire function signature and body. However, this is usually unnecessarily verbose - when we are pointing at an entire function in a diagnostic, we almost always want to point at the signature. The actual contents of the body tends to be irrelevant to the diagnostic we are emitting, and just takes up additional screen space. This commit changes the `def_span` of all function items (freestanding functions, `impl`-block methods, and `trait`-block methods) to be the span of the signature. For example, the function ```rust pub fn foo<T>(val: T) -> T { val } ``` now has a `def_span` corresponding to `pub fn foo<T>(val: T) -> T` (everything before the opening curly brace). Trait methods without a body have a `def_span` which includes the trailing semicolon. For example: ```rust trait Foo { fn bar(); }``` the function definition `Foo::bar` has a `def_span` of `fn bar();` This makes our diagnostic output much shorter, and emphasizes information that is relevant to whatever diagnostic we are reporting. We continue to use the full span (including the body) in a few of places: * MIR building uses the full span when building source scopes. * 'Outlives suggestions' use the full span to sort the diagnostics being emitted. * The `#[rustc_on_unimplemented(enclosing_scope="in this scope")]` attribute points the entire scope body. * The 'unconditional recursion' lint uses the full span to show additional context for the recursive call. All of these cases work only with local items, so we don't need to add anything extra to crate metadata.
2020-08-12 17:02:14 -04:00
},
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
2022-02-13 16:27:59 +01:00
Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
_ => named_span(item.span, item.ident, None),
Use smaller def span for functions Currently, the def span of a funtion encompasses the entire function signature and body. However, this is usually unnecessarily verbose - when we are pointing at an entire function in a diagnostic, we almost always want to point at the signature. The actual contents of the body tends to be irrelevant to the diagnostic we are emitting, and just takes up additional screen space. This commit changes the `def_span` of all function items (freestanding functions, `impl`-block methods, and `trait`-block methods) to be the span of the signature. For example, the function ```rust pub fn foo<T>(val: T) -> T { val } ``` now has a `def_span` corresponding to `pub fn foo<T>(val: T) -> T` (everything before the opening curly brace). Trait methods without a body have a `def_span` which includes the trailing semicolon. For example: ```rust trait Foo { fn bar(); }``` the function definition `Foo::bar` has a `def_span` of `fn bar();` This makes our diagnostic output much shorter, and emphasizes information that is relevant to whatever diagnostic we are reporting. We continue to use the full span (including the body) in a few of places: * MIR building uses the full span when building source scopes. * 'Outlives suggestions' use the full span to sort the diagnostics being emitted. * The `#[rustc_on_unimplemented(enclosing_scope="in this scope")]` attribute points the entire scope body. * The 'unconditional recursion' lint uses the full span to show additional context for the recursive call. All of these cases work only with local items, so we don't need to add anything extra to crate metadata.
2020-08-12 17:02:14 -04:00
},
2023-01-03 07:31:04 +00:00
Node::Ctor(_) => return self.opt_span(self.parent_id(hir_id)),
Node::Expr(Expr {
kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
span,
..
}) => {
// Ensure that the returned span has the item's SyntaxContext.
fn_decl_span.find_ancestor_inside(*span).unwrap_or(*span)
}
2022-02-13 16:27:59 +01:00
_ => self.span_with_body(hir_id),
};
debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt());
2022-02-13 16:27:59 +01:00
Some(span)
}
/// Like `hir.span()`, but includes the body of items
/// (instead of just the item header)
pub fn span_with_body(self, hir_id: HirId) -> Span {
match self.get(hir_id) {
Node::Param(param) => param.span,
Node::Item(item) => item.span,
Node::ForeignItem(foreign_item) => foreign_item.span,
Node::TraitItem(trait_item) => trait_item.span,
Node::ImplItem(impl_item) => impl_item.span,
2020-12-23 10:32:00 +01:00
Node::Variant(variant) => variant.span,
Node::Field(field) => field.span,
Node::AnonConst(constant) => self.body(constant.body).value.span,
Node::ConstBlock(constant) => self.body(constant.body).value.span,
2020-12-23 10:32:00 +01:00
Node::Expr(expr) => expr.span,
Node::ExprField(field) => field.span,
2020-12-23 10:32:00 +01:00
Node::Stmt(stmt) => stmt.span,
2022-02-14 13:25:26 +01:00
Node::PathSegment(seg) => {
let ident_span = seg.ident.span;
ident_span
.with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
}
2020-12-23 10:32:00 +01:00
Node::Ty(ty) => ty.span,
Node::TypeBinding(tb) => tb.span,
2020-12-23 10:32:00 +01:00
Node::TraitRef(tr) => tr.path.span,
Node::Pat(pat) => pat.span,
Node::PatField(field) => field.span,
2020-12-23 10:32:00 +01:00
Node::Arm(arm) => arm.span,
Node::Block(block) => block.span,
2023-01-03 07:31:04 +00:00
Node::Ctor(..) => self.span_with_body(self.parent_id(hir_id)),
Node::Lifetime(lifetime) => lifetime.ident.span,
2020-12-23 10:32:00 +01:00
Node::GenericParam(param) => param.span,
2021-04-24 21:41:57 +00:00
Node::Infer(i) => i.span,
2020-12-23 10:32:00 +01:00
Node::Local(local) => local.span,
Node::Crate(item) => item.spans.inner_span,
Use smaller def span for functions Currently, the def span of a funtion encompasses the entire function signature and body. However, this is usually unnecessarily verbose - when we are pointing at an entire function in a diagnostic, we almost always want to point at the signature. The actual contents of the body tends to be irrelevant to the diagnostic we are emitting, and just takes up additional screen space. This commit changes the `def_span` of all function items (freestanding functions, `impl`-block methods, and `trait`-block methods) to be the span of the signature. For example, the function ```rust pub fn foo<T>(val: T) -> T { val } ``` now has a `def_span` corresponding to `pub fn foo<T>(val: T) -> T` (everything before the opening curly brace). Trait methods without a body have a `def_span` which includes the trailing semicolon. For example: ```rust trait Foo { fn bar(); }``` the function definition `Foo::bar` has a `def_span` of `fn bar();` This makes our diagnostic output much shorter, and emphasizes information that is relevant to whatever diagnostic we are reporting. We continue to use the full span (including the body) in a few of places: * MIR building uses the full span when building source scopes. * 'Outlives suggestions' use the full span to sort the diagnostics being emitted. * The `#[rustc_on_unimplemented(enclosing_scope="in this scope")]` attribute points the entire scope body. * The 'unconditional recursion' lint uses the full span to show additional context for the recursive call. All of these cases work only with local items, so we don't need to add anything extra to crate metadata.
2020-08-12 17:02:14 -04:00
}
}
pub fn span_if_local(self, id: DefId) -> Option<Span> {
id.is_local().then(|| self.tcx.def_span(id))
}
pub fn res_span(self, res: Res) -> Option<Span> {
match res {
Res::Err => None,
Res::Local(id) => Some(self.span(id)),
res => self.span_if_local(res.opt_def_id()?),
}
}
/// Get a representation of this `id` for debugging purposes.
/// NOTE: Do NOT use this in diagnostics!
pub fn node_to_string(self, id: HirId) -> String {
hir_id_to_string(self, id)
2019-02-03 09:14:31 +01:00
}
/// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
/// called with the HirId for the `{ ... }` anon const
pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
2023-01-03 17:30:35 +00:00
match self.get_parent(anon_const) {
Node::GenericParam(GenericParam {
def_id: param_id,
kind: GenericParamKind::Const { .. },
..
}) => Some(*param_id),
_ => None,
}
}
pub fn maybe_get_struct_pattern_shorthand_field(&self, expr: &Expr<'_>) -> Option<Symbol> {
let local = match expr {
Expr {
kind:
ExprKind::Path(QPath::Resolved(
None,
Path {
res: def::Res::Local(_), segments: [PathSegment { ident, .. }], ..
},
)),
..
} => Some(ident),
_ => None,
}?;
match self.find_parent(expr.hir_id)? {
Node::ExprField(field) => {
if field.ident.name == local.name && field.is_shorthand {
return Some(local.name);
}
}
_ => {}
}
None
}
}
2020-01-07 17:25:33 +01:00
impl<'hir> intravisit::Map<'hir> for Map<'hir> {
fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
(*self).find(hir_id)
}
2020-01-07 17:25:33 +01:00
fn body(&self, id: BodyId) -> &'hir Body<'hir> {
(*self).body(id)
2020-01-07 17:25:33 +01:00
}
2021-01-30 12:06:04 +01:00
fn item(&self, id: ItemId) -> &'hir Item<'hir> {
(*self).item(id)
2020-01-07 17:25:33 +01:00
}
fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
(*self).trait_item(id)
2020-01-07 17:25:33 +01:00
}
fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
(*self).impl_item(id)
2020-01-07 17:25:33 +01:00
}
2020-11-11 21:57:54 +01:00
fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
(*self).foreign_item(id)
2020-11-11 21:57:54 +01:00
}
2020-01-07 17:25:33 +01:00
}
2023-03-13 22:22:59 +00:00
pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
2021-09-19 22:07:12 +02:00
let krate = tcx.hir_crate(());
let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash");
2021-02-28 18:58:50 +01:00
let upstream_crates = upstream_crates(tcx);
2021-02-28 18:58:50 +01:00
let resolutions = tcx.resolutions(());
2021-02-28 18:58:50 +01:00
// We hash the final, remapped names of all local source files so we
// don't have to include the path prefix remapping commandline args.
// If we included the full mapping in the SVH, we could only have
// reproducible builds by compiling from the same directory. So we just
// hash the result of the mapping instead of the mapping itself.
let mut source_file_names: Vec<_> = tcx
.sess
.source_map()
.files()
.iter()
.filter(|source_file| source_file.cnum == LOCAL_CRATE)
.map(|source_file| source_file.name_hash)
.collect();
source_file_names.sort_unstable();
// We have to take care of debugger visualizers explicitly. The HIR (and
// thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but
// these attributes only store the file path to the visualizer file, not
// their content. Yet that content is exported into crate metadata, so any
// changes to it need to be reflected in the crate hash.
let debugger_visualizers: Vec<_> = tcx
.debugger_visualizers(LOCAL_CRATE)
.iter()
// We ignore the path to the visualizer file since it's not going to be
// encoded in crate metadata and we already hash the full contents of
// the file.
.map(DebuggerVisualizerFile::path_erased)
.collect();
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new();
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
if tcx.sess.opts.incremental.is_some() {
let definitions = tcx.untracked().definitions.freeze();
let mut owner_spans: Vec<_> = krate
.owners
.iter_enumerated()
.filter_map(|(def_id, info)| {
let _ = info.as_owner()?;
let def_path_hash = definitions.def_path_hash(def_id);
let span = tcx.source_span(def_id);
debug_assert_eq!(span.parent(), None);
Some((def_path_hash, span))
})
.collect();
owner_spans.sort_unstable_by_key(|bn| bn.0);
owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
}
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
tcx.stable_crate_id(LOCAL_CRATE).hash_stable(&mut hcx, &mut stable_hasher);
// Hash visibility information since it does not appear in HIR.
resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
stable_hasher.finish()
});
2021-02-28 18:58:50 +01:00
Svh::new(crate_hash)
2021-02-28 18:58:50 +01:00
}
fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
let mut upstream_crates: Vec<_> = tcx
.crates(())
2021-02-28 18:58:50 +01:00
.iter()
.map(|&cnum| {
let stable_crate_id = tcx.stable_crate_id(cnum);
let hash = tcx.crate_hash(cnum);
(stable_crate_id, hash)
2021-02-28 18:58:50 +01:00
})
.collect();
upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id);
2021-02-28 18:58:50 +01:00
upstream_crates
}
fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id);
2016-04-06 13:51:55 +03:00
let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default();
let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str());
2019-06-24 09:58:49 +02:00
match map.find(id) {
2018-08-25 15:56:16 +01:00
Some(Node::Item(item)) => {
2019-09-26 17:51:36 +01:00
let item_str = match item.kind {
2018-07-11 23:36:06 +08:00
ItemKind::ExternCrate(..) => "extern crate",
ItemKind::Use(..) => "use",
ItemKind::Static(..) => "static",
ItemKind::Const(..) => "const",
ItemKind::Fn(..) => "fn",
2021-07-30 23:50:57 -07:00
ItemKind::Macro(..) => "macro",
2018-07-11 23:36:06 +08:00
ItemKind::Mod(..) => "mod",
2020-11-11 22:40:09 +01:00
ItemKind::ForeignMod { .. } => "foreign mod",
2018-07-11 23:36:06 +08:00
ItemKind::GlobalAsm(..) => "global asm",
ItemKind::TyAlias(..) => "ty",
2022-09-06 17:37:00 +02:00
ItemKind::OpaqueTy(ref opaque) => {
if opaque.in_trait {
"opaque type in trait"
} else {
"opaque type"
}
}
2018-07-11 23:36:06 +08:00
ItemKind::Enum(..) => "enum",
ItemKind::Struct(..) => "struct",
ItemKind::Union(..) => "union",
ItemKind::Trait(..) => "trait",
ItemKind::TraitAlias(..) => "trait alias",
ItemKind::Impl { .. } => "impl",
};
format!("{id} ({item_str} {})", path_str(item.owner_id.def_id))
}
Some(Node::ForeignItem(item)) => {
format!("{id} (foreign item {})", path_str(item.owner_id.def_id))
}
Some(Node::ImplItem(ii)) => {
let kind = match ii.kind {
ImplItemKind::Const(..) => "assoc const",
ImplItemKind::Fn(..) => "method",
ImplItemKind::Type(_) => "assoc type",
};
format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
}
2018-08-25 15:56:16 +01:00
Some(Node::TraitItem(ti)) => {
let kind = match ti.kind {
TraitItemKind::Const(..) => "assoc constant",
2020-03-03 12:46:22 -06:00
TraitItemKind::Fn(..) => "trait method",
TraitItemKind::Type(..) => "assoc type",
};
format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
}
2018-08-25 15:56:16 +01:00
Some(Node::Variant(ref variant)) => {
format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id))
}
2018-08-25 15:56:16 +01:00
Some(Node::Field(ref field)) => {
format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
}
Some(Node::AnonConst(_)) => node_str("const"),
Some(Node::ConstBlock(_)) => node_str("const"),
Some(Node::Expr(_)) => node_str("expr"),
Some(Node::ExprField(_)) => node_str("expr field"),
Some(Node::Stmt(_)) => node_str("stmt"),
Some(Node::PathSegment(_)) => node_str("path segment"),
Some(Node::Ty(_)) => node_str("type"),
Some(Node::TypeBinding(_)) => node_str("type binding"),
Some(Node::TraitRef(_)) => node_str("trait ref"),
Some(Node::Pat(_)) => node_str("pat"),
Some(Node::PatField(_)) => node_str("pattern field"),
Some(Node::Param(_)) => node_str("param"),
Some(Node::Arm(_)) => node_str("arm"),
Some(Node::Block(_)) => node_str("block"),
2021-04-24 21:41:57 +00:00
Some(Node::Infer(_)) => node_str("infer"),
Some(Node::Local(_)) => node_str("local"),
Some(Node::Ctor(ctor)) => format!(
"{id} (ctor {})",
ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)),
),
Some(Node::Lifetime(_)) => node_str("lifetime"),
Some(Node::GenericParam(ref param)) => {
format!("{id} (generic_param {})", path_str(param.def_id))
}
Some(Node::Crate(..)) => String::from("(root_crate)"),
None => format!("{id} (unknown node)"),
}
}
2021-07-18 18:12:17 +02:00
2023-04-26 20:53:51 +02:00
pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems {
let mut collector = ItemCollector::new(tcx, false);
2021-07-18 18:12:17 +02:00
let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
collector.visit_mod(hir_mod, span, hir_id);
let ItemCollector {
submodules,
items,
trait_items,
impl_items,
foreign_items,
body_owners,
..
} = collector;
2021-09-07 20:07:33 +02:00
return ModuleItems {
submodules: submodules.into_boxed_slice(),
items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
impl_items: impl_items.into_boxed_slice(),
foreign_items: foreign_items.into_boxed_slice(),
body_owners: body_owners.into_boxed_slice(),
2021-09-07 20:07:33 +02:00
};
2021-07-18 18:12:17 +02:00
}
pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
let mut collector = ItemCollector::new(tcx, true);
// A "crate collector" and "module collector" start at a
// module item (the former starts at the crate root) but only
// the former needs to collect it. ItemCollector does not do this for us.
collector.submodules.push(CRATE_OWNER_ID);
tcx.hir().walk_toplevel_module(&mut collector);
let ItemCollector {
submodules,
items,
trait_items,
impl_items,
foreign_items,
body_owners,
..
} = collector;
return ModuleItems {
submodules: submodules.into_boxed_slice(),
items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
impl_items: impl_items.into_boxed_slice(),
foreign_items: foreign_items.into_boxed_slice(),
body_owners: body_owners.into_boxed_slice(),
};
}
struct ItemCollector<'tcx> {
// When true, it collects all items in the create,
// otherwise it collects items in some module.
crate_collector: bool,
tcx: TyCtxt<'tcx>,
submodules: Vec<OwnerId>,
items: Vec<ItemId>,
trait_items: Vec<TraitItemId>,
impl_items: Vec<ImplItemId>,
foreign_items: Vec<ForeignItemId>,
body_owners: Vec<LocalDefId>,
}
impl<'tcx> ItemCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> {
ItemCollector {
crate_collector,
tcx,
submodules: Vec::default(),
items: Vec::default(),
trait_items: Vec::default(),
impl_items: Vec::default(),
foreign_items: Vec::default(),
body_owners: Vec::default(),
}
}
}
impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
type NestedFilter = nested_filter::All;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_item(&mut self, item: &'hir Item<'hir>) {
if associated_body(Node::Item(item)).is_some() {
self.body_owners.push(item.owner_id.def_id);
}
self.items.push(item.item_id());
// Items that are modules are handled here instead of in visit_mod.
if let ItemKind::Mod(module) = &item.kind {
self.submodules.push(item.owner_id);
// A module collector does not recurse inside nested modules.
if self.crate_collector {
intravisit::walk_mod(self, module, item.hir_id());
}
} else {
intravisit::walk_item(self, item)
}
}
fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
self.foreign_items.push(item.foreign_item_id());
intravisit::walk_foreign_item(self, item)
}
fn visit_anon_const(&mut self, c: &'hir AnonConst) {
2022-11-06 19:17:57 +00:00
self.body_owners.push(c.def_id);
intravisit::walk_anon_const(self, c)
}
fn visit_inline_const(&mut self, c: &'hir ConstBlock) {
self.body_owners.push(c.def_id);
intravisit::walk_inline_const(self, c)
}
fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
2022-11-06 13:29:21 +00:00
if let ExprKind::Closure(closure) = ex.kind {
self.body_owners.push(closure.def_id);
}
intravisit::walk_expr(self, ex)
}
fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
if associated_body(Node::TraitItem(item)).is_some() {
self.body_owners.push(item.owner_id.def_id);
}
self.trait_items.push(item.trait_item_id());
intravisit::walk_trait_item(self, item)
}
fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
if associated_body(Node::ImplItem(item)).is_some() {
self.body_owners.push(item.owner_id.def_id);
}
self.impl_items.push(item.impl_item_id());
intravisit::walk_impl_item(self, item)
}
}