Skip to content

Commit

Permalink
check rust lints when an unknown lint is detected
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Jan 11, 2024
1 parent e927184 commit b4f3934
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 20 deletions.
10 changes: 8 additions & 2 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,14 @@ lint_unknown_gated_lint =
lint_unknown_lint =
unknown lint: `{$name}`
.suggestion = did you mean
.help = did you mean: `{$replace}`
.suggestion = {$from_rustc ->
[true] a lint with the similar name exists in `rustc` lints
*[false] did you mean
}
.help = {$from_rustc ->
[true] a lint with the similar name exists in `rustc`, did you mean: `{$replace}`
*[false] did you mean: `{$replace}`
}
lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
.help = add `#![register_tool({$tool_name})]` to the crate root
Expand Down
35 changes: 28 additions & 7 deletions compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ struct LintGroup {
pub enum CheckLintNameResult<'a> {
Ok(&'a [LintId]),
/// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
NoLint(Option<Symbol>),
NoLint(Option<(Symbol, bool)>),
/// The lint refers to a tool that has not been registered.
NoTool,
/// The lint has been renamed to a new name.
Expand Down Expand Up @@ -377,7 +377,7 @@ impl LintStore {
debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
let tool_prefix = format!("{tool_name}::");
return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
self.no_lint_suggestion(&complete_name)
self.no_lint_suggestion(&complete_name, tool_name.as_str())
} else {
// 2. The tool isn't currently running, so no lints will be registered.
// To avoid giving a false positive, ignore all unknown lints.
Expand Down Expand Up @@ -419,13 +419,14 @@ impl LintStore {
}
}

fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> {
fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
let name_lower = lint_name.to_lowercase();

if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() {
// First check if the lint name is (partly) in upper case instead of lower case...
return CheckLintNameResult::NoLint(Some(Symbol::intern(&name_lower)));
return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
}

// ...if not, search for lints with a similar name
// Note: find_best_match_for_name depends on the sort order of its input vector.
// To ensure deterministic output, sort elements of the lint_groups hash map.
Expand All @@ -440,8 +441,28 @@ impl LintStore {
groups.sort();
let groups = groups.iter().map(|k| Symbol::intern(k));
let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower()));
let names: Vec<Symbol> = groups.chain(lints).collect();
let suggestion = find_best_match_for_name(&names, Symbol::intern(&name_lower), None);
let mut names: Vec<Symbol> = groups.chain(lints).collect();
// Here, a little bit of extra hack is needed to get the right suggestion,
// we use the lint names from rustc and to mock the tool name,
// if it's selected we strip to the right suggestion
// so we can handle these cases:
// 1. suggest `missing_docs` from rustc for `clippy::missing_docs`
// 2. suggest `dead_code` from rustc for `clippy::dead_cod`
let rustc_names = self
.by_name
.keys()
.map(|k| Symbol::intern(&format!("{tool_name}::{k}")))
.collect::<Vec<_>>();
names.extend(rustc_names.clone());
let suggestion =
find_best_match_for_name(&names, Symbol::intern(&name_lower), None).map(|s| {
if rustc_names.contains(&s) {
let stripped = s.as_str().strip_prefix(&format!("{tool_name}::")).unwrap();
(Symbol::intern(stripped), true)
} else {
(s, false)
}
});
CheckLintNameResult::NoLint(suggestion)
}

Expand All @@ -454,7 +475,7 @@ impl LintStore {
match self.by_name.get(&complete_name) {
None => match self.lint_groups.get(&*complete_name) {
// Now we are sure, that this lint exists nowhere
None => self.no_lint_suggestion(lint_name),
None => self.no_lint_suggestion(lint_name, tool_name),
Some(LintGroup { lint_ids, depr, .. }) => {
// Reaching this would be weird, but let's cover this case anyway
if let Some(LintAlias { name, silent }) = depr {
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
CheckLintNameResult::Renamed(ref replace) => {
let name = lint_name.as_str();
let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
let requested_level = RequestedLevel { level, lint_name };
let requested_level: RequestedLevel<'_> = RequestedLevel { level, lint_name };
let lint = RenamedLintFromCommandLine { name, suggestion, requested_level };
self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
}
Expand All @@ -582,8 +582,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
}
CheckLintNameResult::NoLint(suggestion) => {
let name = lint_name.clone();
let suggestion =
suggestion.map(|replace| UnknownLintSuggestion::WithoutSpan { replace });
let suggestion = suggestion.map(|(replace, from_rustc)| {
UnknownLintSuggestion::WithoutSpan { replace, from_rustc }
});
let requested_level = RequestedLevel { level, lint_name };
let lint = UnknownLintFromCommandLine { name, suggestion, requested_level };
self.emit_lint(UNKNOWN_LINTS, lint);
Expand Down Expand Up @@ -990,8 +991,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
} else {
name.to_string()
};
let suggestion = suggestion.map(|replace| {
UnknownLintSuggestion::WithSpan { suggestion: sp, replace }
let suggestion = suggestion.map(|(replace, from_rustc)| {
UnknownLintSuggestion::WithSpan { suggestion: sp, replace, from_rustc }
});
let lint = UnknownLint { name, suggestion };
self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,9 +1050,10 @@ pub enum UnknownLintSuggestion {
#[primary_span]
suggestion: Span,
replace: Symbol,
from_rustc: bool,
},
#[help(lint_help)]
WithoutSpan { replace: Symbol },
WithoutSpan { replace: Symbol, from_rustc: bool },
}

#[derive(LintDiagnostic)]
Expand Down
4 changes: 3 additions & 1 deletion src/tools/clippy/tests/ui/unknown_clippy_lints.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#[warn(clippy::unnecessary_cast)]
#[warn(clippy::useless_transmute)]
// Shouldn't suggest rustc lint name(`dead_code`)
#[warn(clippy::eq_op)]
#[warn(dead_code)]
// Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`)
#[warn(clippy::unused_self)]
// Shouldn't suggest renamed clippy lint name(`const_static_lifetime`)
#[warn(clippy::redundant_static_lifetimes)]
// issue #118183, should report `missing_docs` from rustc lint
#[warn(missing_docs)]
fn main() {}
2 changes: 2 additions & 0 deletions src/tools/clippy/tests/ui/unknown_clippy_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
#[warn(clippy::unused_colle)]
// Shouldn't suggest renamed clippy lint name(`const_static_lifetime`)
#[warn(clippy::const_static_lifetim)]
// issue #118183, should report `missing_docs` from rustc lint
#[warn(clippy::missing_docs)]
fn main() {}
20 changes: 18 additions & 2 deletions src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ error: unknown lint: `clippy::dead_cod`
--> $DIR/unknown_clippy_lints.rs:11:8
|
LL | #[warn(clippy::dead_cod)]
| ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::eq_op`
| ^^^^^^^^^^^^^^^^
|
help: a lint with the similar name exists in `rustc` lints
|
LL | #[warn(dead_code)]
| ~~~~~~~~~

error: unknown lint: `clippy::unused_colle`
--> $DIR/unknown_clippy_lints.rs:13:8
Expand All @@ -49,5 +54,16 @@ error: unknown lint: `clippy::const_static_lifetim`
LL | #[warn(clippy::const_static_lifetim)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes`

error: aborting due to 8 previous errors
error: unknown lint: `clippy::missing_docs`
--> $DIR/unknown_clippy_lints.rs:17:8
|
LL | #[warn(clippy::missing_docs)]
| ^^^^^^^^^^^^^^^^^^^^
|
help: a lint with the similar name exists in `rustc` lints
|
LL | #[warn(missing_docs)]
| ~~~~~~~~~~~~

error: aborting due to 9 previous errors

5 changes: 5 additions & 0 deletions tests/rustdoc-ui/lints/unknown-renamed-lints.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ error: unknown lint: `rustdoc::intra_doc_link_resolution_failure`
|
LL | #![deny(rustdoc::intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: a lint with the similar name exists in `rustc` lints
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error: aborting due to 8 previous errors

2 changes: 1 addition & 1 deletion tests/ui/lint/issue-83477.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#[allow(rustc::foo::bar::default_hash_types)]
//~^ WARN unknown lint: `rustc::foo::bar::default_hash_types`
//~| HELP did you mean
//~| HELP a lint with the similar name exists in `rustc` lints
//~| SUGGESTION rustc::default_hash_types
#[allow(rustc::foo::default_hash_types)]
//~^ WARN unknown lint: `rustc::foo::default_hash_types`
Expand Down
6 changes: 5 additions & 1 deletion tests/ui/lint/issue-83477.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ warning: unknown lint: `rustc::foo::bar::default_hash_types`
--> $DIR/issue-83477.rs:5:9
|
LL | #[allow(rustc::foo::bar::default_hash_types)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unknown_lints)]` on by default
help: a lint with the similar name exists in `rustc` lints
|
LL | #[allow(rustc::default_hash_types)]
| ~~~~~~~~~~~~~~~~~~~~~~~~~

warning: unknown lint: `rustc::foo::default_hash_types`
--> $DIR/issue-83477.rs:9:9
Expand Down

0 comments on commit b4f3934

Please sign in to comment.