1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::is_from_proc_macro
;
3 use clippy_utils
::msrvs
::{self, Msrv}
;
4 use clippy_utils
::ty
::same_type_and_consts
;
5 use if_chain
::if_chain
;
6 use rustc_data_structures
::fx
::FxHashSet
;
7 use rustc_errors
::Applicability
;
10 def
::{CtorOf, DefKind, Res}
,
12 intravisit
::{walk_inf, walk_ty, Visitor}
,
13 Expr
, ExprKind
, FnRetTy
, FnSig
, GenericArg
, HirId
, Impl
, ImplItemKind
, Item
, ItemKind
, Pat
, PatKind
, Path
, QPath
,
16 use rustc_hir_analysis
::hir_ty_to_ty
;
17 use rustc_lint
::{LateContext, LateLintPass}
;
18 use rustc_session
::{declare_tool_lint, impl_lint_pass}
;
21 declare_clippy_lint
! {
23 /// Checks for unnecessary repetition of structure name when a
24 /// replacement with `Self` is applicable.
26 /// ### Why is this bad?
27 /// Unnecessary repetition. Mixed use of `Self` and struct
29 /// feels inconsistent.
31 /// ### Known problems
32 /// - Unaddressed false negative in fn bodies of trait implementations
47 /// fn new() -> Self {
52 #[clippy::version = "pre 1.29.0"]
55 "unnecessary structure name repetition whereas `Self` is applicable"
61 stack
: Vec
<StackItem
>,
66 pub fn new(msrv
: Msrv
) -> Self {
79 types_to_skip
: FxHashSet
<HirId
>,
84 impl_lint_pass
!(UseSelf
=> [USE_SELF
]);
86 const SEGMENTS_MSG
: &str = "segments should be composed of at least 1 element";
88 impl<'tcx
> LateLintPass
<'tcx
> for UseSelf
{
89 fn check_item(&mut self, cx
: &LateContext
<'tcx
>, item
: &Item
<'tcx
>) {
90 if matches
!(item
.kind
, ItemKind
::OpaqueTy(_
)) {
91 // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>`
94 // We push the self types of `impl`s on a stack here. Only the top type on the stack is
95 // relevant for linting, since this is the self type of the `impl` we're currently in. To
96 // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
97 // we're in an `impl` or nested item, that we don't want to lint
98 let stack_item
= if_chain
! {
99 if let ItemKind
::Impl(Impl { self_ty, .. }
) = item
.kind
;
100 if let TyKind
::Path(QPath
::Resolved(_
, item_path
)) = self_ty
.kind
;
101 let parameters
= &item_path
.segments
.last().expect(SEGMENTS_MSG
).args
;
102 if parameters
.as_ref().map_or(true, |params
| {
103 !params
.parenthesized
&& !params
.args
.iter().any(|arg
| matches
!(arg
, GenericArg
::Lifetime(_
)))
105 if !item
.span
.from_expansion();
106 if !is_from_proc_macro(cx
, item
); // expensive, should be last check
109 impl_id
: item
.owner_id
.def_id
,
111 types_to_skip
: std
::iter
::once(self_ty
.hir_id
).collect(),
117 self.stack
.push(stack_item
);
120 fn check_item_post(&mut self, _
: &LateContext
<'_
>, item
: &Item
<'_
>) {
121 if !matches
!(item
.kind
, ItemKind
::OpaqueTy(_
)) {
126 fn check_impl_item(&mut self, cx
: &LateContext
<'_
>, impl_item
: &hir
::ImplItem
<'_
>) {
127 // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
128 // declaration. The collection of those types is all this method implementation does.
130 if let ImplItemKind
::Fn(FnSig { decl, .. }
, ..) = impl_item
.kind
;
131 if let Some(&mut StackItem
::Check
{
133 ref mut types_to_skip
,
135 }) = self.stack
.last_mut();
136 if let Some(impl_trait_ref
) = cx
.tcx
.impl_trait_ref(impl_id
);
138 // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
140 let self_ty
= impl_trait_ref
.subst_identity().self_ty();
142 // `trait_method_sig` is the signature of the function, how it is declared in the
143 // trait, not in the impl of the trait.
144 let trait_method
= cx
146 .associated_item(impl_item
.owner_id
)
148 .expect("impl method matches a trait method");
149 let trait_method_sig
= cx
.tcx
.fn_sig(trait_method
);
150 let trait_method_sig
= cx
.tcx
.erase_late_bound_regions(trait_method_sig
);
152 // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
153 // implementation of the trait.
154 let output_hir_ty
= if let FnRetTy
::Return(ty
) = &decl
.output
{
159 let impl_inputs_outputs
= decl
.inputs
.iter().chain(output_hir_ty
);
161 // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
163 // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
164 // trait declaration. This is used to check if `Self` was used in the trait
167 // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
168 // to `Self`), we want to skip linting that type and all subtypes of it. This
169 // avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
170 // for u8`, when the trait always uses `Vec<u8>`.
172 // See also https://github.com/rust-lang/rust-clippy/issues/2894.
173 for (impl_hir_ty
, trait_sem_ty
) in impl_inputs_outputs
.zip(trait_method_sig
.inputs_and_output
) {
174 if trait_sem_ty
.walk().any(|inner
| inner
== self_ty
.into()) {
175 let mut visitor
= SkipTyCollector
::default();
176 visitor
.visit_ty(impl_hir_ty
);
177 types_to_skip
.extend(visitor
.types_to_skip
);
184 fn check_body(&mut self, _
: &LateContext
<'_
>, _
: &hir
::Body
<'_
>) {
185 // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
186 // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
187 // However the `node_type()` method can *only* be called in bodies.
188 if let Some(&mut StackItem
::Check { ref mut in_body, .. }
) = self.stack
.last_mut() {
189 *in_body
= in_body
.saturating_add(1);
193 fn check_body_post(&mut self, _
: &LateContext
<'_
>, _
: &hir
::Body
<'_
>) {
194 if let Some(&mut StackItem
::Check { ref mut in_body, .. }
) = self.stack
.last_mut() {
195 *in_body
= in_body
.saturating_sub(1);
199 fn check_ty(&mut self, cx
: &LateContext
<'_
>, hir_ty
: &hir
::Ty
<'_
>) {
201 if !hir_ty
.span
.from_expansion();
202 if self.msrv
.meets(msrvs
::TYPE_ALIAS_ENUM_VARIANTS
);
203 if let Some(&StackItem
::Check
{
207 }) = self.stack
.last();
208 if let TyKind
::Path(QPath
::Resolved(_
, path
)) = hir_ty
.kind
;
211 Res
::SelfTyParam { .. }
212 | Res
::SelfTyAlias { .. }
213 | Res
::Def(DefKind
::TyParam
, _
)
215 if !types_to_skip
.contains(&hir_ty
.hir_id
);
216 let ty
= if in_body
> 0 {
217 cx
.typeck_results().node_type(hir_ty
.hir_id
)
219 hir_ty_to_ty(cx
.tcx
, hir_ty
)
221 if same_type_and_consts(ty
, cx
.tcx
.type_of(impl_id
));
223 span_lint(cx
, hir_ty
.span
);
228 fn check_expr(&mut self, cx
: &LateContext
<'_
>, expr
: &Expr
<'_
>) {
230 if !expr
.span
.from_expansion();
231 if self.msrv
.meets(msrvs
::TYPE_ALIAS_ENUM_VARIANTS
);
232 if let Some(&StackItem
::Check { impl_id, .. }
) = self.stack
.last();
233 if cx
.typeck_results().expr_ty(expr
) == cx
.tcx
.type_of(impl_id
);
234 then {}
else { return; }
237 ExprKind
::Struct(QPath
::Resolved(_
, path
), ..) => check_path(cx
, path
),
238 ExprKind
::Call(fun
, _
) => {
239 if let ExprKind
::Path(QPath
::Resolved(_
, path
)) = fun
.kind
{
240 check_path(cx
, path
);
243 ExprKind
::Path(QPath
::Resolved(_
, path
)) => check_path(cx
, path
),
248 fn check_pat(&mut self, cx
: &LateContext
<'_
>, pat
: &Pat
<'_
>) {
250 if !pat
.span
.from_expansion();
251 if self.msrv
.meets(msrvs
::TYPE_ALIAS_ENUM_VARIANTS
);
252 if let Some(&StackItem
::Check { impl_id, .. }
) = self.stack
.last();
253 // get the path from the pattern
254 if let PatKind
::Path(QPath
::Resolved(_
, path
))
255 | PatKind
::TupleStruct(QPath
::Resolved(_
, path
), _
, _
)
256 | PatKind
::Struct(QPath
::Resolved(_
, path
), _
, _
) = pat
.kind
;
257 if cx
.typeck_results().pat_ty(pat
) == cx
.tcx
.type_of(impl_id
);
259 check_path(cx
, path
);
264 extract_msrv_attr
!(LateContext
);
268 struct SkipTyCollector
{
269 types_to_skip
: Vec
<HirId
>,
272 impl<'tcx
> Visitor
<'tcx
> for SkipTyCollector
{
273 fn visit_infer(&mut self, inf
: &hir
::InferArg
) {
274 self.types_to_skip
.push(inf
.hir_id
);
278 fn visit_ty(&mut self, hir_ty
: &hir
::Ty
<'_
>) {
279 self.types_to_skip
.push(hir_ty
.hir_id
);
281 walk_ty(self, hir_ty
);
285 fn span_lint(cx
: &LateContext
<'_
>, span
: Span
) {
290 "unnecessary structure name repetition",
291 "use the applicable keyword",
293 Applicability
::MachineApplicable
,
297 fn check_path(cx
: &LateContext
<'_
>, path
: &Path
<'_
>) {
299 Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, _
) | DefKind
::Variant
, ..) => {
300 lint_path_to_variant(cx
, path
);
302 Res
::Def(DefKind
::Ctor(CtorOf
::Struct
, _
) | DefKind
::Struct
, ..) => span_lint(cx
, path
.span
),
307 fn lint_path_to_variant(cx
: &LateContext
<'_
>, path
: &Path
<'_
>) {
308 if let [.., self_seg
, _variant
] = path
.segments
{
311 .with_hi(self_seg
.args().span_ext().unwrap_or(self_seg
.ident
.span
).hi());