Skip to content

Commit 973e596

Browse files
authored
option_option: split part of diagnostic message into help message (#15870)
changelog: [`option_option`]: improve diagnostic message
2 parents 95dd88d + 2fe9d4b commit 973e596

File tree

3 files changed

+65
-35
lines changed

3 files changed

+65
-35
lines changed

clippy_lints/src/types/option_option.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use clippy_utils::diagnostics::span_lint;
1+
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::qpath_generic_tys;
33
use clippy_utils::res::MaybeResPath;
4+
use clippy_utils::source::snippet;
45
use rustc_hir::def_id::DefId;
56
use rustc_hir::{self as hir, QPath};
67
use rustc_lint::LateContext;
@@ -13,12 +14,21 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
1314
&& let Some(arg) = qpath_generic_tys(qpath).next()
1415
&& arg.basic_res().opt_def_id() == Some(def_id)
1516
{
16-
span_lint(
17+
span_lint_and_then(
1718
cx,
1819
OPTION_OPTION,
1920
hir_ty.span,
20-
"consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
21-
enum if you need to distinguish all 3 cases",
21+
// use just `T` here, as the inner type is not what's problematic
22+
"use of `Option<Option<T>>`",
23+
|diag| {
24+
// but use the specific type here, as:
25+
// - this is kind of a suggestion
26+
// - it's printed right after the linted type
27+
let inner_opt = snippet(cx, arg.span, "_");
28+
diag.help(format!(
29+
"consider using `{inner_opt}`, or a custom enum if you need to distinguish all 3 cases"
30+
));
31+
},
2232
);
2333
true
2434
} else {

tests/ui/option_option.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,52 @@
1-
#![deny(clippy::option_option)]
2-
#![allow(clippy::unnecessary_wraps, clippy::manual_unwrap_or_default)]
1+
#![warn(clippy::option_option)]
2+
#![expect(clippy::unnecessary_wraps)]
33

44
const C: Option<Option<i32>> = None;
5-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
5+
//~^ option_option
66
static S: Option<Option<i32>> = None;
7-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
7+
//~^ option_option
88

99
fn input(_: Option<Option<u8>>) {}
10-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
10+
//~^ option_option
1111

1212
fn output() -> Option<Option<u8>> {
13-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
13+
//~^ option_option
1414
None
1515
}
1616

1717
fn output_nested() -> Vec<Option<Option<u8>>> {
18-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
18+
//~^ option_option
1919
vec![None]
2020
}
2121

2222
// The lint only generates one warning for this
2323
fn output_nested_nested() -> Option<Option<Option<u8>>> {
24-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
24+
//~^ option_option
2525
None
2626
}
2727

2828
struct Struct {
2929
x: Option<Option<u8>>,
30-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
30+
//~^ option_option
3131
}
3232

3333
impl Struct {
3434
fn struct_fn() -> Option<Option<u8>> {
35-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
35+
//~^ option_option
3636
None
3737
}
3838
}
3939

4040
trait Trait {
4141
fn trait_fn() -> Option<Option<u8>>;
42-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
42+
//~^ option_option
4343
}
4444

4545
enum Enum {
4646
Tuple(Option<Option<u8>>),
47-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
47+
//~^ option_option
4848
Struct { x: Option<Option<u8>> },
49-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
49+
//~^ option_option
5050
}
5151

5252
// The lint allows this
@@ -88,7 +88,7 @@ mod issue_4298 {
8888
#[serde(default)]
8989
#[serde(borrow)]
9090
foo: Option<Option<Cow<'a, str>>>,
91-
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom
91+
//~^ option_option
9292
}
9393

9494
#[allow(clippy::option_option)]

tests/ui/option_option.stderr

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,100 @@
1-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
1+
error: use of `Option<Option<T>>`
22
--> tests/ui/option_option.rs:4:10
33
|
44
LL | const C: Option<Option<i32>> = None;
55
| ^^^^^^^^^^^^^^^^^^^
66
|
7-
note: the lint level is defined here
8-
--> tests/ui/option_option.rs:1:9
9-
|
10-
LL | #![deny(clippy::option_option)]
11-
| ^^^^^^^^^^^^^^^^^^^^^
7+
= help: consider using `Option<i32>`, or a custom enum if you need to distinguish all 3 cases
8+
= note: `-D clippy::option-option` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::option_option)]`
1210

13-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
11+
error: use of `Option<Option<T>>`
1412
--> tests/ui/option_option.rs:6:11
1513
|
1614
LL | static S: Option<Option<i32>> = None;
1715
| ^^^^^^^^^^^^^^^^^^^
16+
|
17+
= help: consider using `Option<i32>`, or a custom enum if you need to distinguish all 3 cases
1818

19-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
19+
error: use of `Option<Option<T>>`
2020
--> tests/ui/option_option.rs:9:13
2121
|
2222
LL | fn input(_: Option<Option<u8>>) {}
2323
| ^^^^^^^^^^^^^^^^^^
24+
|
25+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
2426

25-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
27+
error: use of `Option<Option<T>>`
2628
--> tests/ui/option_option.rs:12:16
2729
|
2830
LL | fn output() -> Option<Option<u8>> {
2931
| ^^^^^^^^^^^^^^^^^^
32+
|
33+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
3034

31-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
35+
error: use of `Option<Option<T>>`
3236
--> tests/ui/option_option.rs:17:27
3337
|
3438
LL | fn output_nested() -> Vec<Option<Option<u8>>> {
3539
| ^^^^^^^^^^^^^^^^^^
40+
|
41+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
3642

37-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
43+
error: use of `Option<Option<T>>`
3844
--> tests/ui/option_option.rs:23:30
3945
|
4046
LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
4147
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
|
49+
= help: consider using `Option<Option<u8>>`, or a custom enum if you need to distinguish all 3 cases
4250

43-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
51+
error: use of `Option<Option<T>>`
4452
--> tests/ui/option_option.rs:29:8
4553
|
4654
LL | x: Option<Option<u8>>,
4755
| ^^^^^^^^^^^^^^^^^^
56+
|
57+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
4858

49-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
59+
error: use of `Option<Option<T>>`
5060
--> tests/ui/option_option.rs:34:23
5161
|
5262
LL | fn struct_fn() -> Option<Option<u8>> {
5363
| ^^^^^^^^^^^^^^^^^^
64+
|
65+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
5466

55-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
67+
error: use of `Option<Option<T>>`
5668
--> tests/ui/option_option.rs:41:22
5769
|
5870
LL | fn trait_fn() -> Option<Option<u8>>;
5971
| ^^^^^^^^^^^^^^^^^^
72+
|
73+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
6074

61-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
75+
error: use of `Option<Option<T>>`
6276
--> tests/ui/option_option.rs:46:11
6377
|
6478
LL | Tuple(Option<Option<u8>>),
6579
| ^^^^^^^^^^^^^^^^^^
80+
|
81+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
6682

67-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
83+
error: use of `Option<Option<T>>`
6884
--> tests/ui/option_option.rs:48:17
6985
|
7086
LL | Struct { x: Option<Option<u8>> },
7187
| ^^^^^^^^^^^^^^^^^^
88+
|
89+
= help: consider using `Option<u8>`, or a custom enum if you need to distinguish all 3 cases
7290

73-
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
91+
error: use of `Option<Option<T>>`
7492
--> tests/ui/option_option.rs:90:14
7593
|
7694
LL | foo: Option<Option<Cow<'a, str>>>,
7795
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
96+
|
97+
= help: consider using `Option<Cow<'a, str>>`, or a custom enum if you need to distinguish all 3 cases
7898

7999
error: aborting due to 12 previous errors
80100

0 commit comments

Comments
 (0)