Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions clippy_lints/src/types/option_option.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::qpath_generic_tys;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::snippet;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, QPath};
use rustc_lint::LateContext;
Expand All @@ -13,12 +14,21 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
&& let Some(arg) = qpath_generic_tys(qpath).next()
&& arg.basic_res().opt_def_id() == Some(def_id)
{
span_lint(
span_lint_and_then(
cx,
OPTION_OPTION,
hir_ty.span,
"consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
enum if you need to distinguish all 3 cases",
// use just `T` here, as the inner type is not what's problematic
"use of `Option<Option<T>>`",
|diag| {
// but use the specific type here, as:
// - this is kind of a suggestion
// - it's printed right after the linted type
let inner_opt = snippet(cx, arg.span, "_");
diag.help(format!(
"consider using `{inner_opt}`, or a custom enum if you need to distinguish all 3 cases"
));
},
);
true
} else {
Expand Down
28 changes: 14 additions & 14 deletions tests/ui/option_option.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
#![deny(clippy::option_option)]
#![allow(clippy::unnecessary_wraps, clippy::manual_unwrap_or_default)]
#![warn(clippy::option_option)]
#![expect(clippy::unnecessary_wraps)]

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

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

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

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

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

struct Struct {
x: Option<Option<u8>>,
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
//~^ option_option
}

impl Struct {
fn struct_fn() -> Option<Option<u8>> {
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
//~^ option_option
None
}
}

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

enum Enum {
Tuple(Option<Option<u8>>),
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
//~^ option_option
Struct { x: Option<Option<u8>> },
//~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum
//~^ option_option
}

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

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

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

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

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

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

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

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

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

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

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

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

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

error: aborting due to 12 previous errors