1
1
use crate :: rustc_lint:: LintContext ;
2
2
use clippy_utils:: diagnostics:: span_lint_and_help;
3
3
use rustc_hir:: {
4
- intravisit:: FnKind , FnDecl , FnRetTy , GenericArg , GenericBound , GenericParam , GenericParamKind , Generics ,
5
- LifetimeParamKind , ParamName , QPath , Ty , TyKind , TypeBindingKind , WherePredicate ,
4
+ def:: { DefKind , Res } ,
5
+ intravisit:: FnKind ,
6
+ FnDecl , FnRetTy , GenericArg , GenericBound , GenericParam , GenericParamKind , Generics , ItemKind , LifetimeParamKind ,
7
+ Node , ParamName , QPath , Ty , TyKind , TypeBindingKind , WherePredicate ,
6
8
} ;
7
9
use rustc_lint:: LateContext ;
8
- use rustc_middle:: lint:: in_external_macro;
10
+ use rustc_middle:: { hir :: map :: Map , lint:: in_external_macro} ;
9
11
use rustc_span:: Span ;
10
12
11
13
use super :: HIDDEN_STATIC_LIFETIME ;
12
14
13
15
pub ( super ) fn check_fn < ' tcx > ( cx : & LateContext < ' _ > , kind : FnKind < ' tcx > , decl : & ' tcx FnDecl < ' _ > , span : Span ) {
14
- if !in_external_macro ( cx. sess ( ) , span) && let FnKind :: ItemFn ( _, generics, _) = kind {
15
- let mut lifetime_is_used;
16
+ if !in_external_macro ( cx. sess ( ) , span) && let FnKind :: ItemFn ( _, generics, _) =
17
+ kind { let mut lifetime_is_used;
16
18
for generic in generics. params . iter ( ) {
17
19
if let GenericParamKind :: Lifetime { kind } = generic. kind &&
18
20
kind != LifetimeParamKind :: Elided {
@@ -65,8 +67,8 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'t
65
67
bound. span ( ) ,
66
68
"this lifetime can be changed to `'static`" ,
67
69
None ,
68
- & format ! ( "try removing the lifetime parameter `{}` and changing references to `'static`" , generic . name . ident ( ) . as_str ( ) ) ,
69
- ) ;
70
+ & format ! ( "try removing the lifetime parameter `{}` and changing references to `'static`" ,
71
+ generic . name . ident ( ) . as_str ( ) ) , ) ;
70
72
} ;
71
73
} ;
72
74
} ;
@@ -81,25 +83,27 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'t
81
83
region_predicate. span ,
82
84
"this lifetime can be changed to `'static`" ,
83
85
None ,
84
- & format ! ( "try removing the lifetime parameter `{}` and changing references to `'static`" , generic . name . ident ( ) . as_str ( ) ) ,
85
- ) ;
86
+ & format ! ( "try removing the lifetime parameter `{}` and changing references to `'static`" ,
87
+ generic . name . ident ( ) . as_str ( ) ) , ) ;
86
88
} ;
87
89
} ;
88
90
} ;
89
91
} ;
90
92
91
93
// Check again.
92
- if !lifetime_is_used {
94
+ if !lifetime_is_used &&
93
95
// Check validness
94
- if check_validness ( ret_ty, generic, generics) {
96
+ check_validness ( ret_ty, generic, generics)
97
+ && check_mut_fields ( cx. tcx . hir ( ) , & ret_ty. peel_refs ( ) . kind ) {
95
98
span_lint_and_help ( cx,
96
- HIDDEN_STATIC_LIFETIME ,
97
- generic. span ,
98
- "this lifetime can be changed to `'static`" ,
99
- None ,
100
- & format ! ( "try removing the lifetime parameter `{}` and changing references to `'static`" , generic. name. ident( ) . as_str( ) ) ,
99
+ HIDDEN_STATIC_LIFETIME ,
100
+ generic. span ,
101
+ "this lifetime can be changed to `'static`" ,
102
+ None ,
103
+ & format ! (
104
+ "try removing the lifetime parameter `{}` and changing references to `'static`" ,
105
+ generic. name. ident( ) . as_str( ) ) ,
101
106
) ;
102
- } ;
103
107
} ;
104
108
} ;
105
109
} ;
@@ -166,3 +170,38 @@ fn check_validness(ret_ty: &Ty<'_>, generic: &GenericParam<'_>, generics: &Gener
166
170
} ;
167
171
true
168
172
}
173
+
174
+ // true = no mut fields
175
+ fn check_mut_fields ( map : Map < ' _ > , tykind : & TyKind < ' _ > ) -> bool {
176
+ if_chain ! {
177
+ if let TyKind :: Path ( qpath) = tykind;
178
+ if let QPath :: Resolved ( _, path) = qpath;
179
+ if let Res :: Def ( defkind, def_id) = path. res;
180
+ if let DefKind :: Struct = defkind;
181
+ then {
182
+ if let Some ( node) = map. get_if_local( def_id) {
183
+ if let Node :: Item ( item) = node {
184
+ if let ItemKind :: Struct ( variant_data, _) = & item. kind {
185
+ for field in variant_data. fields( ) {
186
+ if let TyKind :: Ref ( _, mut_ty) = & field. ty. kind {
187
+ if mut_ty. mutbl. is_mut( ) {
188
+ return false ;
189
+ } ;
190
+ return true ;
191
+ } else if let TyKind :: Ptr ( mut_ty) = & field. ty. kind {
192
+ if mut_ty. mutbl. is_mut( ) {
193
+ return false ;
194
+ } ;
195
+ return true ;
196
+ }
197
+ }
198
+ }
199
+ } ;
200
+ return true ;
201
+ } ;
202
+ // Don't lint if struct isn't local.
203
+ return false
204
+ }
205
+ } ;
206
+ true
207
+ }
0 commit comments