diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 6f8b645dd70d..9c5db18336fc 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,8 +1,9 @@ //! checks for attributes use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::match_panic_def_id; +use clippy_utils::msrvs; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; +use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; @@ -12,7 +13,8 @@ use rustc_hir::{ 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_semver::RustcVersion; +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::sym; use rustc_span::symbol::{Symbol, SymbolStr}; @@ -497,7 +499,11 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { } } -declare_lint_pass!(EarlyAttributes => [ +pub struct EarlyAttributes { + pub msrv: Option, +} + +impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS, EMPTY_LINE_AFTER_OUTER_ATTR, @@ -509,9 +515,11 @@ impl EarlyLintPass for EarlyAttributes { } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { - check_deprecated_cfg_attr(cx, attr); + check_deprecated_cfg_attr(cx, attr, self.msrv); check_mismatched_target_os(cx, attr); } + + extract_msrv_attr!(EarlyContext); } fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { @@ -548,8 +556,9 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It } } -fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { +fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option) { if_chain! { + if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES); // check cfg_attr if attr.has_name(sym::cfg_attr); if let Some(items) = attr.meta_item_list(); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bc302046b2d1..d91b2e1f448d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -404,10 +404,21 @@ use crate::utils::conf::TryConf; /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. + + let msrv = conf.msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(&format!( + "error reading Clippy's configuration file. `{}` is not a valid Rust version", + s + )); + None + }) + }); + store.register_pre_expansion_pass(|| Box::new(write::Write::default())); - store.register_pre_expansion_pass(|| Box::new(attrs::EarlyAttributes)); + store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv })); store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro)); } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 122a5ce3fc8f..3c4f114fe597 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -148,7 +148,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index fa57dfbb57ed..f3913203f4b4 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -27,7 +27,7 @@ msrv_aliases! { 1,36,0 { ITERATOR_COPIED } 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } - 1,30,0 { ITERATOR_FIND_MAP } + 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST } 1,16,0 { STR_REPEAT } } diff --git a/src/driver.rs b/src/driver.rs index 0c82f37d6a22..a8aa3a76abc6 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -108,7 +108,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let conf = clippy_lints::read_conf(sess); clippy_lints::register_plugins(lint_store, sess, &conf); - clippy_lints::register_pre_expansion_lints(lint_store); + clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf); clippy_lints::register_renamed(lint_store); })); diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 8d9fc5a864d7..57ed453da10b 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -137,6 +137,9 @@ fn unnest_or_patterns() { if let TS(0, x) | TS(1, x) = TS(0, 0) {} } +#[cfg_attr(rustfmt, rustfmt_skip)] +fn deprecated_cfg_attr() {} + fn main() { filter_map_next(); checked_conversion(); @@ -155,9 +158,9 @@ fn main() { unnest_or_patterns(); } -mod meets_msrv { +mod just_under_msrv { #![feature(custom_inner_attributes)] - #![clippy::msrv = "1.45.0"] + #![clippy::msrv = "1.44.0"] fn main() { let s = "hello, world!"; @@ -167,9 +170,9 @@ mod meets_msrv { } } -mod just_under_msrv { +mod meets_msrv { #![feature(custom_inner_attributes)] - #![clippy::msrv = "1.46.0"] + #![clippy::msrv = "1.45.0"] fn main() { let s = "hello, world!"; @@ -181,7 +184,7 @@ mod just_under_msrv { mod just_above_msrv { #![feature(custom_inner_attributes)] - #![clippy::msrv = "1.44.0"] + #![clippy::msrv = "1.46.0"] fn main() { let s = "hello, world!"; diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 360dcfb230c6..4388b78f832a 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,12 +1,12 @@ error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:165:24 + --> $DIR/min_rust_version_attr.rs:180:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:164:9 + --> $DIR/min_rust_version_attr.rs:179:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,13 +17,13 @@ LL ~ assert_eq!(.to_uppercase(), "WORLD!"); | error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:177:24 + --> $DIR/min_rust_version_attr.rs:192:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:176:9 + --> $DIR/min_rust_version_attr.rs:191:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^