@@ -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}
2728declare_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+
89102impl 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 }
0 commit comments