about summary refs log tree commit diff
path: root/compiler/rustc_lint/src/levels.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint/src/levels.rs')
-rw-r--r--compiler/rustc_lint/src/levels.rs202
1 files changed, 119 insertions, 83 deletions
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 527fc117351..f5323c295d0 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,5 +1,5 @@
 use rustc_ast_pretty::pprust;
-use rustc_data_structures::{fx::FxIndexMap, fx::FxIndexSet, sync::Lrc};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
 use rustc_feature::{Features, GateIssue};
 use rustc_hir::HirId;
@@ -31,7 +31,7 @@ use crate::errors::{
     OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
 };
 use crate::fluent_generated as fluent;
-use crate::late::{unerased_lint_store, name_without_tool};
+use crate::late::{unerased_lint_store /*name_without_tool*/};
 use crate::lints::{
     DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
     OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint,
@@ -115,34 +115,41 @@ impl LintLevelSets {
     }
 }
 
-/// Walk the whole crate collecting nodes where lint levels change
-/// (e.g. `#[allow]` attributes), and joins that list with the warn-by-default
-/// (and not allowed in the crate) and CLI lints. The returned value is a tuple
-/// of 1. The lints that will emit (or at least, should run), and 2.
-/// The lints that are allowed at the crate level and will not emit.
-pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(FxIndexSet<String>, FxIndexSet<String>)> {
-    let mut visitor = LintLevelMinimum::new(tcx);
-    visitor.process_opts();
-    tcx.hir().walk_attributes(&mut visitor);
-
+fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
     let store = unerased_lint_store(&tcx.sess);
 
-    let lint_groups = store.get_lint_groups();
-    for group in lint_groups {
-        let binding = group.0.to_lowercase();
-        let group_name = name_without_tool(&binding).to_string();
-        if visitor.lints_that_actually_run.contains(&group_name) {
-            for lint in group.1 {
-                visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string());
-            }
-        } else if visitor.lints_allowed.contains(&group_name) {
-            for lint in &group.1 {
-                visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string());
+    let dont_need_to_run: FxIndexSet<LintId> = store
+        .get_lints()
+        .into_iter()
+        .filter_map(|lint| {
+            if !lint.loadbearing && lint.default_level(tcx.sess.edition()) == Level::Allow {
+                Some(LintId::of(lint))
+            } else {
+                None
             }
-        }
-    }
+        })
+        .collect();
 
-    Lrc::new((visitor.lints_that_actually_run, visitor.lints_allowed))
+    let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
+    visitor.process_opts();
+    tcx.hir().walk_attributes(&mut visitor);
+
+    // let lint_groups = store.get_lint_groups();
+    // for group in lint_groups {
+    //     let binding = group.0.to_lowercase();
+    //     let group_name = name_without_tool(&binding).to_string();
+    //     if visitor.lints_that_actually_run.contains(&group_name) {
+    //         for lint in group.1 {
+    //             visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string());
+    //         }
+    //     } else if visitor.lints_allowed.contains(&group_name) {
+    //         for lint in &group.1 {
+    //             visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string());
+    //         }
+    //     }
+    // }
+
+    visitor.dont_need_to_run
 }
 
 #[instrument(level = "trace", skip(tcx), ret)]
@@ -336,39 +343,29 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
 ///
 /// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
 /// uses #[warn(lint)], this visitor will set that lint level as `Warn`
-struct LintLevelMinimum<'tcx> {
+struct LintLevelMaximum<'tcx> {
     tcx: TyCtxt<'tcx>,
     /// The actual list of detected lints.
-    lints_that_actually_run: FxIndexSet<String>,
-    lints_allowed: FxIndexSet<String>,
+    dont_need_to_run: FxIndexSet<LintId>,
 }
 
-impl<'tcx> LintLevelMinimum<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
-        let mut lints_that_actually_run = FxIndexSet::default();
-        lints_that_actually_run.reserve(230);
-        let mut lints_allowed = FxIndexSet::default();
-        lints_allowed.reserve(100);
-        Self {
-            tcx,
-            // That magic number is the current number of lints + some more for possible future lints
-            lints_that_actually_run,
-            lints_allowed,
-        }
-    }
-
+impl<'tcx> LintLevelMaximum<'tcx> {
     fn process_opts(&mut self) {
-        for (lint, level) in &self.tcx.sess.opts.lint_opts {
-            if *level == Level::Allow {
-                self.lints_allowed.insert(lint.clone());
-            } else {
-                self.lints_that_actually_run.insert(lint.to_string());
+        let store = unerased_lint_store(self.tcx.sess);
+        for (lint_group, level) in &self.tcx.sess.opts.lint_opts {
+            if *level != Level::Allow {
+                let Ok(lints) = store.find_lints(lint_group) else {
+                    return;
+                };
+                for lint in lints {
+                    self.dont_need_to_run.swap_remove(&lint);
+                }
             }
         }
     }
 }
 
-impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> {
+impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
     type NestedFilter = nested_filter::All;
 
     fn nested_visit_map(&mut self) -> Self::Map {
@@ -376,42 +373,82 @@ impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> {
     }
 
     fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) {
-        if let Some(meta) = attribute.meta() {
-            if [sym::warn, sym::deny, sym::forbid, sym::expect]
-                .iter()
-                .any(|kind| meta.has_name(*kind))
-            {
+        match Level::from_attr(attribute) {
+            Some(
+                Level::Warn
+                | Level::Deny
+                | Level::Forbid
+                | Level::Expect(..)
+                | Level::ForceWarn(..),
+            ) => {
+                let store = unerased_lint_store(self.tcx.sess);
+                let Some(meta) = attribute.meta() else { return };
                 // SAFETY: Lint attributes are always a metalist inside a
                 // metalist (even with just one lint).
-                for meta_list in meta.meta_item_list().unwrap() {
-                    // If it's a tool lint (e.g. clippy::my_clippy_lint)
-                    if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
-                        if meta_item.path.segments.len() == 1 {
-                            self.lints_that_actually_run.insert(
-                                // SAFETY: Lint attributes can only have literals
-                                meta_list.ident().unwrap().name.as_str().to_string(),
-                            );
-                        } else {
-                            self.lints_that_actually_run
-                                .insert(meta_item.path.segments[1].ident.name.as_str().to_string());
-                        }
-                    }
-                }
-            // We handle #![allow]s differently, as these remove checking rather than adding.
-            } else if meta.has_name(sym::allow)
-                && let ast::AttrStyle::Inner = attribute.style
-            {
-                for meta_list in meta.meta_item_list().unwrap() {
-                    // If it's a tool lint (e.g. clippy::my_clippy_lint)
-                    if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
-                        if meta_item.path.segments.len() == 1 {
-                            self.lints_allowed.insert(meta_list.name_or_empty().as_str().to_string());
-                        } else {
-                            self.lints_allowed
-                                .insert(meta_item.path.segments[1].ident.name.as_str().to_string());
-                        }
+                let Some(meta_item_list) = meta.meta_item_list() else { return };
+
+                for meta_list in meta_item_list {
+                    // Convert Path to String
+                    let Some(meta_item) = meta_list.meta_item() else { return };
+                    let ident: &str = &meta_item
+                        .path
+                        .segments
+                        .iter()
+                        .map(|segment| segment.ident.as_str())
+                        .collect::<Vec<&str>>()
+                        .join("::");
+                    let Ok(lints) = store.find_lints(
+                        // SAFETY: Lint attributes can only have literals
+                        ident,
+                    ) else {
+                        return;
+                    };
+                    for lint in lints {
+                        self.dont_need_to_run.swap_remove(&lint);
                     }
+                    // // If it's a tool lint (e.g. clippy::my_clippy_lint)
+                    // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
+                    //     if meta_item.path.segments.len() == 1 {
+                    //         let Ok(lints) = store.find_lints(
+                    //             // SAFETY: Lint attributes can only have literals
+                    //             meta_list.ident().unwrap().name.as_str(),
+                    //         ) else {
+                    //             return;
+                    //         };
+                    //         for lint in lints {
+                    //             dbg!("LINT REMOVED", &lint);
+                    //             self.dont_need_to_run.swap_remove(&lint);
+                    //         }
+                    //     } else {
+                    //         let Ok(lints) = store.find_lints(
+                    //             // SAFETY: Lint attributes can only have literals
+                    //             meta_item.path.segments[1].ident.name.as_str(),
+                    //         ) else {
+                    //             return;
+                    //         };
+                    //         for lint in lints {
+                    //             dbg!("LINT REMOVED", &lint);
+                    //             self.dont_need_to_run.swap_remove(&lint);
+                    //         }
+                    //     }
                 }
+                // We handle #![allow]s differently, as these remove checking rather than adding.
+            } // Some(Level::Allow) if ast::AttrStyle::Inner == attribute.style => {
+            //     for meta_list in meta.meta_item_list().unwrap() {
+            //         // If it's a tool lint (e.g. clippy::my_clippy_lint)
+            //         if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
+            //             if meta_item.path.segments.len() == 1 {
+            //                 self.lints_allowed
+            //                     .insert(meta_list.name_or_empty().as_str().to_string());
+            //             } else {
+            //                 self.lints_allowed
+            //                     .insert(meta_item.path.segments[1].ident.name.as_str().to_string());
+            //             }
+            //         }
+            //     }
+            // }
+            _ => {
+                return;
             }
         }
     }
@@ -1047,8 +1084,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers =
-        Providers { shallow_lint_levels_on, lints_that_can_emit, ..*providers };
+    *providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers };
 }
 
 pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {