mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Follow review comments (optimize the filtering)
This commit is contained in:
parent
edc6577627
commit
71b4d108c7
@ -972,7 +972,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
|||||||
tcx.ensure().check_mod_privacy(module);
|
tcx.ensure().check_mod_privacy(module);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
} // { sess.time("mir_checking", || { tcx.hir().mir_for }) }
|
||||||
);
|
);
|
||||||
|
|
||||||
// This check has to be run after all lints are done processing. We don't
|
// This check has to be run after all lints are done processing. We don't
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
//! If you define a new `LateLintPass`, you will also need to add it to the
|
//! If you define a new `LateLintPass`, you will also need to add it to the
|
||||||
//! `late_lint_methods!` invocation in `lib.rs`.
|
//! `late_lint_methods!` invocation in `lib.rs`.
|
||||||
|
|
||||||
|
use std::default::Default;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use ast::token::TokenKind;
|
use ast::token::TokenKind;
|
||||||
@ -73,12 +74,10 @@ use crate::{
|
|||||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
|
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
|
||||||
fluent_generated as fluent,
|
fluent_generated as fluent,
|
||||||
};
|
};
|
||||||
|
// use std::fmt::Write;
|
||||||
use std::default::Default;
|
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
// hardwired lints from rustc_lint_defs
|
// hardwired lints from rustc_lint_defs
|
||||||
pub use rustc_session::lint::builtin::*;
|
// pub use rustc_session::lint::builtin::*;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `while_true` lint detects `while true { }`.
|
/// The `while_true` lint detects `while true { }`.
|
||||||
|
@ -24,13 +24,12 @@ use rustc_hir::def_id::{LocalDefId, LocalModDefId};
|
|||||||
use rustc_hir::{HirId, intravisit as hir_visit};
|
use rustc_hir::{HirId, intravisit as hir_visit};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_session::Session;
|
use rustc_session::{Session, lint::{LintPass, builtin::HardwiredLints}};
|
||||||
use rustc_session::lint::LintPass;
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::passes::LateLintPassObject;
|
use crate::passes::LateLintPassObject;
|
||||||
use crate::{LateContext, LateLintPass, LintStore};
|
use crate::{LateContext, LateLintPass, LintId, LintStore};
|
||||||
|
|
||||||
/// Extract the [`LintStore`] from [`Session`].
|
/// Extract the [`LintStore`] from [`Session`].
|
||||||
///
|
///
|
||||||
@ -371,29 +370,24 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
|
|||||||
} else {
|
} else {
|
||||||
let passes: Vec<_> =
|
let passes: Vec<_> =
|
||||||
store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
|
store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
|
||||||
|
|
||||||
// Filter unused lints
|
// Filter unused lints
|
||||||
let (lints_that_actually_run, lints_allowed) = &**tcx.lints_that_can_emit(());
|
let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());
|
||||||
// let lints_that_actually_run = &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
|
let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|pass| {
|
.filter(|pass| {
|
||||||
let pass = LintPass::get_lints(pass);
|
let lints = LintPass::get_lints(pass);
|
||||||
pass.iter().any(|&lint| {
|
if lints.is_empty() {
|
||||||
let lint_name = name_without_tool(&lint.name.to_lowercase()).to_string();
|
true
|
||||||
lints_that_actually_run.contains(&lint_name)
|
} else {
|
||||||
|| (!lints_allowed.contains(&lint_name)
|
lints
|
||||||
&& lint.default_level != crate::Level::Allow)
|
.iter()
|
||||||
})
|
.any(|lint| !lints_that_dont_need_to_run.contains(&LintId::of(lint)))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
filtered_passes.push(Box::new(builtin_lints));
|
filtered_passes.push(Box::new(builtin_lints));
|
||||||
|
filtered_passes.push(Box::new(HardwiredLints));
|
||||||
|
|
||||||
let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
|
let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
|
||||||
late_lint_mod_inner(tcx, module_def_id, context, pass);
|
late_lint_mod_inner(tcx, module_def_id, context, pass);
|
||||||
@ -426,7 +420,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
|
|||||||
|
|
||||||
fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||||
// Note: `passes` is often empty.
|
// Note: `passes` is often empty.
|
||||||
let mut passes: Vec<_> =
|
let passes: Vec<_> =
|
||||||
unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
|
unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
|
||||||
|
|
||||||
if passes.is_empty() {
|
if passes.is_empty() {
|
||||||
@ -444,7 +438,30 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
|||||||
only_module: false,
|
only_module: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
|
let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());
|
||||||
|
|
||||||
|
// dbg!(&lints_that_dont_need_to_run);
|
||||||
|
let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
|
||||||
|
.into_iter()
|
||||||
|
.filter(|pass| {
|
||||||
|
let lints = LintPass::get_lints(pass);
|
||||||
|
!lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint)))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
filtered_passes.push(Box::new(HardwiredLints));
|
||||||
|
|
||||||
|
// let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
|
||||||
|
// .into_iter()
|
||||||
|
// .filter(|pass| {
|
||||||
|
// let lints = LintPass::get_lints(pass);
|
||||||
|
// lints.iter()
|
||||||
|
// .any(|lint|
|
||||||
|
// !lints_that_dont_need_to_run.contains(&LintId::of(lint)))
|
||||||
|
// }).collect();
|
||||||
|
//
|
||||||
|
|
||||||
|
let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
|
||||||
late_lint_crate_inner(tcx, context, pass);
|
late_lint_crate_inner(tcx, context, pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,10 +499,3 @@ 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)
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use rustc_ast_pretty::pprust;
|
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_errors::{Diag, LintDiagnostic, MultiSpan};
|
||||||
use rustc_feature::{Features, GateIssue};
|
use rustc_feature::{Features, GateIssue};
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
@ -31,7 +31,7 @@ use crate::errors::{
|
|||||||
OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
|
OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
|
||||||
};
|
};
|
||||||
use crate::fluent_generated as fluent;
|
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::{
|
use crate::lints::{
|
||||||
DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
|
DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
|
||||||
OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint,
|
OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint,
|
||||||
@ -115,34 +115,41 @@ impl LintLevelSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk the whole crate collecting nodes where lint levels change
|
fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
|
||||||
/// (e.g. `#[allow]` attributes), and joins that list with the warn-by-default
|
let store = unerased_lint_store(&tcx.sess);
|
||||||
/// (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.
|
let dont_need_to_run: FxIndexSet<LintId> = store
|
||||||
/// The lints that are allowed at the crate level and will not emit.
|
.get_lints()
|
||||||
pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(FxIndexSet<String>, FxIndexSet<String>)> {
|
.into_iter()
|
||||||
let mut visitor = LintLevelMinimum::new(tcx);
|
.filter_map(|lint| {
|
||||||
|
if !lint.loadbearing && lint.default_level(tcx.sess.edition()) == Level::Allow {
|
||||||
|
Some(LintId::of(lint))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
|
||||||
visitor.process_opts();
|
visitor.process_opts();
|
||||||
tcx.hir().walk_attributes(&mut visitor);
|
tcx.hir().walk_attributes(&mut visitor);
|
||||||
|
|
||||||
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 lint_groups = store.get_lint_groups();
|
visitor.dont_need_to_run
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Lrc::new((visitor.lints_that_actually_run, visitor.lints_allowed))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(tcx), ret)]
|
#[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
|
/// 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`
|
/// uses #[warn(lint)], this visitor will set that lint level as `Warn`
|
||||||
struct LintLevelMinimum<'tcx> {
|
struct LintLevelMaximum<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
/// The actual list of detected lints.
|
/// The actual list of detected lints.
|
||||||
lints_that_actually_run: FxIndexSet<String>,
|
dont_need_to_run: FxIndexSet<LintId>,
|
||||||
lints_allowed: FxIndexSet<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
fn process_opts(&mut self) {
|
||||||
for (lint, level) in &self.tcx.sess.opts.lint_opts {
|
let store = unerased_lint_store(self.tcx.sess);
|
||||||
if *level == Level::Allow {
|
for (lint_group, level) in &self.tcx.sess.opts.lint_opts {
|
||||||
self.lints_allowed.insert(lint.clone());
|
if *level != Level::Allow {
|
||||||
} else {
|
let Ok(lints) = store.find_lints(lint_group) else {
|
||||||
self.lints_that_actually_run.insert(lint.to_string());
|
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;
|
type NestedFilter = nested_filter::All;
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> Self::Map {
|
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) {
|
fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) {
|
||||||
if let Some(meta) = attribute.meta() {
|
match Level::from_attr(attribute) {
|
||||||
if [sym::warn, sym::deny, sym::forbid, sym::expect]
|
Some(
|
||||||
.iter()
|
Level::Warn
|
||||||
.any(|kind| meta.has_name(*kind))
|
| 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
|
// SAFETY: Lint attributes are always a metalist inside a
|
||||||
// metalist (even with just one lint).
|
// metalist (even with just one lint).
|
||||||
for meta_list in meta.meta_item_list().unwrap() {
|
let Some(meta_item_list) = meta.meta_item_list() else { return };
|
||||||
// If it's a tool lint (e.g. clippy::my_clippy_lint)
|
|
||||||
if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
|
for meta_list in meta_item_list {
|
||||||
if meta_item.path.segments.len() == 1 {
|
// Convert Path to String
|
||||||
self.lints_that_actually_run.insert(
|
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
|
// SAFETY: Lint attributes can only have literals
|
||||||
meta_list.ident().unwrap().name.as_str().to_string(),
|
ident,
|
||||||
);
|
) else {
|
||||||
} else {
|
return;
|
||||||
self.lints_that_actually_run
|
};
|
||||||
.insert(meta_item.path.segments[1].ident.name.as_str().to_string());
|
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.
|
// We handle #![allow]s differently, as these remove checking rather than adding.
|
||||||
} else if meta.has_name(sym::allow)
|
} // Some(Level::Allow) if ast::AttrStyle::Inner == attribute.style => {
|
||||||
&& 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)
|
||||||
for meta_list in meta.meta_item_list().unwrap() {
|
// if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
|
||||||
// If it's a tool lint (e.g. clippy::my_clippy_lint)
|
// if meta_item.path.segments.len() == 1 {
|
||||||
if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list {
|
// self.lints_allowed
|
||||||
if meta_item.path.segments.len() == 1 {
|
// .insert(meta_list.name_or_empty().as_str().to_string());
|
||||||
self.lints_allowed.insert(meta_list.name_or_empty().as_str().to_string());
|
// } else {
|
||||||
} else {
|
// self.lints_allowed
|
||||||
self.lints_allowed
|
// .insert(meta_item.path.segments[1].ident.name.as_str().to_string());
|
||||||
.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) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
*providers =
|
*providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers };
|
||||||
Providers { shallow_lint_levels_on, lints_that_can_emit, ..*providers };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
|
pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
|
||||||
|
@ -199,7 +199,6 @@ late_lint_methods!(
|
|||||||
ForLoopsOverFallibles: ForLoopsOverFallibles,
|
ForLoopsOverFallibles: ForLoopsOverFallibles,
|
||||||
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
|
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
|
||||||
DropForgetUseless: DropForgetUseless,
|
DropForgetUseless: DropForgetUseless,
|
||||||
HardwiredLints: HardwiredLints,
|
|
||||||
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
||||||
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
||||||
InvalidFromUtf8: InvalidFromUtf8,
|
InvalidFromUtf8: InvalidFromUtf8,
|
||||||
@ -280,6 +279,7 @@ fn register_builtins(store: &mut LintStore) {
|
|||||||
store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
|
store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
|
||||||
store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
|
store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
|
||||||
store.register_lints(&foreign_modules::get_lints());
|
store.register_lints(&foreign_modules::get_lints());
|
||||||
|
store.register_lints(&HardwiredLints::default().get_lints());
|
||||||
|
|
||||||
add_lint_group!(
|
add_lint_group!(
|
||||||
"nonstandard_style",
|
"nonstandard_style",
|
||||||
|
@ -70,7 +70,18 @@ macro_rules! declare_late_lint_pass {
|
|||||||
// for all the `check_*` methods.
|
// for all the `check_*` methods.
|
||||||
late_lint_methods!(declare_late_lint_pass, []);
|
late_lint_methods!(declare_late_lint_pass, []);
|
||||||
|
|
||||||
impl LateLintPass<'_> for HardwiredLints {}
|
impl LateLintPass<'_> for HardwiredLints {
|
||||||
|
fn check_fn(
|
||||||
|
&mut self,
|
||||||
|
_: &LateContext<'_>,
|
||||||
|
_: rustc_hir::intravisit::FnKind<'_>,
|
||||||
|
_: &'_ rustc_hir::FnDecl<'_>,
|
||||||
|
_: &'_ rustc_hir::Body<'_>,
|
||||||
|
_: rustc_span::Span,
|
||||||
|
_: rustc_span::def_id::LocalDefId,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! expand_combined_late_lint_pass_method {
|
macro_rules! expand_combined_late_lint_pass_method {
|
||||||
|
@ -1026,7 +1026,7 @@ pub(crate) struct UnusedParens {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UnusedParens {
|
impl Default for UnusedParens {
|
||||||
fpub(crate) fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() }
|
Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,6 @@ use rustc_span::edition::Edition;
|
|||||||
use crate::{FutureIncompatibilityReason, declare_lint, declare_lint_pass};
|
use crate::{FutureIncompatibilityReason, declare_lint, declare_lint_pass};
|
||||||
|
|
||||||
declare_lint_pass! {
|
declare_lint_pass! {
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
|
||||||
/// that are used by other parts of the compiler.
|
|
||||||
HardwiredLints => [
|
HardwiredLints => [
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||||
@ -403,7 +401,8 @@ declare_lint! {
|
|||||||
/// `panic!` or `unreachable!` macro instead in case the panic is intended.
|
/// `panic!` or `unreachable!` macro instead in case the panic is intended.
|
||||||
pub UNCONDITIONAL_PANIC,
|
pub UNCONDITIONAL_PANIC,
|
||||||
Deny,
|
Deny,
|
||||||
"operation will cause a panic at runtime"
|
"operation will cause a panic at runtime",
|
||||||
|
[loadbearing: true]
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -29,6 +29,7 @@ use rustc_hir::def_id::{
|
|||||||
use rustc_hir::lang_items::{LangItem, LanguageItems};
|
use rustc_hir::lang_items::{LangItem, LanguageItems};
|
||||||
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
|
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
|
use rustc_lint_defs::LintId;
|
||||||
use rustc_macros::rustc_queries;
|
use rustc_macros::rustc_queries;
|
||||||
use rustc_query_system::ich::StableHashingContext;
|
use rustc_query_system::ich::StableHashingContext;
|
||||||
use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached};
|
use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached};
|
||||||
@ -422,7 +423,7 @@ rustc_queries! {
|
|||||||
desc { "computing `#[expect]`ed lints in this crate" }
|
desc { "computing `#[expect]`ed lints in this crate" }
|
||||||
}
|
}
|
||||||
|
|
||||||
query lints_that_can_emit(_: ()) -> &'tcx Lrc<(FxIndexSet<String>, FxIndexSet<String>)> {
|
query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet<LintId> {
|
||||||
arena_cache
|
arena_cache
|
||||||
desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" }
|
desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" }
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,7 @@ pub struct Session {
|
|||||||
/// errors.
|
/// errors.
|
||||||
pub ctfe_backtrace: Lock<CtfeBacktrace>,
|
pub ctfe_backtrace: Lock<CtfeBacktrace>,
|
||||||
|
|
||||||
|
// pub force_ctfe: bool,
|
||||||
/// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a
|
/// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a
|
||||||
/// const check, optionally with the relevant feature gate. We use this to
|
/// const check, optionally with the relevant feature gate. We use this to
|
||||||
/// warn about unleashing, but with a single diagnostic instead of dozens that
|
/// warn about unleashing, but with a single diagnostic instead of dozens that
|
||||||
|
@ -3,7 +3,7 @@ use std::fmt;
|
|||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
|
use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
|
||||||
use rustc_ast::{InlineAsm, Item, ItemKind};
|
use rustc_ast::{InlineAsm, Item, ItemKind};
|
||||||
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintPass, LintContext};
|
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::asm::InlineAsmArch;
|
use rustc_target::asm::InlineAsmArch;
|
||||||
|
@ -8,30 +8,44 @@ use core::ops::ControlFlow;
|
|||||||
use rustc_ast::ast::Attribute;
|
use rustc_ast::ast::Attribute;
|
||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl};
|
use rustc_hir::{Body, Expr, ExprKind, FnDecl};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::Level::Allow;
|
||||||
|
use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
|
||||||
use rustc_session::impl_lint_pass;
|
use rustc_session::impl_lint_pass;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::{Span, sym};
|
use rustc_span::{Span, sym};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
use crate::LintInfo;
|
||||||
/// ### What it does
|
|
||||||
/// Checks for methods with high cognitive complexity.
|
pub static COGNITIVE_COMPLEXITY: &Lint = &Lint {
|
||||||
///
|
name: &"clippy::COGNITIVE_COMPLEXITY",
|
||||||
/// ### Why is this bad?
|
default_level: Allow,
|
||||||
/// Methods of high cognitive complexity tend to be hard to
|
desc: "functions that should be split up into multiple functions",
|
||||||
/// both read and maintain. Also LLVM will tend to optimize small methods better.
|
edition_lint_opts: None,
|
||||||
///
|
report_in_external_macro: true,
|
||||||
/// ### Known problems
|
future_incompatible: None,
|
||||||
/// Sometimes it's hard to find a way to reduce the
|
is_externally_loaded: true,
|
||||||
/// complexity.
|
crate_level_only: false,
|
||||||
///
|
loadbearing: true,
|
||||||
/// ### Example
|
..Lint::default_fields_for_macro()
|
||||||
/// You'll see it when you get the warning.
|
};
|
||||||
#[clippy::version = "1.35.0"]
|
pub(crate) static COGNITIVE_COMPLEXITY_INFO: &'static LintInfo = &LintInfo {
|
||||||
pub COGNITIVE_COMPLEXITY,
|
lint: &COGNITIVE_COMPLEXITY,
|
||||||
nursery,
|
category: crate::LintCategory::Nursery,
|
||||||
"functions that should be split up into multiple functions"
|
explanation: r"### What it does
|
||||||
}
|
Checks for methods with high cognitive complexity.
|
||||||
|
|
||||||
|
### Why is this bad?
|
||||||
|
Methods of high cognitive complexity tend to be hard to both read and maintain.
|
||||||
|
Also LLVM will tend to optimize small methods better.
|
||||||
|
|
||||||
|
### Known problems
|
||||||
|
Sometimes it's hard to find a way to reduce the complexity.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
You'll see it when you get the warning.",
|
||||||
|
version: Some("1.35.0"),
|
||||||
|
location: "#L0",
|
||||||
|
};
|
||||||
|
|
||||||
pub struct CognitiveComplexity {
|
pub struct CognitiveComplexity {
|
||||||
limit: LimitStack,
|
limit: LimitStack,
|
||||||
|
54
src/tools/clippy/clippy_lints/src/ctfe.rs
Normal file
54
src/tools/clippy/clippy_lints/src/ctfe.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
use rustc_hir::intravisit::FnKind;
|
||||||
|
use rustc_hir::{Body, FnDecl};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_session::declare_lint_pass;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for comparisons where one side of the relation is
|
||||||
|
/// either the minimum or maximum value for its type and warns if it involves a
|
||||||
|
/// case that is always true or always false. Only integer and boolean types are
|
||||||
|
/// checked.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// An expression like `min <= x` may misleadingly imply
|
||||||
|
/// that it is possible for `x` to be less than the minimum. Expressions like
|
||||||
|
/// `max < x` are probably mistakes.
|
||||||
|
///
|
||||||
|
/// ### Known problems
|
||||||
|
/// For `usize` the size of the current compile target will
|
||||||
|
/// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
|
||||||
|
/// a comparison to detect target pointer width will trigger this lint. One can
|
||||||
|
/// use `mem::sizeof` and compare its value or conditional compilation
|
||||||
|
/// attributes
|
||||||
|
/// like `#[cfg(target_pointer_width = "64")] ..` instead.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// let vec: Vec<isize> = Vec::new();
|
||||||
|
/// if vec.len() <= 0 {}
|
||||||
|
/// if 100 > i32::MAX {}
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.82.0"]
|
||||||
|
pub CLIPPY_CTFE,
|
||||||
|
correctness,
|
||||||
|
"a comparison with a maximum or minimum value that is always true or false"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] }
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
|
||||||
|
fn check_fn(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
_: FnKind<'tcx>,
|
||||||
|
_: &'tcx FnDecl<'tcx>,
|
||||||
|
_: &'tcx Body<'tcx>,
|
||||||
|
_: Span,
|
||||||
|
defid: LocalDefId,
|
||||||
|
) {
|
||||||
|
cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint
|
||||||
|
}
|
||||||
|
}
|
@ -65,6 +65,7 @@ extern crate clippy_utils;
|
|||||||
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
|
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub mod ctfe; // VERY important lint (rust#125116)
|
||||||
pub mod declared_lints;
|
pub mod declared_lints;
|
||||||
pub mod deprecated_lints;
|
pub mod deprecated_lints;
|
||||||
|
|
||||||
@ -605,6 +606,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
|
||||||
|
|
||||||
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
|
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
|
||||||
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
|
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
|
||||||
store.register_late_pass(|_| Box::new(utils::author::Author));
|
store.register_late_pass(|_| Box::new(utils::author::Author));
|
||||||
|
@ -12,7 +12,7 @@ use rustc_span::symbol::{Ident, Symbol};
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::fmt::{Display, Formatter, Write as _};
|
use std::fmt::{Display, Formatter, Write as _};
|
||||||
|
|
||||||
declare_clippy_lint!{
|
declare_lint_pass!(
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Generates clippy code that detects the offending pattern
|
/// Generates clippy code that detects the offending pattern
|
||||||
///
|
///
|
||||||
@ -44,13 +44,8 @@ declare_clippy_lint!{
|
|||||||
/// // report your lint here
|
/// // report your lint here
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.0.0"]
|
Author => []
|
||||||
pub AUTHOR,
|
);
|
||||||
internal,
|
|
||||||
"The author lint, see documentation at <https://doc.rust-lang.org/nightly/clippy/development/adding_lints.html#author-lint>"
|
|
||||||
};
|
|
||||||
|
|
||||||
declare_lint_pass! { Author => [AUTHOR] }
|
|
||||||
|
|
||||||
/// Writes a line of output with indentation added
|
/// Writes a line of output with indentation added
|
||||||
macro_rules! out {
|
macro_rules! out {
|
||||||
@ -803,3 +798,4 @@ fn path_to_string(path: &QPath<'_>) -> Result<String, ()> {
|
|||||||
inner(&mut s, path)?;
|
inner(&mut s, path)?;
|
||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod author;
|
||||||
pub mod dump_hir;
|
pub mod dump_hir;
|
||||||
pub mod format_args_collector;
|
pub mod format_args_collector;
|
||||||
#[cfg(feature = "internal")]
|
#[cfg(feature = "internal")]
|
||||||
|
Loading…
Reference in New Issue
Block a user