diff options
| author | blyxyas <blyxyas@gmail.com> | 2023-11-13 14:35:37 +0100 |
|---|---|---|
| committer | blyxyas <blyxyas@gmail.com> | 2024-10-19 16:19:44 +0200 |
| commit | b4da0585959ec8b2c111bc9f8fd0e34e78c7f260 (patch) | |
| tree | ca92dd0b22c057b4c1632a91e8967126124b2c74 /compiler/rustc_lint/src/late.rs | |
| parent | c926476d013fbb2ca43bd5259d0a7228009a9cb2 (diff) | |
| download | rust-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.rs | 45 |
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) +} |
