Skip to content

Commit

Permalink
Auto merge of rust-lang#79519 - cjgillot:noattr, r=wesleywiser
Browse files Browse the repository at this point in the history
Store HIR attributes in a side table

Same idea as rust-lang#72015 but for attributes.
The objective is to reduce incr-comp invalidations due to modified attributes.
Notably, those due to modified doc comments.

Implementation:
- collect attributes during AST->HIR lowering, in `LocalDefId -> ItemLocalId -> &[Attributes]` nested tables;
- access the attributes through a `hir_owner_attrs` query;
- local refactorings to use this access;
- remove `attrs` from HIR data structures one-by-one.

Change in behaviour:
- the HIR visitor traverses all attributes at once instead of parent-by-parent;
- attribute arrays are sometimes duplicated: for statements and variant constructors;
- as a consequence, attributes are marked as used after unused-attribute lint emission to avoid duplicate lints.

~~Current bug: the lint level is not correctly applied in `std::backtrace_rs`, triggering an unused attribute warning on `#![no_std]`. I welcome suggestions.~~
  • Loading branch information
bors committed Mar 10, 2021
2 parents cb8bc0b + 6c66826 commit 36a27ec
Show file tree
Hide file tree
Showing 26 changed files with 103 additions and 81 deletions.
11 changes: 6 additions & 5 deletions clippy_lints/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
}

fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
if is_relevant_item(cx, item) {
check_attrs(cx, item.span, item.ident.name, &item.attrs)
check_attrs(cx, item.span, item.ident.name, attrs)
}
match item.kind {
ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym::macro_use));
let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use));

for attr in item.attrs {
for attr in attrs {
if in_external_macro(cx.sess(), attr.span) {
return;
}
Expand Down Expand Up @@ -353,13 +354,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {

fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
if is_relevant_impl(cx, item) {
check_attrs(cx, item.span, item.ident.name, &item.attrs)
check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
}
}

fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if is_relevant_trait(cx, item) {
check_attrs(cx, item.span, item.ident.name, &item.attrs)
check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/cognitive_complexity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ impl CognitiveComplexity {

if rust_cc > self.limit.limit() {
let fn_span = match kind {
FnKind::ItemFn(ident, _, _, _, _) | FnKind::Method(ident, _, _, _) => ident.span,
FnKind::Closure(_) => {
FnKind::ItemFn(ident, _, _, _) | FnKind::Method(ident, _, _) => ident.span,
FnKind::Closure => {
let header_span = body_span.with_hi(decl.output.span().lo());
let pos = snippet_opt(cx, header_span).and_then(|snip| {
let low_offset = snip.find('|')?;
Expand Down
3 changes: 2 additions & 1 deletion clippy_lints/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind
{
let ty = cx.tcx.type_of(item.def_id);
let is_automatically_derived = is_automatically_derived(&*item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let is_automatically_derived = is_automatically_derived(attrs);

check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
Expand Down
14 changes: 9 additions & 5 deletions clippy_lints/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,14 @@ impl_lint_pass!(DocMarkdown =>
);

impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
check_attrs(cx, &self.valid_idents, &krate.item.attrs);
fn check_crate(&mut self, cx: &LateContext<'tcx>, _: &'tcx hir::Crate<'_>) {
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
check_attrs(cx, &self.valid_idents, attrs);
}

fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let headers = check_attrs(cx, &self.valid_idents, attrs);
match item.kind {
hir::ItemKind::Fn(ref sig, _, body_id) => {
if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
Expand Down Expand Up @@ -249,7 +251,8 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
}

fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let headers = check_attrs(cx, &self.valid_idents, attrs);
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
if !in_external_macro(cx.tcx.sess, item.span) {
lint_for_missing_headers(cx, item.hir_id(), item.span, sig, headers, None, None);
Expand All @@ -258,7 +261,8 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
}

fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let headers = check_attrs(cx, &self.valid_idents, attrs);
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
return;
}
Expand Down
3 changes: 2 additions & 1 deletion clippy_lints/src/exhaustive_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ impl LateLintPass<'_> for ExhaustiveItems {
if_chain! {
if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
if cx.access_levels.is_exported(item.hir_id());
if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
then {
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
Expand Down
24 changes: 13 additions & 11 deletions clippy_lints/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
hir_id: hir::HirId,
) {
let unsafety = match kind {
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _, _) => unsafety,
intravisit::FnKind::Method(_, sig, _, _) => sig.header.unsafety,
intravisit::FnKind::Closure(_) => return,
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
intravisit::FnKind::Closure => return,
};

// don't warn for implementations, it's not their fault
Expand All @@ -267,9 +267,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
..
},
_,
_,
)
| intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
| intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _) => {
self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi()))
},
_ => {},
Expand All @@ -281,7 +280,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
}

fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attr = must_use_attr(&item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = must_use_attr(attrs);
if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
let is_public = cx.access_levels.is_exported(item.hir_id());
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
Expand All @@ -292,7 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
return;
}
if is_public && !is_proc_macro(cx.sess(), &item.attrs) && attr_by_name(&item.attrs, "no_mangle").is_none() {
if is_public && !is_proc_macro(cx.sess(), attrs) && attr_by_name(attrs, "no_mangle").is_none() {
check_must_use_candidate(
cx,
&sig.decl,
Expand All @@ -313,11 +313,12 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() {
check_result_unit_err(cx, &sig.decl, item.span, fn_header_span);
}
let attr = must_use_attr(&item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = must_use_attr(attrs);
if let Some(attr) = attr {
check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if is_public
&& !is_proc_macro(cx.sess(), &item.attrs)
&& !is_proc_macro(cx.sess(), attrs)
&& trait_ref_of_method(cx, item.hir_id()).is_none()
{
check_must_use_candidate(
Expand Down Expand Up @@ -345,15 +346,16 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
check_result_unit_err(cx, &sig.decl, item.span, fn_header_span);
}

let attr = must_use_attr(&item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = must_use_attr(attrs);
if let Some(attr) = attr {
check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
}
if let hir::TraitFn::Provided(eid) = *eid {
let body = cx.tcx.hir().body(eid);
Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id());

if attr.is_none() && is_public && !is_proc_macro(cx.sess(), &item.attrs) {
if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
check_must_use_candidate(
cx,
&sig.decl,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/future_not_send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
_: Span,
hir_id: HirId,
) {
if let FnKind::Closure(_) = kind {
if let FnKind::Closure = kind {
return;
}
let ret_ty = utils::return_ty(cx, hir_id);
Expand Down
3 changes: 2 additions & 1 deletion clippy_lints/src/inline_fn_without_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind {
check_attrs(cx, item.ident.name, &item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
check_attrs(cx, item.ident.name, attrs);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
let msg = "empty `loop {}` wastes CPU cycles";
let help = if is_no_std_crate(cx.tcx.hir().krate()) {
let help = if is_no_std_crate(cx) {
"you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body"
} else {
"you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body"
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/macro_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
if_chain! {
if cx.sess().opts.edition >= Edition::Edition2018;
if let hir::ItemKind::Use(path, _kind) = &item.kind;
if let Some(mac_attr) = item
.attrs
let attrs = cx.tcx.hir().attrs(item.hir_id());
if let Some(mac_attr) = attrs
.iter()
.find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
if let Res::Def(DefKind::Mod, id) = path.res;
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/main_recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ pub struct MainRecursion {
impl_lint_pass!(MainRecursion => [MAIN_RECURSION]);

impl LateLintPass<'_> for MainRecursion {
fn check_crate(&mut self, _: &LateContext<'_>, krate: &Crate<'_>) {
self.has_no_std_attr = is_no_std_crate(krate);
fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
self.has_no_std_attr = is_no_std_crate(cx);
}

fn check_expr_post(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1207,11 +1207,11 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
if b0 != b1;
let if_guard = &b0_arms[0].guard;
if if_guard.is_none() || b0_arms.len() == 1;
if b0_arms[0].attrs.is_empty();
if cx.tcx.hir().attrs(b0_arms[0].hir_id).is_empty();
if b0_arms[1..].iter()
.all(|arm| {
find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) &&
arm.guard.is_none() && arm.attrs.is_empty()
arm.guard.is_none() && cx.tcx.hir().attrs(arm.hir_id).is_empty()
});
then {
// The suggestion may be incorrect, because some arms can have `cfg` attributes
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
span: Span,
_: HirId,
) {
if let FnKind::Closure(_) = k {
if let FnKind::Closure = k {
// Does not apply to closures
return;
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/missing_const_for_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
return;
}
},
FnKind::Closure(..) => return,
FnKind::Closure => return,
}

let mir = cx.tcx.optimized_mir(def_id);
Expand Down
18 changes: 12 additions & 6 deletions clippy_lints/src/missing_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}

fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
self.check_missing_docs_attrs(cx, &krate.item.attrs, krate.item.span, "the", "crate");
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
self.check_missing_docs_attrs(cx, attrs, krate.item.span, "the", "crate");
}

fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
Expand Down Expand Up @@ -160,13 +161,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {

let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());

self.check_missing_docs_attrs(cx, &it.attrs, it.span, article, desc);
let attrs = cx.tcx.hir().attrs(it.hir_id());
self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
}

fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());

self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, article, desc);
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
}

fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
Expand All @@ -181,16 +184,19 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}

let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, article, desc);
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
}

fn check_struct_field(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::StructField<'_>) {
if !sf.is_positional() {
self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a", "struct field");
let attrs = cx.tcx.hir().attrs(sf.hir_id);
self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
}
}

fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
self.check_missing_docs_attrs(cx, &v.attrs, v.span, "a", "variant");
let attrs = cx.tcx.hir().attrs(v.id);
self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
}
}
9 changes: 6 additions & 3 deletions clippy_lints/src/missing_inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
match it.kind {
hir::ItemKind::Fn(..) => {
let desc = "a function";
check_missing_inline_attrs(cx, &it.attrs, it.span, desc);
let attrs = cx.tcx.hir().attrs(it.hir_id());
check_missing_inline_attrs(cx, attrs, it.span, desc);
},
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, trait_items) => {
// note: we need to check if the trait is exported so we can't use
Expand All @@ -108,7 +109,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
// an impl is not provided
let desc = "a default trait method";
let item = cx.tcx.hir().trait_item(tit.id);
check_missing_inline_attrs(cx, &item.attrs, item.span, desc);
let attrs = cx.tcx.hir().attrs(item.hir_id());
check_missing_inline_attrs(cx, attrs, item.span, desc);
}
},
}
Expand Down Expand Up @@ -160,6 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
}
}

check_missing_inline_attrs(cx, &impl_item.attrs, impl_item.span, desc);
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
check_missing_inline_attrs(cx, attrs, impl_item.span, desc);
}
}
5 changes: 3 additions & 2 deletions clippy_lints/src/needless_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
}
}

fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if is_automatically_derived(item.attrs) {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
if is_automatically_derived(attrs) {
debug_assert!(self.derived_item.is_none());
self.derived_item = Some(item.def_id);
}
Expand Down
5 changes: 3 additions & 2 deletions clippy_lints/src/needless_pass_by_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
}

match kind {
FnKind::ItemFn(.., header, _, attrs) => {
FnKind::ItemFn(.., header, _) => {
let attrs = cx.tcx.hir().attrs(hir_id);
if header.abi != Abi::Rust || requires_exact_signature(attrs) {
return;
}
},
FnKind::Method(..) => (),
FnKind::Closure(..) => return,
FnKind::Closure => return,
}

// Exclude non-inherent impls
Expand Down
4 changes: 1 addition & 3 deletions clippy_lints/src/panic_in_result_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
span: Span,
hir_id: hir::HirId,
) {
if !matches!(fn_kind, FnKind::Closure(_))
&& is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type)
{
if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
lint_impl_body(cx, span, body);
}
}
Expand Down
3 changes: 2 additions & 1 deletion clippy_lints/src/partialeq_ne_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! {
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
if !is_automatically_derived(&*item.attrs);
let attrs = cx.tcx.hir().attrs(item.hir_id());
if !is_automatically_derived(attrs);
if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait;
then {
Expand Down
Loading

0 comments on commit 36a27ec

Please sign in to comment.