Auto merge of #80524 - jyn514:unknown-tool-lints, r=flip1995,matthewjasper
Don't make tools responsible for checking unknown and renamed lints Previously, clippy (and any other tool emitting lints) had to have their own separate UNKNOWN_LINTS pass, because the compiler assumed any tool lint could be valid. Now, as long as any lint starting with the tool prefix exists, the compiler will warn when an unknown lint is present. This may interact with the unstable `tool_lint` feature, which I don't entirely understand, but it will take the burden off those external tools to add their own lint pass, which seems like a step in the right direction to me. - Don't mark `ineffective_unstable_trait_impl` as an internal lint - Use clippy's more advanced lint suggestions - Deprecate the `UNKNOWN_CLIPPY_LINTS` pass (and make it a no-op) - Say 'unknown lint `clippy::x`' instead of 'unknown lint x' This is tested by existing clippy tests. When https://github.com/rust-lang/rust/pull/80527 merges, it will also be tested in rustdoc tests. AFAIK there is no way to test this with rustc directly.
This commit is contained in:
commit
1f0fc02cc8
@ -354,10 +354,23 @@ pub fn check_lint_name(
|
||||
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::<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)
|
||||
} 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,21 @@ pub fn check_lint_name(
|
||||
}
|
||||
}
|
||||
|
||||
fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> {
|
||||
let name_lower = lint_name.to_lowercase();
|
||||
let symbols =
|
||||
self.get_lints().iter().map(|l| Symbol::intern(&l.name_lower())).collect::<Vec<_>>();
|
||||
|
||||
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...
|
||||
CheckLintNameResult::NoLint(Some(Symbol::intern(&name_lower)))
|
||||
} else {
|
||||
// ...if not, search for lints with a similar name
|
||||
let suggestion = find_best_match_for_name(&symbols, Symbol::intern(&name_lower), None);
|
||||
CheckLintNameResult::NoLint(suggestion)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_tool_name_for_backwards_compat(
|
||||
&self,
|
||||
lint_name: &str,
|
||||
@ -407,18 +435,7 @@ fn check_tool_name_for_backwards_compat(
|
||||
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::<Vec<_>>();
|
||||
|
||||
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 {
|
||||
|
@ -381,6 +381,11 @@ pub(crate) fn push(
|
||||
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(
|
||||
|
@ -4,7 +4,7 @@
|
||||
//! compiler code, rather than using their own custom pass. Those
|
||||
//! lints are all available in `rustc_lint::builtin`.
|
||||
|
||||
use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
|
||||
use crate::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
@ -2825,8 +2825,29 @@
|
||||
};
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
||||
declare_lint! {
|
||||
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// #![feature(staged_api)]
|
||||
///
|
||||
/// #[derive(Clone)]
|
||||
/// #[stable(feature = "x", since = "1")]
|
||||
/// struct S {}
|
||||
///
|
||||
/// #[unstable(feature = "y", issue = "none")]
|
||||
/// impl Copy for S {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// `staged_api` does not currently support using a stability attribute on `impl` blocks.
|
||||
/// `impl`s are always stable if both the type and trait are stable, and always unstable otherwise.
|
||||
pub INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
||||
Deny,
|
||||
"detects `#[unstable]` on stable trait implementations for stable types"
|
||||
}
|
||||
|
@ -33,7 +33,8 @@ fn wake_by_ref(self: &Arc<Self>) {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::ineffective_unstable_trait_impl)]
|
||||
#[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))]
|
||||
#[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))]
|
||||
#[unstable(feature = "wake_trait", issue = "69912")]
|
||||
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
|
||||
fn from(waker: Arc<W>) -> Waker {
|
||||
@ -43,7 +44,8 @@ fn from(waker: Arc<W>) -> Waker {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::ineffective_unstable_trait_impl)]
|
||||
#[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))]
|
||||
#[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))]
|
||||
#[unstable(feature = "wake_trait", issue = "69912")]
|
||||
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
|
||||
fn from(waker: Arc<W>) -> RawWaker {
|
||||
|
@ -22,7 +22,7 @@ impl StableTrait for UnstableType {}
|
||||
impl UnstableTrait for StableType {}
|
||||
|
||||
#[unstable(feature = "x", issue = "none")]
|
||||
//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl]
|
||||
//~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
|
||||
impl StableTrait for StableType {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,7 +4,7 @@ error: an `#[unstable]` annotation here has no effect
|
||||
LL | #[unstable(feature = "x", issue = "none")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default
|
||||
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
|
||||
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -10,11 +10,10 @@
|
||||
use rustc_hir::{
|
||||
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
|
||||
};
|
||||
use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::{Symbol, SymbolStr};
|
||||
@ -156,33 +155,6 @@
|
||||
"empty line after outer attribute"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `allow`/`warn`/`deny`/`forbid` attributes with scoped clippy
|
||||
/// lints and if those lints exist in clippy. If there is an uppercase letter in the lint name
|
||||
/// (not the tool name) and a lowercase version of this lint exists, it will suggest to lowercase
|
||||
/// the lint name.
|
||||
///
|
||||
/// **Why is this bad?** A lint attribute with a mistyped lint name won't have an effect.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// Bad:
|
||||
/// ```rust
|
||||
/// #![warn(if_not_els)]
|
||||
/// #![deny(clippy::All)]
|
||||
/// ```
|
||||
///
|
||||
/// Good:
|
||||
/// ```rust
|
||||
/// #![warn(if_not_else)]
|
||||
/// #![deny(clippy::all)]
|
||||
/// ```
|
||||
pub UNKNOWN_CLIPPY_LINTS,
|
||||
style,
|
||||
"unknown_lints for scoped Clippy lints"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
|
||||
///
|
||||
@ -272,7 +244,6 @@
|
||||
INLINE_ALWAYS,
|
||||
DEPRECATED_SEMVER,
|
||||
USELESS_ATTRIBUTE,
|
||||
UNKNOWN_CLIPPY_LINTS,
|
||||
BLANKET_CLIPPY_RESTRICTION_LINTS,
|
||||
]);
|
||||
|
||||
@ -409,48 +380,9 @@ fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<SymbolStr> {
|
||||
}
|
||||
|
||||
fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
|
||||
let lint_store = cx.lints();
|
||||
for lint in items {
|
||||
if let Some(lint_name) = extract_clippy_lint(lint) {
|
||||
if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym::clippy))
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNKNOWN_CLIPPY_LINTS,
|
||||
lint.span(),
|
||||
&format!("unknown clippy lint: clippy::{}", lint_name),
|
||||
|diag| {
|
||||
let name_lower = lint_name.to_lowercase();
|
||||
let symbols = lint_store
|
||||
.get_lints()
|
||||
.iter()
|
||||
.map(|l| Symbol::intern(&l.name_lower()))
|
||||
.collect::<Vec<_>>();
|
||||
let sugg = find_best_match_for_name(
|
||||
&symbols,
|
||||
Symbol::intern(&format!("clippy::{}", name_lower)),
|
||||
None,
|
||||
);
|
||||
if lint_name.chars().any(char::is_uppercase)
|
||||
&& lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok()
|
||||
{
|
||||
diag.span_suggestion(
|
||||
lint.span(),
|
||||
"lowercase the lint name",
|
||||
format!("clippy::{}", name_lower),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(sugg) = sugg {
|
||||
diag.span_suggestion(
|
||||
lint.span(),
|
||||
"did you mean",
|
||||
sugg.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if lint_name == "restriction" && ident != "allow" {
|
||||
if lint_name == "restriction" && ident != "allow" {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
BLANKET_CLIPPY_RESTRICTION_LINTS,
|
||||
|
@ -163,6 +163,19 @@ macro_rules! declare_deprecated_lint {
|
||||
}
|
||||
|
||||
declare_deprecated_lint! {
|
||||
/// **What it does:** Nothing. This lint has been deprecated.
|
||||
///
|
||||
/// **Deprecation reason:** This lint has been uplifted to rustc and is now called
|
||||
/// `panic_fmt`.
|
||||
pub PANIC_PARAMS,
|
||||
"this lint has been uplifted to rustc and is now called `panic_fmt`"
|
||||
}
|
||||
|
||||
declare_deprecated_lint! {
|
||||
/// **What it does:** Nothing. This lint has been deprecated.
|
||||
///
|
||||
/// **Deprecation reason:** This lint has been integrated into the `unknown_lints`
|
||||
/// rustc lint.
|
||||
pub UNKNOWN_CLIPPY_LINTS,
|
||||
"this lint has been integrated into the `unknown_lints` rustc lint"
|
||||
}
|
||||
|
@ -500,6 +500,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
"clippy::panic_params",
|
||||
"this lint has been uplifted to rustc and is now called `panic_fmt`",
|
||||
);
|
||||
store.register_removed(
|
||||
"clippy::unknown_clippy_lints",
|
||||
"this lint has been integrated into the `unknown_lints` rustc lint",
|
||||
);
|
||||
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
|
||||
|
||||
// begin register lints, do not remove this comment, it’s used in `update_lints`
|
||||
@ -541,7 +545,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
&attrs::INLINE_ALWAYS,
|
||||
&attrs::MISMATCHED_TARGET_OS,
|
||||
&attrs::UNKNOWN_CLIPPY_LINTS,
|
||||
&attrs::USELESS_ATTRIBUTE,
|
||||
&await_holding_invalid::AWAIT_HOLDING_LOCK,
|
||||
&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
|
||||
@ -1375,7 +1378,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&attrs::DEPRECATED_CFG_ATTR),
|
||||
LintId::of(&attrs::DEPRECATED_SEMVER),
|
||||
LintId::of(&attrs::MISMATCHED_TARGET_OS),
|
||||
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
|
||||
LintId::of(&attrs::USELESS_ATTRIBUTE),
|
||||
LintId::of(&bit_mask::BAD_BIT_MASK),
|
||||
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
|
||||
@ -1650,7 +1652,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
|
||||
LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
|
||||
LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
|
||||
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
|
||||
LintId::of(&blacklisted_name::BLACKLISTED_NAME),
|
||||
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
|
||||
LintId::of(&collapsible_if::COLLAPSIBLE_IF),
|
||||
|
@ -9,5 +9,6 @@
|
||||
#[warn(clippy::drop_bounds)]
|
||||
#[warn(clippy::temporary_cstring_as_ptr)]
|
||||
#[warn(clippy::panic_params)]
|
||||
#[warn(clippy::unknown_clippy_lints)]
|
||||
|
||||
fn main() {}
|
||||
|
@ -66,11 +66,17 @@ error: lint `clippy::panic_params` has been removed: `this lint has been uplifte
|
||||
LL | #[warn(clippy::panic_params)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lint `clippy::unknown_clippy_lints` has been removed: `this lint has been integrated into the `unknown_lints` rustc lint`
|
||||
--> $DIR/deprecated.rs:12:8
|
||||
|
|
||||
LL | #[warn(clippy::unknown_clippy_lints)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
|
||||
--> $DIR/deprecated.rs:1:8
|
||||
|
|
||||
LL | #[warn(clippy::unstable_as_slice)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
@ -1,52 +1,58 @@
|
||||
error: unknown clippy lint: clippy::if_not_els
|
||||
error: unknown lint: `clippy::All`
|
||||
--> $DIR/unknown_clippy_lints.rs:5:10
|
||||
|
|
||||
LL | #![allow(clippy::All)]
|
||||
| ^^^^^^^^^^^ help: did you mean: `clippy::all`
|
||||
|
|
||||
= note: `-D unknown-lints` implied by `-D warnings`
|
||||
|
||||
error: unknown lint: `clippy::CMP_NAN`
|
||||
--> $DIR/unknown_clippy_lints.rs:6:9
|
||||
|
|
||||
LL | #![warn(clippy::CMP_NAN)]
|
||||
| ^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_nan`
|
||||
|
||||
error: unknown lint: `clippy::if_not_els`
|
||||
--> $DIR/unknown_clippy_lints.rs:9:8
|
||||
|
|
||||
LL | #[warn(clippy::if_not_els)]
|
||||
| ^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::if_not_else`
|
||||
|
|
||||
= note: `-D clippy::unknown-clippy-lints` implied by `-D warnings`
|
||||
|
||||
error: unknown clippy lint: clippy::UNNecsaRy_cAst
|
||||
error: unknown lint: `clippy::UNNecsaRy_cAst`
|
||||
--> $DIR/unknown_clippy_lints.rs:10:8
|
||||
|
|
||||
LL | #[warn(clippy::UNNecsaRy_cAst)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unnecessary_cast`
|
||||
|
||||
error: unknown clippy lint: clippy::useles_transute
|
||||
error: unknown lint: `clippy::useles_transute`
|
||||
--> $DIR/unknown_clippy_lints.rs:11:8
|
||||
|
|
||||
LL | #[warn(clippy::useles_transute)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::useless_transmute`
|
||||
|
||||
error: unknown clippy lint: clippy::dead_cod
|
||||
error: unknown lint: `clippy::dead_cod`
|
||||
--> $DIR/unknown_clippy_lints.rs:13:8
|
||||
|
|
||||
LL | #[warn(clippy::dead_cod)]
|
||||
| ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::drop_copy`
|
||||
|
||||
error: unknown clippy lint: clippy::unused_colle
|
||||
error: unknown lint: `clippy::unused_colle`
|
||||
--> $DIR/unknown_clippy_lints.rs:15:8
|
||||
|
|
||||
LL | #[warn(clippy::unused_colle)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unused_self`
|
||||
|
||||
error: unknown clippy lint: clippy::const_static_lifetim
|
||||
error: unknown lint: `clippy::const_static_lifetim`
|
||||
--> $DIR/unknown_clippy_lints.rs:17:8
|
||||
|
|
||||
LL | #[warn(clippy::const_static_lifetim)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes`
|
||||
|
||||
error: unknown clippy lint: clippy::All
|
||||
error: unknown lint: `clippy::All`
|
||||
--> $DIR/unknown_clippy_lints.rs:5:10
|
||||
|
|
||||
LL | #![allow(clippy::All)]
|
||||
| ^^^^^^^^^^^ help: lowercase the lint name: `clippy::all`
|
||||
| ^^^^^^^^^^^ help: did you mean: `clippy::all`
|
||||
|
||||
error: unknown clippy lint: clippy::CMP_NAN
|
||||
--> $DIR/unknown_clippy_lints.rs:6:9
|
||||
|
|
||||
LL | #![warn(clippy::CMP_NAN)]
|
||||
| ^^^^^^^^^^^^^^^ help: lowercase the lint name: `clippy::cmp_nan`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user