about summary refs log tree commit diff
path: root/compiler/rustc_lint/src/late.rs
diff options
context:
space:
mode:
authorblyxyas <blyxyas@gmail.com>2023-11-13 14:35:37 +0100
committerblyxyas <blyxyas@gmail.com>2024-10-19 16:19:44 +0200
commitb4da0585959ec8b2c111bc9f8fd0e34e78c7f260 (patch)
treeca92dd0b22c057b4c1632a91e8967126124b2c74 /compiler/rustc_lint/src/late.rs
parentc926476d013fbb2ca43bd5259d0a7228009a9cb2 (diff)
downloadrust-b4da0585959ec8b2c111bc9f8fd0e34e78c7f260.tar.gz
rust-b4da0585959ec8b2c111bc9f8fd0e34e78c7f260.zip
Do not run lints that cannot emit
Before this change, adding a lint was a difficult matter
because it always had some overhead involved. This was
because all lints would run, no matter their default level,
or if the user had #![allow]ed them. This PR changes that
Diffstat (limited to 'compiler/rustc_lint/src/late.rs')
-rw-r--r--compiler/rustc_lint/src/late.rs45
1 files changed, 40 insertions, 5 deletions
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 6d5903ac467..ccd06ba612b 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -326,6 +326,9 @@ impl LintPass for RuntimeCombinedLateLintPass<'_, '_> {
     fn name(&self) -> &'static str {
         panic!()
     }
+    fn get_lints(&self) -> crate::LintVec {
+        panic!()
+    }
 }
 
 macro_rules! impl_late_lint_pass {
@@ -361,13 +364,38 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
     // Note: `passes` is often empty. In that case, it's faster to run
     // `builtin_lints` directly rather than bundling it up into the
     // `RuntimeCombinedLateLintPass`.
-    let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes;
-    if late_module_passes.is_empty() {
+    let store = unerased_lint_store(tcx.sess);
+
+    if store.late_module_passes.is_empty() {
         late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
     } else {
-        let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
-        passes.push(Box::new(builtin_lints));
-        let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+        let passes: Vec<_> =
+            store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
+
+        // Filter unused lints
+        let (lints_to_emit, lints_allowed) = &**tcx.lints_that_can_emit(());
+        // let lints_to_emit = &lints_that_can_emit.0;
+        // let lints_allowed = &lints_that_can_emit.1;
+
+        // Now, we'll filtered passes in a way that discards any lint that won't trigger.
+        // If any lint is a given pass is detected to be emitted, we will keep that pass.
+        // Otherwise, we don't
+        let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
+            .into_iter()
+            .filter(|pass| {
+                let pass = LintPass::get_lints(pass);
+                pass.iter().any(|&lint| {
+                    let lint_name = name_without_tool(&lint.name.to_lowercase()).to_string();
+                    lints_to_emit.contains(&lint_name)
+                        || (!lints_allowed.contains(&lint_name)
+                            && lint.default_level != crate::Level::Allow)
+                })
+            })
+            .collect();
+
+        filtered_passes.push(Box::new(builtin_lints));
+
+        let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
         late_lint_mod_inner(tcx, module_def_id, context, pass);
     }
 }
@@ -454,3 +482,10 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
         },
     );
 }
+
+/// Format name ignoring the name, useful for filtering non-used lints.
+/// For example, 'clippy::my_lint' will turn into 'my_lint'
+pub(crate) fn name_without_tool(name: &str) -> &str {
+    // Doing some calculations here to account for those separators
+    name.rsplit("::").next().unwrap_or(name)
+}