Skip to content

Commit

Permalink
Use nearly exclusively HIR and avoid at all cost unnecessary query calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Urgau committed Feb 26, 2024
1 parent 301ce36 commit 8ecf8fb
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 84 deletions.
102 changes: 68 additions & 34 deletions compiler/rustc_lint/src/non_local_def.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind};
use rustc_hir::{Body, Item, ItemKind, OwnerNode, Path, QPath, TyKind};
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};

use smallvec::{smallvec, SmallVec};
use rustc_span::{sym, symbol::kw, symbol::Ident, ExpnKind, MacroKind};

use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
use crate::{LateContext, LateLintPass, LintContext};
Expand Down Expand Up @@ -71,15 +69,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
return;
}

let parent = cx.tcx.parent(item.owner_id.def_id.into());
let parent_def_kind = cx.tcx.def_kind(parent);
let parent_opt_item_name = cx.tcx.opt_item_name(parent);
let Some((_, parent_node)) = cx.tcx.hir().parent_owner_iter(item.hir_id()).next() else {
return;
};
let parent_is_anon_const = matches!(
parent_node,
OwnerNode::Item(Item {
ident: Ident { name: kw::Underscore, .. },
kind: ItemKind::Const(..),
..
})
);

// Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module.
if self.body_depth == 1
&& parent_def_kind == DefKind::Const
&& parent_opt_item_name == Some(kw::Underscore)
{
if self.body_depth == 1 && parent_is_anon_const {
return;
}

Expand Down Expand Up @@ -119,23 +122,34 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
// We also ignore anon-const in item by including the anon-const
// parent as well; and since it's quite uncommon, we use smallvec
// to avoid unnecessary heap allocations.
let local_parents: SmallVec<[DefId; 1]> = if parent_def_kind == DefKind::Const
&& parent_opt_item_name == Some(kw::Underscore)
{
smallvec![parent, cx.tcx.parent(parent)]
} else {
smallvec![parent]
let mut local_parent = {
let mut local_parent_cache = None;
move || {
*local_parent_cache
.get_or_insert_with(|| cx.tcx.parent(item.owner_id.to_def_id()))
}
};
let mut extra_local_parent = {
let mut extra_parent_cache = None;
move |did| {
*extra_parent_cache
.get_or_insert_with(|| parent_is_anon_const.then(|| cx.tcx.parent(did)))
}
};

let self_ty_has_local_parent = match impl_.self_ty.kind {
TyKind::Path(QPath::Resolved(_, ty_path)) => {
path_has_local_parent(ty_path, cx, &*local_parents)
}
TyKind::Path(QPath::Resolved(_, ty_path)) => path_has_local_parent(
ty_path,
cx,
&mut local_parent,
&mut extra_local_parent,
),
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
path_has_local_parent(
principle_poly_trait_ref.trait_ref.path,
cx,
&*local_parents,
&mut local_parent,
&mut extra_local_parent,
)
}
TyKind::TraitObject([], _, _)
Expand All @@ -157,17 +171,21 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {

let of_trait_has_local_parent = impl_
.of_trait
.map(|of_trait| path_has_local_parent(of_trait.path, cx, &*local_parents))
.map(|of_trait| {
path_has_local_parent(
of_trait.path,
cx,
&mut local_parent,
&mut extra_local_parent,
)
})
.unwrap_or(false);

// If none of them have a local parent (LOGICAL NOR) this means that
// this impl definition is a non-local definition and so we lint on it.
if !(self_ty_has_local_parent || of_trait_has_local_parent) {
let const_anon = if self.body_depth == 1
&& parent_def_kind == DefKind::Const
&& parent_opt_item_name != Some(kw::Underscore)
&& let Some(parent) = parent.as_local()
&& let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent)
&& let OwnerNode::Item(item) = parent_node
&& let ItemKind::Const(ty, _, _) = item.kind
&& let TyKind::Tup(&[]) = ty.kind
{
Expand All @@ -181,9 +199,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
item.span,
NonLocalDefinitionsDiag::Impl {
depth: self.body_depth,
body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent),
body_name: parent_opt_item_name
.map(|s| s.to_ident_string())
body_kind_descr: "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */,
body_name: parent_node
.ident()
.map(|s| s.name.to_ident_string())
.unwrap_or_else(|| "<unnameable>".to_string()),
cargo_update: cargo_update(),
const_anon,
Expand All @@ -199,9 +218,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
item.span,
NonLocalDefinitionsDiag::MacroRules {
depth: self.body_depth,
body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent),
body_name: parent_opt_item_name
.map(|s| s.to_ident_string())
body_kind_descr: "?" /* FIXME: cx.tcx.def_kind_descr(parent_def_kind, parent) */,
body_name: parent_node
.ident()
.map(|s| s.name.to_ident_string())
.unwrap_or_else(|| "<unnameable>".to_string()),
cargo_update: cargo_update(),
},
Expand All @@ -221,6 +241,20 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
/// std::convert::PartialEq<Foo<Bar>>
/// ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
fn path_has_local_parent(path: &Path<'_>, cx: &LateContext<'_>, local_parents: &[DefId]) -> bool {
path.res.opt_def_id().is_some_and(|did| local_parents.contains(&cx.tcx.parent(did)))
fn path_has_local_parent(
path: &Path<'_>,
cx: &LateContext<'_>,
local_parent: &mut impl FnMut() -> DefId,
extra_local_parent: &mut impl FnMut(DefId) -> Option<DefId>,
) -> bool {
if let Some(did) = path.res.opt_def_id() {
if !did.is_local() {
false
} else {
let res_parent = cx.tcx.parent(did);
res_parent == local_parent() || Some(res_parent) == extra_local_parent(local_parent())
}
} else {
true
}
}
Loading

0 comments on commit 8ecf8fb

Please sign in to comment.