Skip to content

Commit b20100c

Browse files
committed
Support associated functions
1 parent efe7f8c commit b20100c

File tree

3 files changed

+88
-65
lines changed

3 files changed

+88
-65
lines changed

clippy_lints/src/redundant_type_annotations.rs

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ declare_clippy_lint! {
99
/// Warns about needless / redundant type annotations.
1010
///
1111
/// ### Why is this bad?
12-
/// Code is more idiomatic, shorter, and easier to modify.
12+
/// Code without type annotations is shorter and in most cases
13+
/// more idiomatic and easier to modify.
1314
///
1415
/// ### Example
1516
/// ```rust
@@ -22,91 +23,101 @@ declare_clippy_lint! {
2223
#[clippy::version = "1.70.0"]
2324
pub REDUNDANT_TYPE_ANNOTATIONS,
2425
pedantic,
25-
"Warns about needless / redundant type annotations."
26+
"warns about needless / redundant type annotations."
2627
}
2728
declare_lint_pass!(RedundantTypeAnnotations => [REDUNDANT_TYPE_ANNOTATIONS]);
2829

29-
fn is_redundant_in_resolved_path<'tcx>(cx: &LateContext<'tcx>, res: hir::def::Res, func_return_type: Ty<'tcx>) -> bool {
30+
fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, func_return_type: Ty<'tcx>) -> bool {
3031
// type annotation is primitive
31-
if let hir::def::Res::PrimTy(primty) = res
32+
if let hir::def::Res::PrimTy(primty) = ty_resolved_path
3233
&& func_return_type.is_primitive()
3334
&& let Some(func_return_type_sym) = func_return_type.primitive_symbol()
3435
{
35-
return primty.name() == func_return_type_sym;
36-
}
36+
return primty.name() == func_return_type_sym;
37+
}
3738

3839
// type annotation is any other non generic type
39-
if let hir::def::Res::Def(_, defid) = res
40+
if let hir::def::Res::Def(_, defid) = ty_resolved_path
4041
&& let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars()
4142
{
42-
return annotation_ty == func_return_type
43-
}
43+
return annotation_ty == func_return_type;
44+
}
4445

4546
false
4647
}
4748

48-
fn is_redundant_in_func_call<'tcx>(
49+
/// Extracts the fn Ty, e.g. `fn() -> std::string::String {f}`
50+
fn extract_fn_ty<'tcx>(
4951
cx: &LateContext<'tcx>,
50-
res: hir::def::Res,
52+
call: &hir::Expr<'tcx>,
5153
func_return_path: &hir::QPath<'tcx>,
52-
) -> bool {
53-
// TODO: Problem with something like
54-
// let a: String = StructTest::func() where func returns String::from
55-
// The problem is that the DefId that I get refers to the struct itself and not to string
56-
54+
) -> Option<Ty<'tcx>> {
5755
match func_return_path {
5856
// let a: String = f(); where f: fn f() -> String
5957
hir::QPath::Resolved(_, resolved_path) => {
6058
if let hir::def::Res::Def(_, defid) = resolved_path.res
6159
&& let Some(middle_ty_init) = cx.tcx.type_of(defid).no_bound_vars()
62-
&& middle_ty_init.is_fn()
63-
&& let Some(init_return_type) = middle_ty_init.fn_sig(cx.tcx).output().no_bound_vars()
6460
{
65-
return is_redundant_in_resolved_path(cx, res, init_return_type);
66-
}
67-
68-
false
61+
Some(middle_ty_init)
62+
} else {
63+
None
64+
}
6965
},
66+
// Associated functions like
7067
// let a: String = String::new();
71-
hir::QPath::TypeRelative(func_hir_ty, _) => {
72-
if let hir::def::Res::Def(_, defid) = res
73-
&& let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars()
74-
75-
&& let hir::TyKind::Path(init_ty_path) = &func_hir_ty.kind
76-
&& let hir::QPath::Resolved(_, resolved_init_ty_path) = init_ty_path
77-
&& let hir::def::Res::Def(_, init_defid) = resolved_init_ty_path.res
78-
&& let Some(init_ty) = cx.tcx.type_of(init_defid).no_bound_vars()
68+
// let a: String = String::get_string();
69+
hir::QPath::TypeRelative(..) => {
70+
if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(call.hir_id)
71+
&& defkind == hir::def::DefKind::AssocFn
72+
&& let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars()
7973
{
80-
return annotation_ty == init_ty
74+
Some(init_ty)
75+
} else {
76+
None
8177
}
82-
83-
false
8478
},
85-
hir::QPath::LangItem(..) => false,
79+
hir::QPath::LangItem(..) => None,
8680
}
8781
}
8882

83+
fn is_redundant_in_func_call<'tcx>(
84+
cx: &LateContext<'tcx>,
85+
ty_resolved_path: hir::def::Res,
86+
call: &hir::Expr<'tcx>,
87+
) -> bool {
88+
if let hir::ExprKind::Path(init_path) = &call.kind {
89+
let func_type = extract_fn_ty(cx, call, init_path);
90+
91+
if let Some(func_type) = func_type
92+
&& func_type.is_fn()
93+
&& let Some(init_return_type) = func_type.fn_sig(cx.tcx).output().no_bound_vars()
94+
{
95+
return is_same_type(cx, ty_resolved_path, init_return_type);
96+
}
97+
}
98+
99+
false
100+
}
101+
89102
impl LateLintPass<'_> for RedundantTypeAnnotations {
90-
fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'_>) {
91-
// type annotation part
103+
fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) {
104+
// type annotation part
92105
if let Some(ty) = &local.ty
93106
&& let hir::TyKind::Path(ty_path) = &ty.kind
94107
&& let hir::QPath::Resolved(_, resolved_path_ty) = ty_path
95108

96109
// initialization part
97110
&& let Some(init) = local.init
98111
{
99-
match &init.kind {
100-
// When the initialization is a call to a function
101-
hir::ExprKind::Call(init_call, _) => {
102-
if let hir::ExprKind::Path(init_path) = &init_call.kind
103-
&& is_redundant_in_func_call(cx, resolved_path_ty.res, init_path)
104-
{
105-
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
106-
}
107-
},
108-
// When the initialization is a path for example u32::MAX
109-
hir::ExprKind::Path(init_path) => {
112+
match &init.kind {
113+
// When the initialization is a call to a function
114+
hir::ExprKind::Call(init_call, _) => {
115+
if is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) {
116+
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
117+
}
118+
},
119+
// When the initialization is a path for example u32::MAX
120+
hir::ExprKind::Path(init_path) => {
110121
if let hir::def::Res::PrimTy(primty) = resolved_path_ty.res
111122

112123
&& let hir::QPath::TypeRelative(init_ty, _) = init_path
@@ -116,10 +127,10 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
116127

117128
&& primty == primty_init
118129
{
119-
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
120-
}
121-
}
122-
_ => ()
130+
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
131+
}
132+
}
133+
_ => ()
123134
}
124135
};
125136
}

tests/ui/redundant_type_annotations.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ impl ATest2 {
3939
fn new() -> Self {
4040
Self { inner: 5 }
4141
}
42+
43+
fn get_string() -> String {
44+
String::from("")
45+
}
4246
}
4347

4448
fn f_prim() -> u32 {
@@ -63,5 +67,7 @@ fn main() {
6367

6468
let a: u32 = u32::MAX;
6569

66-
let a: u32 = ATest2::get_num(); // this should lint but doesn't (DefId refers to ATest2 and not to the func)
70+
let a: u32 = ATest2::get_num();
71+
72+
let a: String = ATest2::get_string();
6773
}
Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,58 @@
11
error: redundant type annotation
2-
--> $DIR/redundant_type_annotations.rs:49:5
2+
--> $DIR/redundant_type_annotations.rs:53:5
33
|
44
LL | let a: String = f();
55
| ^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::redundant-type-annotations` implied by `-D warnings`
88

99
error: redundant type annotation
10-
--> $DIR/redundant_type_annotations.rs:51:5
10+
--> $DIR/redundant_type_annotations.rs:55:5
1111
|
1212
LL | let a: A = f_struct();
1313
| ^^^^^^^^^^^^^^^^^^^^^^
1414

1515
error: redundant type annotation
16-
--> $DIR/redundant_type_annotations.rs:53:5
16+
--> $DIR/redundant_type_annotations.rs:57:5
1717
|
1818
LL | let a: E = f_enum();
1919
| ^^^^^^^^^^^^^^^^^^^^
2020

2121
error: redundant type annotation
22-
--> $DIR/redundant_type_annotations.rs:55:5
22+
--> $DIR/redundant_type_annotations.rs:59:5
2323
|
2424
LL | let a: u32 = f_prim();
2525
| ^^^^^^^^^^^^^^^^^^^^^^
2626

2727
error: redundant type annotation
28-
--> $DIR/redundant_type_annotations.rs:57:5
28+
--> $DIR/redundant_type_annotations.rs:61:5
2929
|
3030
LL | let a: String = String::new();
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3232

3333
error: redundant type annotation
34-
--> $DIR/redundant_type_annotations.rs:59:5
34+
--> $DIR/redundant_type_annotations.rs:63:5
3535
|
3636
LL | let st: ATest2 = ATest2::new();
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838

3939
error: redundant type annotation
40-
--> $DIR/redundant_type_annotations.rs:62:5
40+
--> $DIR/redundant_type_annotations.rs:68:5
4141
|
42-
LL | let a: String = String::from("test");
43-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
LL | let a: u32 = u32::MAX;
43+
| ^^^^^^^^^^^^^^^^^^^^^^
4444

4545
error: redundant type annotation
46-
--> $DIR/redundant_type_annotations.rs:64:5
46+
--> $DIR/redundant_type_annotations.rs:70:5
4747
|
48-
LL | let a: u32 = u32::MAX;
49-
| ^^^^^^^^^^^^^^^^^^^^^^
48+
LL | let a: u32 = ATest2::get_num();
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
51+
error: redundant type annotation
52+
--> $DIR/redundant_type_annotations.rs:72:5
53+
|
54+
LL | let a: String = ATest2::get_string();
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5056

51-
error: aborting due to 8 previous errors
57+
error: aborting due to 9 previous errors
5258

0 commit comments

Comments
 (0)