Remove Session.used_attrs
and move logic to CheckAttrVisitor
Instead of updating global state to mark attributes as used, we now explicitly emit a warning when an attribute is used in an unsupported position. As a side effect, we are to emit more detailed warning messages (instead of just a generic "unused" message). `Session.check_name` is removed, since its only purpose was to mark the attribute as used. All of the callers are modified to use `Attribute.has_name` Additionally, `AttributeType::AssumedUsed` is removed - an 'assumed used' attribute is implemented by simply not performing any checks in `CheckAttrVisitor` for a particular attribute. We no longer emit unused attribute warnings for the `#[rustc_dummy]` attribute - it's an internal attribute used for tests, so it doesn't mark sense to treat it as 'unused'. With this commit, a large source of global untracked state is removed.
This commit is contained in:
parent
b6e334d873
commit
af46699f81
62 changed files with 535 additions and 739 deletions
|
@ -46,7 +46,6 @@ use rustc_middle::ty::subst::{GenericArgKind, Subst};
|
|||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
|
@ -344,7 +343,7 @@ impl UnsafeCode {
|
|||
|
||||
impl EarlyLintPass for UnsafeCode {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
if cx.sess().check_name(attr, sym::allow_internal_unsafe) {
|
||||
if attr.has_name(sym::allow_internal_unsafe) {
|
||||
self.report_unsafe(cx, attr.span, |lint| {
|
||||
lint.build(
|
||||
"`allow_internal_unsafe` allows defining \
|
||||
|
@ -492,12 +491,12 @@ pub struct MissingDoc {
|
|||
|
||||
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
|
||||
|
||||
fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool {
|
||||
fn has_doc(attr: &ast::Attribute) -> bool {
|
||||
if attr.is_doc_comment() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !sess.check_name(attr, sym::doc) {
|
||||
if !attr.has_name(sym::doc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -554,7 +553,7 @@ impl MissingDoc {
|
|||
}
|
||||
|
||||
let attrs = cx.tcx.get_attrs(def_id.to_def_id());
|
||||
let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
|
||||
let has_doc = attrs.iter().any(has_doc);
|
||||
if !has_doc {
|
||||
cx.struct_span_lint(
|
||||
MISSING_DOCS,
|
||||
|
@ -568,10 +567,10 @@ impl MissingDoc {
|
|||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||
fn enter_lint_attrs(&mut self, cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
|
||||
fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
|
||||
let doc_hidden = self.doc_hidden()
|
||||
|| attrs.iter().any(|attr| {
|
||||
cx.sess().check_name(attr, sym::doc)
|
||||
attr.has_name(sym::doc)
|
||||
&& match attr.meta_item_list() {
|
||||
None => false,
|
||||
Some(l) => attr::list_contains_name(&l, sym::hidden),
|
||||
|
@ -595,7 +594,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
|||
}
|
||||
|
||||
let attrs = cx.tcx.hir().attrs(macro_def.hir_id());
|
||||
let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
|
||||
let has_doc = attrs.iter().any(has_doc);
|
||||
if !has_doc {
|
||||
cx.struct_span_lint(
|
||||
MISSING_DOCS,
|
||||
|
@ -999,7 +998,7 @@ impl EarlyLintPass for DeprecatedAttr {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if cx.sess().check_name(attr, sym::no_start) || cx.sess().check_name(attr, sym::crate_id) {
|
||||
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
|
||||
let path_str = pprust::path_to_string(&attr.get_normal_item().path);
|
||||
let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
|
||||
lint_deprecated_attr(cx, attr, &msg, None);
|
||||
|
@ -1028,7 +1027,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
|
|||
|
||||
let span = sugared_span.take().unwrap_or(attr.span);
|
||||
|
||||
if is_doc_comment || cx.sess().check_name(attr, sym::doc) {
|
||||
if is_doc_comment || attr.has_name(sym::doc) {
|
||||
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
|
||||
let mut err = lint.build("unused doc comment");
|
||||
err.span_label(
|
||||
|
@ -1301,7 +1300,7 @@ declare_lint_pass!(
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
|
||||
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
if cx.sess().check_name(attr, sym::feature) {
|
||||
if attr.has_name(sym::feature) {
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
|
||||
|
@ -2771,7 +2770,7 @@ impl ClashingExternDeclarations {
|
|||
overridden_link_name,
|
||||
tcx.get_attrs(fi.def_id.to_def_id())
|
||||
.iter()
|
||||
.find(|at| tcx.sess.check_name(at, sym::link_name))
|
||||
.find(|at| at.has_name(sym::link_name))
|
||||
.unwrap()
|
||||
.span,
|
||||
)
|
||||
|
|
|
@ -236,8 +236,6 @@ impl<'s> LintLevelsBuilder<'s> {
|
|||
Some(lvl) => lvl,
|
||||
};
|
||||
|
||||
self.sess.mark_attr_used(attr);
|
||||
|
||||
let mut metas = unwrap_or!(attr.meta_item_list(), continue);
|
||||
|
||||
if metas.is_empty() {
|
||||
|
|
|
@ -151,8 +151,6 @@ macro_rules! late_lint_passes {
|
|||
// FIXME: Look into regression when this is used as a module lint
|
||||
// May Depend on constants elsewhere
|
||||
UnusedBrokenConst: UnusedBrokenConst,
|
||||
// Uses attr::is_used which is untracked, can't be an incremental module pass.
|
||||
UnusedAttributes: UnusedAttributes::new(),
|
||||
// Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
|
||||
UnstableFeatures: UnstableFeatures,
|
||||
// Tracks state across modules
|
||||
|
|
|
@ -669,9 +669,7 @@ enum FfiResult<'tcx> {
|
|||
}
|
||||
|
||||
crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool {
|
||||
tcx.get_attrs(def.did)
|
||||
.iter()
|
||||
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
|
||||
tcx.get_attrs(def.did).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
|
||||
}
|
||||
|
||||
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
|
||||
|
|
|
@ -4,21 +4,16 @@ use rustc_ast as ast;
|
|||
use rustc_ast::util::parser;
|
||||
use rustc_ast::{ExprKind, StmtKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{pluralize, Applicability};
|
||||
use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::adjustment;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_must_use` lint detects unused result of a type flagged as
|
||||
/// `#[must_use]`.
|
||||
|
@ -308,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|||
descr_post_path: &str,
|
||||
) -> bool {
|
||||
for attr in cx.tcx.get_attrs(def_id).iter() {
|
||||
if cx.sess().check_name(attr, sym::must_use) {
|
||||
if attr.has_name(sym::must_use) {
|
||||
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
|
||||
let msg = format!(
|
||||
"unused {}`{}`{} that must be used",
|
||||
|
@ -382,62 +377,6 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct UnusedAttributes {
|
||||
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
|
||||
}
|
||||
|
||||
impl UnusedAttributes {
|
||||
pub fn new() -> Self {
|
||||
UnusedAttributes { builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP }
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UnusedAttributes {
|
||||
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
debug!("checking attribute: {:?}", attr);
|
||||
|
||||
if attr.is_doc_comment() {
|
||||
return;
|
||||
}
|
||||
|
||||
let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name));
|
||||
|
||||
if let Some(&&(name, ty, ..)) = attr_info {
|
||||
if let AttributeType::AssumedUsed = ty {
|
||||
debug!("{:?} is AssumedUsed", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if !cx.sess().is_attr_used(attr) {
|
||||
debug!("emitting warning for: {:?}", attr);
|
||||
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
||||
// Mark as used to avoid duplicate warnings.
|
||||
cx.sess().mark_attr_used(attr);
|
||||
lint.build("unused attribute").emit()
|
||||
});
|
||||
// Is it a builtin attribute that must be used at the crate level?
|
||||
if attr_info.map_or(false, |(_, ty, ..)| ty == &AttributeType::CrateLevel) {
|
||||
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
||||
let msg = match attr.style {
|
||||
ast::AttrStyle::Outer => {
|
||||
"crate-level attribute should be an inner attribute: add an exclamation \
|
||||
mark: `#![foo]`"
|
||||
}
|
||||
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
||||
};
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
debug!("Attr was used: {:?}", attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum UnusedDelimsCtx {
|
||||
FunctionArg,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue