diff options
| author | bors <bors@rust-lang.org> | 2022-03-04 19:23:39 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-03-04 19:23:39 +0000 |
| commit | 48d54942f55078cd5866a96bd182bbaf2b81d0f6 (patch) | |
| tree | c357a5c99c1bdc6cd876a8dae73551e0742437a5 | |
| parent | 53189ad190f313cbad28f8138a04e734ac052cfc (diff) | |
| parent | ab6ffb6371b78d1777b90c25a44163562ae53036 (diff) | |
| download | rust-48d54942f55078cd5866a96bd182bbaf2b81d0f6.tar.gz rust-48d54942f55078cd5866a96bd182bbaf2b81d0f6.zip | |
Auto merge of #8504 - xFrednet:8502-allow-lint-without-reason, r=flip1995
Add lint to detect `allow` attributes without reason I was considering putting this lint into the pedantic group. However, that would result in countless warnings for existing projects. Having it in restriction also seems good to me :upside_down_face: (And now I need sleep :zzz: ) --- changelog: New lint [`allow_lint_without_reason`] (Requires the `lint_reasons` feature) Closes: rust-lang/rust-clippy#8502
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | clippy_lints/src/attrs.rs | 60 | ||||
| -rw-r--r-- | clippy_lints/src/lib.register_lints.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.register_restriction.rs | 1 | ||||
| -rw-r--r-- | tests/ui/allow_attributes_without_reason.rs | 14 | ||||
| -rw-r--r-- | tests/ui/allow_attributes_without_reason.stderr | 23 |
6 files changed, 99 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f18a00a9dd..e7884818596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3042,6 +3042,7 @@ Released 2018-09-13 <!-- lint disable no-unused-definitions --> <!-- begin autogenerated links to lint list --> [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons +[`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index a58d12ddd6b..d0b03c0a9c2 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -255,7 +255,38 @@ declare_clippy_lint! { "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for attributes that allow lints without a reason. + /// + /// (This requires the `lint_reasons` feature) + /// + /// ### Why is this bad? + /// Allowing a lint should always have a reason. This reason should be documented to + /// ensure that others understand the reasoning + /// + /// ### Example + /// Bad: + /// ```rust + /// #![feature(lint_reasons)] + /// + /// #![allow(clippy::some_lint)] + /// ``` + /// + /// Good: + /// ```rust + /// #![feature(lint_reasons)] + /// + /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] + /// ``` + #[clippy::version = "1.61.0"] + pub ALLOW_ATTRIBUTES_WITHOUT_REASON, + restriction, + "ensures that all `allow` and `expect` attributes have a reason" +} + declare_lint_pass!(Attributes => [ + ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE, @@ -269,6 +300,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if is_lint_level(ident.name) { check_clippy_lint_names(cx, ident.name, items); } + if matches!(ident.name, sym::allow | sym::expect) { + check_lint_reason(cx, ident.name, items, attr); + } if items.is_empty() || !attr.has_name(sym::deprecated) { return; } @@ -404,6 +438,30 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe } } +fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem], attr: &'_ Attribute) { + // Check for the feature + if !cx.tcx.sess.features_untracked().lint_reasons { + return; + } + + // Check if the reason is present + if let Some(item) = items.last().and_then(NestedMetaItem::meta_item) + && let MetaItemKind::NameValue(_) = &item.kind + && item.path == sym::reason + { + return; + } + + span_lint_and_help( + cx, + ALLOW_ATTRIBUTES_WITHOUT_REASON, + attr.span, + &format!("`{}` attribute without specifying a reason", name.as_str()), + None, + "try adding a reason at the end with `, reason = \"..\"`", + ); +} + fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { if let ItemKind::Fn(_, _, eid) = item.kind { is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value) @@ -659,5 +717,5 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { } fn is_lint_level(symbol: Symbol) -> bool { - matches!(symbol, sym::allow | sym::warn | sym::deny | sym::forbid) + matches!(symbol, sym::allow | sym::expect | sym::warn | sym::deny | sym::forbid) } diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index d248c2a41ee..8bfa1dfe585 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -44,6 +44,7 @@ store.register_lints(&[ assign_ops::ASSIGN_OP_PATTERN, assign_ops::MISREFACTORED_ASSIGN_OP, async_yields_async::ASYNC_YIELDS_ASYNC, + attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON, attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, attrs::DEPRECATED_CFG_ATTR, attrs::DEPRECATED_SEMVER, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index f89f35b885c..4e30fc38197 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -8,6 +8,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(as_conversions::AS_CONVERSIONS), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON), LintId::of(casts::FN_TO_NUMERIC_CAST_ANY), LintId::of(create_dir::CREATE_DIR), LintId::of(dbg_macro::DBG_MACRO), diff --git a/tests/ui/allow_attributes_without_reason.rs b/tests/ui/allow_attributes_without_reason.rs new file mode 100644 index 00000000000..1a0d4e88657 --- /dev/null +++ b/tests/ui/allow_attributes_without_reason.rs @@ -0,0 +1,14 @@ +#![feature(lint_reasons)] +#![deny(clippy::allow_attributes_without_reason)] + +// These should trigger the lint +#[allow(dead_code)] +#[allow(dead_code, deprecated)] +// These should be fine +#[allow(dead_code, reason = "This should be allowed")] +#[warn(dyn_drop, reason = "Warnings can also have reasons")] +#[warn(deref_nullptr)] +#[deny(deref_nullptr)] +#[forbid(deref_nullptr)] + +fn main() {} diff --git a/tests/ui/allow_attributes_without_reason.stderr b/tests/ui/allow_attributes_without_reason.stderr new file mode 100644 index 00000000000..cd040a144aa --- /dev/null +++ b/tests/ui/allow_attributes_without_reason.stderr @@ -0,0 +1,23 @@ +error: `allow` attribute without specifying a reason + --> $DIR/allow_attributes_without_reason.rs:5:1 + | +LL | #[allow(dead_code)] + | ^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/allow_attributes_without_reason.rs:2:9 + | +LL | #![deny(clippy::allow_attributes_without_reason)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: try adding a reason at the end with `, reason = ".."` + +error: `allow` attribute without specifying a reason + --> $DIR/allow_attributes_without_reason.rs:6:1 + | +LL | #[allow(dead_code, deprecated)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a reason at the end with `, reason = ".."` + +error: aborting due to 2 previous errors + |
