1
Fork 0

Auto merge of #79519 - cjgillot:noattr, r=wesleywiser

Store HIR attributes in a side table

Same idea as #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.~~
This commit is contained in:
bors 2021-03-10 08:40:51 +00:00
commit 36a27ecaac
26 changed files with 103 additions and 81 deletions

View file

@ -276,14 +276,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
} }
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { 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) { 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 { match item.kind {
ItemKind::ExternCrate(..) | ItemKind::Use(..) => { 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) { if in_external_macro(cx.sess(), attr.span) {
return; return;
} }
@ -353,13 +354,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
if is_relevant_impl(cx, item) { 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<'_>) { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if is_relevant_trait(cx, item) { 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()))
} }
} }
} }

View file

@ -76,8 +76,8 @@ impl CognitiveComplexity {
if rust_cc > self.limit.limit() { if rust_cc > self.limit.limit() {
let fn_span = match kind { let fn_span = match kind {
FnKind::ItemFn(ident, _, _, _, _) | FnKind::Method(ident, _, _, _) => ident.span, FnKind::ItemFn(ident, _, _, _) | FnKind::Method(ident, _, _) => ident.span,
FnKind::Closure(_) => { FnKind::Closure => {
let header_span = body_span.with_hi(decl.output.span().lo()); let header_span = body_span.with_hi(decl.output.span().lo());
let pos = snippet_opt(cx, header_span).and_then(|snip| { let pos = snippet_opt(cx, header_span).and_then(|snip| {
let low_offset = snip.find('|')?; let low_offset = snip.find('|')?;

View file

@ -170,7 +170,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind }) = item.kind
{ {
let ty = cx.tcx.type_of(item.def_id); 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_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);

View file

@ -208,12 +208,14 @@ impl_lint_pass!(DocMarkdown =>
); );
impl<'tcx> LateLintPass<'tcx> for DocMarkdown { impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) { fn check_crate(&mut self, cx: &LateContext<'tcx>, _: &'tcx hir::Crate<'_>) {
check_attrs(cx, &self.valid_idents, &krate.item.attrs); 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<'_>) { 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 { match item.kind {
hir::ItemKind::Fn(ref sig, _, body_id) => { 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)) { if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
@ -249,7 +251,8 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
} }
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { 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 let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
if !in_external_macro(cx.tcx.sess, item.span) { if !in_external_macro(cx.tcx.sess, item.span) {
lint_for_missing_headers(cx, item.hir_id(), item.span, sig, headers, None, None); lint_for_missing_headers(cx, item.hir_id(), item.span, sig, headers, None, None);
@ -258,7 +261,8 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
} }
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { 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) { if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
return; return;
} }

View file

@ -73,7 +73,8 @@ impl LateLintPass<'_> for ExhaustiveItems {
if_chain! { if_chain! {
if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind; if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
if cx.access_levels.is_exported(item.hir_id()); 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 { then {
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
if v.fields().iter().any(|f| !f.vis.node.is_pub()) { if v.fields().iter().any(|f| !f.vis.node.is_pub()) {

View file

@ -251,9 +251,9 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
hir_id: hir::HirId, hir_id: hir::HirId,
) { ) {
let unsafety = match kind { let unsafety = match kind {
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _, _) => unsafety, intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
intravisit::FnKind::Method(_, sig, _, _) => sig.header.unsafety, intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
intravisit::FnKind::Closure(_) => return, intravisit::FnKind::Closure => return,
}; };
// don't warn for implementations, it's not their fault // don't warn for implementations, it's not their fault
@ -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())) self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi()))
}, },
_ => {}, _ => {},
@ -281,7 +280,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
} }
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { 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 { 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 is_public = cx.access_levels.is_exported(item.hir_id());
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@ -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); check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
return; 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( check_must_use_candidate(
cx, cx,
&sig.decl, &sig.decl,
@ -313,11 +313,12 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() { 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); 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 { if let Some(attr) = attr {
check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr); check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if is_public } 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() && trait_ref_of_method(cx, item.hir_id()).is_none()
{ {
check_must_use_candidate( check_must_use_candidate(
@ -345,7 +346,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); 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 { if let Some(attr) = attr {
check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr); check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} }
@ -353,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
let body = cx.tcx.hir().body(eid); let body = cx.tcx.hir().body(eid);
Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id()); 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( check_must_use_candidate(
cx, cx,
&sig.decl, &sig.decl,

View file

@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
_: Span, _: Span,
hir_id: HirId, hir_id: HirId,
) { ) {
if let FnKind::Closure(_) = kind { if let FnKind::Closure = kind {
return; return;
} }
let ret_ty = utils::return_ty(cx, hir_id); let ret_ty = utils::return_ty(cx, hir_id);

View file

@ -34,7 +34,8 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind { 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);
} }
} }
} }

View file

@ -578,7 +578,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
// also check for empty `loop {}` statements, skipping those in #[panic_handler] // 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) { if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
let msg = "empty `loop {}` wastes CPU cycles"; 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" "you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body"
} else { } else {
"you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body" "you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body"

View file

@ -107,8 +107,8 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
if_chain! { if_chain! {
if cx.sess().opts.edition >= Edition::Edition2018; if cx.sess().opts.edition >= Edition::Edition2018;
if let hir::ItemKind::Use(path, _kind) = &item.kind; if let hir::ItemKind::Use(path, _kind) = &item.kind;
if let Some(mac_attr) = item let attrs = cx.tcx.hir().attrs(item.hir_id());
.attrs if let Some(mac_attr) = attrs
.iter() .iter()
.find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string())); .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
if let Res::Def(DefKind::Mod, id) = path.res; if let Res::Def(DefKind::Mod, id) = path.res;

View file

@ -32,8 +32,8 @@ pub struct MainRecursion {
impl_lint_pass!(MainRecursion => [MAIN_RECURSION]); impl_lint_pass!(MainRecursion => [MAIN_RECURSION]);
impl LateLintPass<'_> for MainRecursion { impl LateLintPass<'_> for MainRecursion {
fn check_crate(&mut self, _: &LateContext<'_>, krate: &Crate<'_>) { fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
self.has_no_std_attr = is_no_std_crate(krate); self.has_no_std_attr = is_no_std_crate(cx);
} }
fn check_expr_post(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr_post(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {

View file

@ -1207,11 +1207,11 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
if b0 != b1; if b0 != b1;
let if_guard = &b0_arms[0].guard; let if_guard = &b0_arms[0].guard;
if if_guard.is_none() || b0_arms.len() == 1; 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() if b0_arms[1..].iter()
.all(|arm| { .all(|arm| {
find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) && 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 { then {
// The suggestion may be incorrect, because some arms can have `cfg` attributes // The suggestion may be incorrect, because some arms can have `cfg` attributes

View file

@ -278,7 +278,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
span: Span, span: Span,
_: HirId, _: HirId,
) { ) {
if let FnKind::Closure(_) = k { if let FnKind::Closure = k {
// Does not apply to closures // Does not apply to closures
return; return;
} }

View file

@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
return; return;
} }
}, },
FnKind::Closure(..) => return, FnKind::Closure => return,
} }
let mir = cx.tcx.optimized_mir(def_id); let mir = cx.tcx.optimized_mir(def_id);

View file

@ -127,7 +127,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
} }
fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) { 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<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
@ -160,13 +161,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id()); 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<'_>) { 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()); 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<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
@ -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()); 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<'_>) { fn check_struct_field(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::StructField<'_>) {
if !sf.is_positional() { 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<'_>) { 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");
} }
} }

View file

@ -93,7 +93,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
match it.kind { match it.kind {
hir::ItemKind::Fn(..) => { hir::ItemKind::Fn(..) => {
let desc = "a function"; 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) => { 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 // note: we need to check if the trait is exported so we can't use
@ -108,7 +109,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
// an impl is not provided // an impl is not provided
let desc = "a default trait method"; let desc = "a default trait method";
let item = cx.tcx.hir().trait_item(tit.id); 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);
} }
}, },
} }
@ -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);
} }
} }

View file

@ -115,8 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
} }
} }
fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if is_automatically_derived(item.attrs) { let attrs = cx.tcx.hir().attrs(item.hir_id());
if is_automatically_derived(attrs) {
debug_assert!(self.derived_item.is_none()); debug_assert!(self.derived_item.is_none());
self.derived_item = Some(item.def_id); self.derived_item = Some(item.def_id);
} }

View file

@ -80,13 +80,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
} }
match kind { 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) { if header.abi != Abi::Rust || requires_exact_signature(attrs) {
return; return;
} }
}, },
FnKind::Method(..) => (), FnKind::Method(..) => (),
FnKind::Closure(..) => return, FnKind::Closure => return,
} }
// Exclude non-inherent impls // Exclude non-inherent impls

View file

@ -43,9 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
span: Span, span: Span,
hir_id: hir::HirId, hir_id: hir::HirId,
) { ) {
if !matches!(fn_kind, FnKind::Closure(_)) if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
&& is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type)
{
lint_impl_body(cx, span, body); lint_impl_body(cx, span, body);
} }
} }

View file

@ -35,7 +35,8 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! { if_chain! {
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; 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 let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait; if trait_ref.path.res.def_id() == eq_trait;
then { then {

View file

@ -224,10 +224,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
} }
match kind { match kind {
FnKind::ItemFn(.., header, _, attrs) => { FnKind::ItemFn(.., header, _) => {
if header.abi != Abi::Rust { if header.abi != Abi::Rust {
return; return;
} }
let attrs = cx.tcx.hir().attrs(hir_id);
for a in attrs { for a in attrs {
if let Some(meta_items) = a.meta_item_list() { if let Some(meta_items) = a.meta_item_list() {
if a.has_name(sym::proc_macro_derive) if a.has_name(sym::proc_macro_derive)
@ -239,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
} }
}, },
FnKind::Method(..) => (), FnKind::Method(..) => (),
FnKind::Closure(..) => return, FnKind::Closure => return,
} }
// Exclude non-inherent impls // Exclude non-inherent impls

View file

@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
if let Some(stmt) = block.stmts.iter().last(); if let Some(stmt) = block.stmts.iter().last();
if let StmtKind::Local(local) = &stmt.kind; if let StmtKind::Local(local) = &stmt.kind;
if local.ty.is_none(); if local.ty.is_none();
if local.attrs.is_empty(); if cx.tcx.hir().attrs(local.hir_id).is_empty();
if let Some(initexpr) = &local.init; if let Some(initexpr) = &local.init;
if let PatKind::Binding(.., ident, _) = local.pat.kind; if let PatKind::Binding(.., ident, _) = local.pat.kind;
if let ExprKind::Path(qpath) = &retexpr.kind; if let ExprKind::Path(qpath) = &retexpr.kind;
@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
_: HirId, _: HirId,
) { ) {
match kind { match kind {
FnKind::Closure(_) => { FnKind::Closure => {
// when returning without value in closure, replace this `return` // when returning without value in closure, replace this `return`
// with an empty block to prevent invalid suggestion (see #6501) // with an empty block to prevent invalid suggestion (see #6501)
let replacement = if let ExprKind::Ret(None) = &body.value.kind { let replacement = if let ExprKind::Ret(None) = &body.value.kind {
@ -177,7 +177,8 @@ fn check_final_expr<'tcx>(
// simple return is always "bad" // simple return is always "bad"
ExprKind::Ret(ref inner) => { ExprKind::Ret(ref inner) => {
// allow `#[cfg(a)] return a; #[cfg(b)] return b;` // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
if !expr.attrs.iter().any(attr_is_cfg) { let attrs = cx.tcx.hir().attrs(expr.hir_id);
if !attrs.iter().any(attr_is_cfg) {
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if !borrows { if !borrows {
emit_return_lint( emit_return_lint(

View file

@ -66,12 +66,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
) { ) {
// Abort if public function/method or closure. // Abort if public function/method or closure.
match fn_kind { match fn_kind {
FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => { FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => {
if visibility.node.is_pub() { if visibility.node.is_pub() {
return; return;
} }
}, },
FnKind::Closure(..) => return, FnKind::Closure => return,
_ => (), _ => (),
} }

View file

@ -2,7 +2,7 @@
//! to generate a clippy lint detecting said code automatically. //! to generate a clippy lint detecting said code automatically.
use crate::utils::get_attr; use crate::utils::get_attr;
use rustc_ast::ast::{Attribute, LitFloatType, LitKind}; use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_ast::walk_list; use rustc_ast::walk_list;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir; use rustc_hir as hir;
@ -10,7 +10,6 @@ use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_session::Session;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! { declare_clippy_lint! {
@ -66,7 +65,7 @@ fn done() {
impl<'tcx> LateLintPass<'tcx> for Author { impl<'tcx> LateLintPass<'tcx> for Author {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !has_attr(cx.sess(), &item.attrs) { if !has_attr(cx, item.hir_id()) {
return; return;
} }
prelude(); prelude();
@ -75,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
if !has_attr(cx.sess(), &item.attrs) { if !has_attr(cx, item.hir_id()) {
return; return;
} }
prelude(); prelude();
@ -84,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
if !has_attr(cx.sess(), &item.attrs) { if !has_attr(cx, item.hir_id()) {
return; return;
} }
prelude(); prelude();
@ -93,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_variant(&mut self, cx: &LateContext<'tcx>, var: &'tcx hir::Variant<'_>) { fn check_variant(&mut self, cx: &LateContext<'tcx>, var: &'tcx hir::Variant<'_>) {
if !has_attr(cx.sess(), &var.attrs) { if !has_attr(cx, var.id) {
return; return;
} }
prelude(); prelude();
@ -103,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_struct_field(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::StructField<'_>) { fn check_struct_field(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::StructField<'_>) {
if !has_attr(cx.sess(), &field.attrs) { if !has_attr(cx, field.hir_id) {
return; return;
} }
prelude(); prelude();
@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if !has_attr(cx.sess(), &expr.attrs) { if !has_attr(cx, expr.hir_id) {
return; return;
} }
prelude(); prelude();
@ -121,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) { fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
if !has_attr(cx.sess(), &arm.attrs) { if !has_attr(cx, arm.hir_id) {
return; return;
} }
prelude(); prelude();
@ -130,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
if !has_attr(cx.sess(), stmt.kind.attrs(|id| cx.tcx.hir().item(id))) { if !has_attr(cx, stmt.hir_id) {
return; return;
} }
prelude(); prelude();
@ -139,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
} }
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'_>) { fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'_>) {
if !has_attr(cx.sess(), &item.attrs) { if !has_attr(cx, item.hir_id()) {
return; return;
} }
prelude(); prelude();
@ -719,8 +718,9 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
} }
} }
fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool { fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
get_attr(sess, attrs, "author").count() > 0 let attrs = cx.tcx.hir().attrs(hir_id);
get_attr(cx.sess(), attrs, "author").count() > 0
} }
#[must_use] #[must_use]

View file

@ -33,14 +33,14 @@ declare_lint_pass!(DeepCodeInspector => [DEEP_CODE_INSPECTION]);
impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !has_attr(cx.sess(), &item.attrs) { if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
return; return;
} }
print_item(cx, item); print_item(cx, item);
} }
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
if !has_attr(cx.sess(), &item.attrs) { if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
return; return;
} }
println!("impl item `{}`", item.ident.name); println!("impl item `{}`", item.ident.name);
@ -89,14 +89,14 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
// //
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if !has_attr(cx.sess(), &expr.attrs) { if !has_attr(cx.sess(), cx.tcx.hir().attrs(expr.hir_id)) {
return; return;
} }
print_expr(cx, expr, 0); print_expr(cx, expr, 0);
} }
fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) { fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
if !has_attr(cx.sess(), &arm.attrs) { if !has_attr(cx.sess(), cx.tcx.hir().attrs(arm.hir_id)) {
return; return;
} }
print_pat(cx, &arm.pat, 1); print_pat(cx, &arm.pat, 1);
@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
} }
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
if !has_attr(cx.sess(), stmt.kind.attrs(|id| cx.tcx.hir().item(id))) { if !has_attr(cx.sess(), cx.tcx.hir().attrs(stmt.hir_id)) {
return; return;
} }
match stmt.kind { match stmt.kind {

View file

@ -61,7 +61,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::Node; use rustc_hir::Node;
use rustc_hir::{ use rustc_hir::{
def, Arm, Block, Body, Constness, Crate, Expr, ExprKind, FnDecl, HirId, ImplItem, ImplItemKind, Item, ItemKind, def, Arm, Block, Body, Constness, Expr, ExprKind, FnDecl, HirId, ImplItem, ImplItemKind, Item, ItemKind,
MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, TyKind, Unsafety, MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, TyKind, Unsafety,
}; };
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
@ -1510,8 +1510,8 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some()) did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
} }
pub fn is_no_std_crate(krate: &Crate<'_>) -> bool { pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
krate.item.attrs.iter().any(|attr| { cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
if let ast::AttrKind::Normal(ref attr, _) = attr.kind { if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
attr.path == sym::no_std attr.path == sym::no_std
} else { } else {