Skip to content

Commit 6379d26

Browse files
committed
Auto merge of #7288 - camsteffen:use-self2, r=phansch
Fix use_self FPs on type params changelog: Fix [`use_self`] false positives on type parameters Fixes #4140 Fixes #7139
2 parents f1f5ccd + 29b4b4c commit 6379d26

File tree

4 files changed

+101
-131
lines changed

4 files changed

+101
-131
lines changed

clippy_lints/src/use_self.rs

+52-128
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::snippet_opt;
32
use clippy_utils::ty::same_type_and_consts;
43
use clippy_utils::{in_macro, meets_msrv, msrvs};
54
use if_chain::if_chain;
65
use rustc_errors::Applicability;
76
use rustc_hir::{
87
self as hir,
9-
def::{self, DefKind},
8+
def::{CtorOf, DefKind, Res},
109
def_id::LocalDefId,
1110
intravisit::{walk_ty, NestedVisitorMap, Visitor},
12-
Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment,
13-
QPath, TyKind,
11+
Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, QPath, TyKind,
1412
};
1513
use rustc_lint::{LateContext, LateLintPass, LintContext};
1614
use rustc_middle::hir::map::Map;
1715
use rustc_middle::ty::{AssocKind, Ty};
1816
use rustc_semver::RustcVersion;
1917
use rustc_session::{declare_tool_lint, impl_lint_pass};
20-
use rustc_span::{BytePos, Span};
18+
use rustc_span::Span;
2119
use rustc_typeck::hir_ty_to_ty;
2220

2321
declare_clippy_lint! {
@@ -234,111 +232,58 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
234232
}
235233

236234
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
237-
if in_macro(hir_ty.span)
238-
|| in_impl(cx, hir_ty)
239-
|| !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS)
240-
{
241-
return;
242-
}
243-
244-
let lint_dependend_on_expr_kind = if let Some(StackItem::Check {
245-
hir_id,
246-
types_to_lint,
247-
types_to_skip,
248-
..
249-
}) = self.stack.last()
250-
{
251-
if types_to_skip.contains(&hir_ty.hir_id) {
252-
false
253-
} else if types_to_lint.contains(&hir_ty.hir_id) {
254-
true
255-
} else {
256-
let self_ty = ty_from_hir_id(cx, *hir_id);
257-
should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
258-
}
259-
} else {
260-
false
261-
};
262-
263-
if lint_dependend_on_expr_kind {
264-
// FIXME: this span manipulation should not be necessary
265-
// @flip1995 found an ast lowering issue in
266-
// https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#l142-l162
235+
if_chain! {
236+
if !in_macro(hir_ty.span) && !in_impl(cx, hir_ty);
237+
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
238+
if let Some(StackItem::Check {
239+
hir_id,
240+
types_to_lint,
241+
types_to_skip,
242+
..
243+
}) = self.stack.last();
244+
if !types_to_skip.contains(&hir_ty.hir_id);
245+
if types_to_lint.contains(&hir_ty.hir_id)
246+
|| {
247+
let self_ty = ty_from_hir_id(cx, *hir_id);
248+
should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
249+
};
267250
let hir = cx.tcx.hir();
268251
let id = hir.get_parent_node(hir_ty.hir_id);
269-
270-
if !hir.opt_span(id).map_or(false, in_macro) {
271-
match hir.find(id) {
272-
Some(Node::Expr(Expr {
273-
kind: ExprKind::Path(QPath::TypeRelative(_, segment)),
274-
..
275-
})) => span_lint_until_last_segment(cx, hir_ty.span, segment),
276-
_ => span_lint(cx, hir_ty.span),
277-
}
252+
if !hir.opt_span(id).map_or(false, in_macro);
253+
then {
254+
span_lint(cx, hir_ty.span);
278255
}
279256
}
280257
}
281258

282259
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
283-
fn expr_ty_matches(cx: &LateContext<'_>, expr: &Expr<'_>, self_ty: Ty<'_>) -> bool {
284-
let def_id = expr.hir_id.owner;
285-
if cx.tcx.has_typeck_results(def_id) {
286-
cx.tcx.typeck(def_id).expr_ty_opt(expr) == Some(self_ty)
287-
} else {
288-
false
289-
}
290-
}
291-
292-
if in_macro(expr.span) || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) {
293-
return;
260+
if_chain! {
261+
if !in_macro(expr.span);
262+
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
263+
if let Some(StackItem::Check { hir_id, .. }) = self.stack.last();
264+
if cx.typeck_results().expr_ty(expr) == ty_from_hir_id(cx, *hir_id);
265+
then {} else { return; }
294266
}
295-
296-
if let Some(StackItem::Check { hir_id, .. }) = self.stack.last() {
297-
let self_ty = ty_from_hir_id(cx, *hir_id);
298-
299-
match &expr.kind {
300-
ExprKind::Struct(QPath::Resolved(_, path), ..) => {
301-
if expr_ty_matches(cx, expr, self_ty) {
302-
match path.res {
303-
def::Res::SelfTy(..) => (),
304-
def::Res::Def(DefKind::Variant, _) => span_lint_on_path_until_last_segment(cx, path),
305-
_ => {
306-
span_lint(cx, path.span);
307-
},
308-
}
309-
}
310-
},
311-
// tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
312-
ExprKind::Call(fun, _) => {
313-
if let Expr {
314-
kind: ExprKind::Path(ref qpath),
315-
..
316-
} = fun
317-
{
318-
if expr_ty_matches(cx, expr, self_ty) {
319-
let res = cx.qpath_res(qpath, fun.hir_id);
320-
321-
if let def::Res::Def(DefKind::Ctor(ctor_of, _), ..) = res {
322-
match ctor_of {
323-
def::CtorOf::Variant => {
324-
span_lint_on_qpath_resolved(cx, qpath, true);
325-
},
326-
def::CtorOf::Struct => {
327-
span_lint_on_qpath_resolved(cx, qpath, false);
328-
},
329-
}
330-
}
267+
match expr.kind {
268+
ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
269+
Res::SelfTy(..) => (),
270+
Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
271+
_ => span_lint(cx, path.span),
272+
},
273+
// tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
274+
ExprKind::Call(fun, _) => {
275+
if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
276+
if let Res::Def(DefKind::Ctor(ctor_of, _), ..) = path.res {
277+
match ctor_of {
278+
CtorOf::Variant => lint_path_to_variant(cx, path),
279+
CtorOf::Struct => span_lint(cx, path.span),
331280
}
332281
}
333-
},
334-
// unit enum variants (`Enum::A`)
335-
ExprKind::Path(qpath) => {
336-
if expr_ty_matches(cx, expr, self_ty) {
337-
span_lint_on_qpath_resolved(cx, qpath, true);
338-
}
339-
},
340-
_ => (),
341-
}
282+
}
283+
},
284+
// unit enum variants (`Enum::A`)
285+
ExprKind::Path(QPath::Resolved(_, path)) => lint_path_to_variant(cx, path),
286+
_ => (),
342287
}
343288
}
344289

@@ -405,33 +350,12 @@ fn span_lint(cx: &LateContext<'_>, span: Span) {
405350
);
406351
}
407352

408-
#[allow(clippy::cast_possible_truncation)]
409-
fn span_lint_until_last_segment(cx: &LateContext<'_>, span: Span, segment: &PathSegment<'_>) {
410-
let sp = span.with_hi(segment.ident.span.lo());
411-
// remove the trailing ::
412-
let span_without_last_segment = match snippet_opt(cx, sp) {
413-
Some(snippet) => match snippet.rfind("::") {
414-
Some(bidx) => sp.with_hi(sp.lo() + BytePos(bidx as u32)),
415-
None => sp,
416-
},
417-
None => sp,
418-
};
419-
span_lint(cx, span_without_last_segment);
420-
}
421-
422-
fn span_lint_on_path_until_last_segment(cx: &LateContext<'_>, path: &Path<'_>) {
423-
if path.segments.len() > 1 {
424-
span_lint_until_last_segment(cx, path.span, path.segments.last().unwrap());
425-
}
426-
}
427-
428-
fn span_lint_on_qpath_resolved(cx: &LateContext<'_>, qpath: &QPath<'_>, until_last_segment: bool) {
429-
if let QPath::Resolved(_, path) = qpath {
430-
if until_last_segment {
431-
span_lint_on_path_until_last_segment(cx, path);
432-
} else {
433-
span_lint(cx, path.span);
434-
}
353+
fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
354+
if let [.., self_seg, _variant] = path.segments {
355+
let span = path
356+
.span
357+
.with_hi(self_seg.args().span_ext().unwrap_or(self_seg.ident.span).hi());
358+
span_lint(cx, span);
435359
}
436360
}
437361

@@ -462,7 +386,7 @@ fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool {
462386
if same_type_and_consts(ty, self_ty);
463387
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
464388
then {
465-
!matches!(path.res, def::Res::SelfTy(..))
389+
!matches!(path.res, Res::SelfTy(..) | Res::Def(DefKind::TyParam, _))
466390
} else {
467391
false
468392
}

tests/ui/use_self.fixed

+23
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,26 @@ mod issue7206 {
492492
}
493493
}
494494
}
495+
496+
mod self_is_ty_param {
497+
trait Trait {
498+
type Type;
499+
type Hi;
500+
501+
fn test();
502+
}
503+
504+
impl<I> Trait for I
505+
where
506+
I: Iterator,
507+
I::Item: Trait, // changing this to Self would require <Self as Iterator>
508+
{
509+
type Type = I;
510+
type Hi = I::Item;
511+
512+
fn test() {
513+
let _: I::Item;
514+
let _: I; // this could lint, but is questionable
515+
}
516+
}
517+
}

tests/ui/use_self.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ mod generics {
279279
impl<T> Foo<T> {
280280
// `Self` is applicable here
281281
fn foo(value: T) -> Foo<T> {
282-
Foo { value }
282+
Foo::<T> { value }
283283
}
284284

285285
// `Cannot` use `Self` as a return type as the generic types are different
@@ -492,3 +492,26 @@ mod issue7206 {
492492
}
493493
}
494494
}
495+
496+
mod self_is_ty_param {
497+
trait Trait {
498+
type Type;
499+
type Hi;
500+
501+
fn test();
502+
}
503+
504+
impl<I> Trait for I
505+
where
506+
I: Iterator,
507+
I::Item: Trait, // changing this to Self would require <Self as Iterator>
508+
{
509+
type Type = I;
510+
type Hi = I::Item;
511+
512+
fn test() {
513+
let _: I::Item;
514+
let _: I; // this could lint, but is questionable
515+
}
516+
}
517+
}

tests/ui/use_self.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ LL | fn foo(value: T) -> Foo<T> {
153153
error: unnecessary structure name repetition
154154
--> $DIR/use_self.rs:282:13
155155
|
156-
LL | Foo { value }
157-
| ^^^ help: use the applicable keyword: `Self`
156+
LL | Foo::<T> { value }
157+
| ^^^^^^^^ help: use the applicable keyword: `Self`
158158

159159
error: unnecessary structure name repetition
160160
--> $DIR/use_self.rs:454:13

0 commit comments

Comments
 (0)