diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0f40324acb11..c4df0acbbb0f 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -354,10 +354,23 @@ impl LintStore { lint_name.to_string() }; // If the lint was scoped with `tool::` check if the tool lint exists - if tool_name.is_some() { + if let Some(tool_name) = tool_name { match self.by_name.get(&complete_name) { None => match self.lint_groups.get(&*complete_name) { - None => return CheckLintNameResult::Tool(Err((None, String::new()))), + // If the lint isn't registered, there are two possibilities: + None => { + // 1. The tool is currently running, so this lint really doesn't exist. + // FIXME: should this handle tools that never register a lint, like rustfmt? + tracing::debug!("lints={:?}", self.by_name.keys().collect::>()); + 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) + } else { + // 2. The tool isn't currently running, so no lints will be registered. + // To avoid giving a false positive, ignore all unknown lints. + CheckLintNameResult::Tool(Err((None, String::new()))) + }; + } Some(LintGroup { lint_ids, .. }) => { return CheckLintNameResult::Tool(Ok(&lint_ids)); } @@ -398,6 +411,15 @@ impl LintStore { } } + fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> { + let symbols = self.by_name.keys().map(|name| Symbol::intern(&name)).collect::>(); + + let suggestion = + find_best_match_for_name(&symbols, Symbol::intern(&lint_name.to_lowercase()), None); + + CheckLintNameResult::NoLint(suggestion) + } + fn check_tool_name_for_backwards_compat( &self, lint_name: &str, @@ -407,18 +429,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 => { - let symbols = - self.by_name.keys().map(|name| Symbol::intern(&name)).collect::>(); - - let suggestion = find_best_match_for_name( - &symbols, - Symbol::intern(&lint_name.to_lowercase()), - None, - ); - - CheckLintNameResult::NoLint(suggestion) - } + None => self.no_lint_suggestion(lint_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 { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 37bdc878b16c..fc8f84461f99 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -381,6 +381,11 @@ impl<'s> LintLevelsBuilder<'s> { src, Some(li.span().into()), |lint| { + let name = if let Some(tool_name) = tool_name { + format!("{}::{}", tool_name, name) + } else { + name.to_string() + }; let mut db = lint.build(&format!("unknown lint: `{}`", name)); if let Some(suggestion) = suggestion { db.span_suggestion(