Skip to content

Commit 6f2a6fe

Browse files
committed
Auto merge of rust-lang#6977 - flip1995:or_patterns_msrv, r=llogiq
Add MSRV options to `unnested_or_patterns` changelog: [`unnested_or_patterns`] can now be configured with the `msrv` config/attribute. Fixes rust-lang#6953
2 parents 63aca96 + 5279b59 commit 6f2a6fe

File tree

6 files changed

+84
-36
lines changed

6 files changed

+84
-36
lines changed

clippy_lints/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10791079
store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
10801080
store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark::new(msrv));
10811081
store.register_late_pass(move || box casts::Casts::new(msrv));
1082+
store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
10821083

10831084
store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
10841085
store.register_late_pass(|| box map_clone::MapClone);
@@ -1254,7 +1255,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12541255
store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
12551256
single_char_binding_names_threshold,
12561257
});
1257-
store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
12581258
store.register_late_pass(|| box macro_use::MacroUseImports::default());
12591259
store.register_late_pass(|| box map_identity::MapIdentity);
12601260
store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);

clippy_lints/src/unnested_or_patterns.rs

+36-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
22

3-
use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
43
use clippy_utils::diagnostics::span_lint_and_then;
54
use clippy_utils::over;
5+
use clippy_utils::{
6+
ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path},
7+
meets_msrv,
8+
};
69
use rustc_ast::mut_visit::*;
710
use rustc_ast::ptr::P;
811
use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
912
use rustc_ast_pretty::pprust;
1013
use rustc_errors::Applicability;
1114
use rustc_lint::{EarlyContext, EarlyLintPass};
12-
use rustc_session::{declare_lint_pass, declare_tool_lint};
15+
use rustc_semver::RustcVersion;
16+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1317
use rustc_span::DUMMY_SP;
1418

1519
use std::cell::Cell;
@@ -50,26 +54,50 @@ declare_clippy_lint! {
5054
"unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
5155
}
5256

53-
declare_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
57+
const UNNESTED_OR_PATTERNS_MSRV: RustcVersion = RustcVersion::new(1, 53, 0);
58+
59+
#[derive(Clone, Copy)]
60+
pub struct UnnestedOrPatterns {
61+
msrv: Option<RustcVersion>,
62+
}
63+
64+
impl UnnestedOrPatterns {
65+
#[must_use]
66+
pub fn new(msrv: Option<RustcVersion>) -> Self {
67+
Self { msrv }
68+
}
69+
}
70+
71+
impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
5472

5573
impl EarlyLintPass for UnnestedOrPatterns {
5674
fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
57-
lint_unnested_or_patterns(cx, &a.pat);
75+
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
76+
lint_unnested_or_patterns(cx, &a.pat);
77+
}
5878
}
5979

6080
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
61-
if let ast::ExprKind::Let(pat, _) = &e.kind {
62-
lint_unnested_or_patterns(cx, pat);
81+
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
82+
if let ast::ExprKind::Let(pat, _) = &e.kind {
83+
lint_unnested_or_patterns(cx, pat);
84+
}
6385
}
6486
}
6587

6688
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
67-
lint_unnested_or_patterns(cx, &p.pat);
89+
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
90+
lint_unnested_or_patterns(cx, &p.pat);
91+
}
6892
}
6993

7094
fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
71-
lint_unnested_or_patterns(cx, &l.pat);
95+
if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
96+
lint_unnested_or_patterns(cx, &l.pat);
97+
}
7298
}
99+
100+
extract_msrv_attr!(EarlyContext);
73101
}
74102

75103
fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {

clippy_lints/src/utils/conf.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ macro_rules! define_Conf {
106106

107107
pub use self::helpers::Conf;
108108
define_Conf! {
109-
/// Lint: 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. The minimum rust version that the project supports
109+
/// Lint: 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. The minimum rust version that the project supports
110110
(msrv, "msrv": Option<String>, None),
111111
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
112112
(blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),

doc/adding_lints.md

+36-22
Original file line numberDiff line numberDiff line change
@@ -388,18 +388,19 @@ pass.
388388
[`FnKind::Fn`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html#variant.Fn
389389
[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
390390

391-
## Specifying the lint's minimum supported Rust version (msrv)
391+
## Specifying the lint's minimum supported Rust version (MSRV)
392392

393-
Projects supporting older versions of Rust would need to disable a lint if it targets features
394-
present in later versions. Support for this can be added by specifying an msrv in your lint like so,
393+
Projects supporting older versions of Rust would need to disable a lint if it
394+
targets features present in later versions. Support for this can be added by
395+
specifying an MSRV in your lint like so,
395396

396397
```rust
397398
const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0);
398399
```
399400

400-
The project's msrv will also have to be an attribute in the lint so you'll have to add a struct
401-
and constructor for your lint. The project's msrv needs to be passed when the lint is registered
402-
in `lib.rs`
401+
The project's MSRV will also have to be an attribute in the lint so you'll have
402+
to add a struct and constructor for your lint. The project's MSRV needs to be
403+
passed when the lint is registered in `lib.rs`
403404

404405
```rust
405406
pub struct ManualStrip {
@@ -414,18 +415,19 @@ impl ManualStrip {
414415
}
415416
```
416417

417-
The project's msrv can then be matched against the lint's msrv in the LintPass using the `meets_msrv` utility
418-
function.
418+
The project's MSRV can then be matched against the lint's `msrv` in the LintPass
419+
using the `meets_msrv` utility function.
419420

420421
``` rust
421422
if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
422423
return;
423424
}
424425
```
425426

426-
The project's msrv can also be specified as an inner attribute, which overrides the value from
427-
`clippy.toml`. This can be accounted for using the `extract_msrv_attr!(LintContext)` macro and passing
428-
LateContext/EarlyContext.
427+
The project's MSRV can also be specified as an inner attribute, which overrides
428+
the value from `clippy.toml`. This can be accounted for using the
429+
`extract_msrv_attr!(LintContext)` macro and passing
430+
`LateContext`/`EarlyContext`.
429431

430432
```rust
431433
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
@@ -436,8 +438,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
436438
}
437439
```
438440

439-
Once the msrv is added to the lint, a relevant test case should be added to `tests/ui/min_rust_version_attr.rs`
440-
which verifies that the lint isn't emitted if the project's msrv is lower.
441+
Once the `msrv` is added to the lint, a relevant test case should be added to
442+
`tests/ui/min_rust_version_attr.rs` which verifies that the lint isn't emitted
443+
if the project's MSRV is lower.
444+
445+
As a last step, the lint should be added to the lint documentation. This is done
446+
in `clippy_lints/src/utils/conf.rs`:
447+
448+
```rust
449+
define_Conf! {
450+
/// Lint: LIST, OF, LINTS, <THE_NEWLY_ADDED_LINT>. The minimum rust version that the project supports
451+
(msrv, "msrv": Option<String>, None),
452+
...
453+
}
454+
```
441455

442456
## Author lint
443457

@@ -533,9 +547,9 @@ Before submitting your PR make sure you followed all of the basic requirements:
533547

534548
## Adding configuration to a lint
535549

536-
Clippy supports the configuration of lints values using a `clippy.toml` file in the workspace
550+
Clippy supports the configuration of lints values using a `clippy.toml` file in the workspace
537551
directory. Adding a configuration to a lint can be useful for thresholds or to constrain some
538-
behavior that can be seen as a false positive for some users. Adding a configuration is done
552+
behavior that can be seen as a false positive for some users. Adding a configuration is done
539553
in the following steps:
540554

541555
1. Adding a new configuration entry to [clippy_utils::conf](/clippy_utils/src/conf.rs)
@@ -544,10 +558,10 @@ in the following steps:
544558
/// Lint: LINT_NAME. <The configuration field doc comment>
545559
(configuration_ident, "configuration_value": Type, DefaultValue),
546560
```
547-
The configuration value and identifier should usually be the same. The doc comment will be
561+
The configuration value and identifier should usually be the same. The doc comment will be
548562
automatically added to the lint documentation.
549563
2. Adding the configuration value to the lint impl struct:
550-
1. This first requires the definition of a lint impl struct. Lint impl structs are usually
564+
1. This first requires the definition of a lint impl struct. Lint impl structs are usually
551565
generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
552566
to add some kind of metadata to it:
553567
```rust
@@ -564,7 +578,7 @@ in the following steps:
564578
LINT_NAME
565579
]);
566580
```
567-
581+
568582
2. Next add the configuration value and a corresponding creation method like this:
569583
```rust
570584
#[derive(Copy, Clone)]
@@ -584,7 +598,7 @@ in the following steps:
584598
```
585599
3. Passing the configuration value to the lint impl struct:
586600

587-
First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs).
601+
First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs).
588602
The configuration value is now cloned or copied into a local value that is then passed to the
589603
impl struct like this:
590604
```rust
@@ -601,9 +615,9 @@ in the following steps:
601615

602616
4. Adding tests:
603617
1. The default configured value can be tested like any normal lint in [`tests/ui`](/tests/ui).
604-
2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml).
605-
Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file
606-
with the configuration value and a rust file that should be linted by Clippy. The test can
618+
2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml).
619+
Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file
620+
with the configuration value and a rust file that should be linted by Clippy. The test can
607621
otherwise be written as usual.
608622

609623
## Cheatsheet

tests/ui/min_rust_version_attr.rs

+6
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ fn missing_const_for_fn() -> i32 {
123123
1
124124
}
125125

126+
fn unnest_or_patterns() {
127+
struct TS(u8, u8);
128+
if let TS(0, x) | TS(1, x) = TS(0, 0) {}
129+
}
130+
126131
fn main() {
127132
filter_map_next();
128133
checked_conversion();
@@ -138,6 +143,7 @@ fn main() {
138143
replace_with_default();
139144
map_unwrap_or();
140145
missing_const_for_fn();
146+
unnest_or_patterns();
141147
}
142148

143149
mod meets_msrv {

tests/ui/min_rust_version_attr.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
error: stripping a prefix manually
2-
--> $DIR/min_rust_version_attr.rs:150:24
2+
--> $DIR/min_rust_version_attr.rs:156:24
33
|
44
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
55
| ^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::manual-strip` implied by `-D warnings`
88
note: the prefix was tested here
9-
--> $DIR/min_rust_version_attr.rs:149:9
9+
--> $DIR/min_rust_version_attr.rs:155:9
1010
|
1111
LL | if s.starts_with("hello, ") {
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,13 +17,13 @@ LL | assert_eq!(<stripped>.to_uppercase(), "WORLD!");
1717
|
1818

1919
error: stripping a prefix manually
20-
--> $DIR/min_rust_version_attr.rs:162:24
20+
--> $DIR/min_rust_version_attr.rs:168:24
2121
|
2222
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
2323
| ^^^^^^^^^^^^^^^^^^^^
2424
|
2525
note: the prefix was tested here
26-
--> $DIR/min_rust_version_attr.rs:161:9
26+
--> $DIR/min_rust_version_attr.rs:167:9
2727
|
2828
LL | if s.starts_with("hello, ") {
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)