@@ -9,7 +9,8 @@ declare_clippy_lint! {
9
9
/// Warns about needless / redundant type annotations.
10
10
///
11
11
/// ### 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.
13
14
///
14
15
/// ### Example
15
16
/// ```rust
@@ -22,91 +23,101 @@ declare_clippy_lint! {
22
23
#[ clippy:: version = "1.70.0" ]
23
24
pub REDUNDANT_TYPE_ANNOTATIONS ,
24
25
pedantic,
25
- "Warns about needless / redundant type annotations."
26
+ "warns about needless / redundant type annotations."
26
27
}
27
28
declare_lint_pass ! ( RedundantTypeAnnotations => [ REDUNDANT_TYPE_ANNOTATIONS ] ) ;
28
29
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 {
30
31
// type annotation is primitive
31
- if let hir:: def:: Res :: PrimTy ( primty) = res
32
+ if let hir:: def:: Res :: PrimTy ( primty) = ty_resolved_path
32
33
&& func_return_type. is_primitive ( )
33
34
&& let Some ( func_return_type_sym) = func_return_type. primitive_symbol ( )
34
35
{
35
- return primty. name ( ) == func_return_type_sym;
36
- }
36
+ return primty. name ( ) == func_return_type_sym;
37
+ }
37
38
38
39
// 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
40
41
&& let Some ( annotation_ty) = cx. tcx . type_of ( defid) . no_bound_vars ( )
41
42
{
42
- return annotation_ty == func_return_type
43
- }
43
+ return annotation_ty == func_return_type;
44
+ }
44
45
45
46
false
46
47
}
47
48
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 > (
49
51
cx : & LateContext < ' tcx > ,
50
- res : hir:: def :: Res ,
52
+ call : & hir:: Expr < ' tcx > ,
51
53
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 > > {
57
55
match func_return_path {
58
56
// let a: String = f(); where f: fn f() -> String
59
57
hir:: QPath :: Resolved ( _, resolved_path) => {
60
58
if let hir:: def:: Res :: Def ( _, defid) = resolved_path. res
61
59
&& 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 ( )
64
60
{
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
+ }
69
65
} ,
66
+ // Associated functions like
70
67
// 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 ( )
79
73
{
80
- return annotation_ty == init_ty
74
+ Some ( init_ty)
75
+ } else {
76
+ None
81
77
}
82
-
83
- false
84
78
} ,
85
- hir:: QPath :: LangItem ( ..) => false ,
79
+ hir:: QPath :: LangItem ( ..) => None ,
86
80
}
87
81
}
88
82
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
+
89
102
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
92
105
if let Some ( ty) = & local. ty
93
106
&& let hir:: TyKind :: Path ( ty_path) = & ty. kind
94
107
&& let hir:: QPath :: Resolved ( _, resolved_path_ty) = ty_path
95
108
96
109
// initialization part
97
110
&& let Some ( init) = local. init
98
111
{
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) => {
110
121
if let hir:: def:: Res :: PrimTy ( primty) = resolved_path_ty. res
111
122
112
123
&& let hir:: QPath :: TypeRelative ( init_ty, _) = init_path
@@ -116,10 +127,10 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
116
127
117
128
&& primty == primty_init
118
129
{
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
+ _ => ( )
123
134
}
124
135
} ;
125
136
}
0 commit comments