Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6892,6 +6892,7 @@ Released 2018-09-13
[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv
[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit
[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
[`recursive-self-in-struct`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-struct
[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline
[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
Expand Down
10 changes: 10 additions & 0 deletions book/src/lint_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,16 @@ exported visibility, or whether they are marked as "pub".
* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)


## `recursive-self-in-struct`
Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.

**Default Value:** `true`

---
**Affected lints:**
* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)


## `semicolon-inside-block-ignore-singleline`
Whether to lint only if it's multiline.

Expand Down
3 changes: 3 additions & 0 deletions clippy_config/src/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,9 @@ define_Conf! {
/// exported visibility, or whether they are marked as "pub".
#[lints(pub_underscore_fields)]
pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported,
/// Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
#[lints(use_self)]
recursive_self_in_struct: bool = true,
/// Whether to lint only if it's multiline.
#[lints(semicolon_inside_block)]
semicolon_inside_block_ignore_singleline: bool = false,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/matches/single_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ enum PatState<'a> {
/// A std enum we know won't be extended. Tracks the states of each variant separately.
///
/// This is not used for `Option` since it uses the current pattern to track its state.
StdEnum(&'a mut [PatState<'a>]),
StdEnum(&'a mut [Self]),
/// Either the initial state for a pattern or a non-std enum. There is currently no need to
/// distinguish these cases.
///
Expand Down
19 changes: 15 additions & 4 deletions clippy_lints/src/use_self.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ declare_clippy_lint! {
pub struct UseSelf {
msrv: Msrv,
stack: Vec<StackItem>,
recursive_struct: bool,
}

impl UseSelf {
pub fn new(conf: &'static Conf) -> Self {
Self {
msrv: conf.msrv,
stack: Vec::new(),
recursive_struct: conf.recursive_self_in_struct,
}
}
}
Expand All @@ -84,10 +86,10 @@ const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
// We push the self types of `impl`s on a stack here. Only the top type on the stack is
// relevant for linting, since this is the self type of the `impl` we're currently in. To
// avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
// we're in an `impl` or nested item, that we don't want to lint
// We push the self types of items on a stack here. Only the top type on the stack is
// relevant for linting, since this is the self type of the item we're currently in. To
// avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal that
// we're in an item or nested item that we don't want to lint
let stack_item = if let ItemKind::Impl(Impl { self_ty, generics, .. }) = item.kind
&& let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind
&& let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args
Expand All @@ -112,6 +114,15 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
impl_id: item.owner_id.def_id,
types_to_skip,
}
} else if let ItemKind::Struct(..) | ItemKind::Enum(..) = item.kind
&& self.recursive_struct
&& !item.span.from_expansion()
&& !is_from_proc_macro(cx, item)
{
StackItem::Check {
impl_id: item.owner_id.def_id,
types_to_skip: FxHashSet::default(),
}
} else {
StackItem::NoCheck
};
Expand Down
8 changes: 4 additions & 4 deletions clippy_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ pub enum Constant {
/// `true` or `false`.
Bool(bool),
/// An array of constants.
Vec(Vec<Constant>),
Vec(Vec<Self>),
/// Also an array, but with only one constant, repeated N times.
Repeat(Box<Constant>, u64),
Repeat(Box<Self>, u64),
/// A tuple of constants.
Tuple(Vec<Constant>),
Tuple(Vec<Self>),
/// A raw pointer.
RawPtr(u128),
/// A reference
Ref(Box<Constant>),
Ref(Box<Self>),
/// A literal with syntax error.
Err,
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/sugg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub enum Sugg<'a> {
/// or `-`, but only if the type with and without the operator is kept identical.
/// It means that doubling the operator can be used to remove it instead, in
/// order to provide better suggestions.
UnOp(UnOp, Box<Sugg<'a>>),
UnOp(UnOp, Box<Self>),
}

/// Literal constant `0`, for convenience.
Expand Down
3 changes: 3 additions & 0 deletions tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
recursive-self-in-struct
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
Expand Down Expand Up @@ -161,6 +162,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
recursive-self-in-struct
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
Expand Down Expand Up @@ -256,6 +258,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
recursive-self-in-struct
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
Expand Down
134 changes: 134 additions & 0 deletions tests/ui/use_self_structs.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#![warn(clippy::use_self)]
#![allow(clippy::type_complexity)]

fn main() {}

struct Basic {
flag: Option<Box<Self>>,
//~^ use_self
}

struct BasicSelf {
okay: Option<Box<Self>>,
}

struct Generic<'q, T: From<u8>> {
t: &'q T,
flag: Option<Box<Self>>,
//~^ use_self
}

struct GenericSelf<'q, T: From<u8>> {
t: &'q T,
okay: Option<Box<Self>>,
}

struct MixedLifetimes<'q, T: From<u8> + 'static> {
t: &'q T,
okay: Option<Box<MixedLifetimes<'static, T>>>,
}

struct ConcreteType<'q, T: From<u8>> {
t: &'q T,
okay: Option<Box<ConcreteType<'q, u64>>>,
}

struct ConcreteAndGeneric<'q, T: From<u8>> {
t: &'q T,
flag: Option<Box<Self>>,
//~^ use_self
okay: Option<Box<ConcreteAndGeneric<'q, u64>>>,
}

struct ConcreteAndGenericSelf<'q, T: From<u8>> {
t: &'q T,
okay_1: Option<Box<Self>>,
okay_2: Option<Box<ConcreteAndGeneric<'q, u64>>>,
}

macro_rules! recursive_struct {
($name:ident) => {
struct $name {
okay: Option<Box<$name>>,
}
};
}

recursive_struct!(X);
recursive_struct!(Y);
recursive_struct!(Z);

struct Tree {
left: Option<Box<Self>>,
//~^ use_self
right: Option<Box<Self>>,
//~^ use_self
}

struct TreeSelf {
left: Option<Box<Self>>,
right: Option<Box<Self>>,
}

struct TreeMixed {
left: Option<Box<Self>>,
right: Option<Box<Self>>,
//~^ use_self
}

struct Nested {
flag: Option<Box<Option<Box<Self>>>>,
//~^ use_self
}

struct NestedSelf {
okay: Option<Box<Option<Box<Self>>>>,
}

struct Tuple(Option<Box<Self>>);
//~^ use_self

struct TupleSelf(Option<Box<Self>>);

use std::cell::RefCell;
use std::rc::{Rc, Weak};

struct Containers {
flag: Vec<Option<Rc<RefCell<Weak<Vec<Box<Self>>>>>>>,
//~^ use_self
}

struct ContainersSelf {
okay: Vec<Option<Rc<RefCell<Weak<Vec<Box<Self>>>>>>>,
}

type Wrappers<T> = Vec<Option<Rc<RefCell<Weak<Vec<Box<T>>>>>>>;

struct Alias {
flag: Wrappers<Self>,
//~^ use_self
}

struct AliasSelf {
okay: Wrappers<Self>,
}

struct Array<const N: usize> {
flag: [Option<Box<Self>>; N],
//~^ use_self
}

struct ArraySelf<const N: usize> {
okay: [Option<Box<Self>>; N],
}

enum Enum {
Nil,
Cons(Box<Self>),
//~^ use_self
}

enum EnumSelf {
Nil,
Cons(Box<Self>),
}
Loading