@@ -74,6 +74,51 @@ declare_clippy_lint! {
74
74
"declaring `const` with interior mutability"
75
75
}
76
76
77
+ declare_clippy_lint ! {
78
+ /// ### What it does
79
+ ///
80
+ /// Checks whether a global variable defined.
81
+ ///
82
+ /// ### Why restrict this?
83
+ ///
84
+ /// - Global variables can be modified from any part of the program, making it difficult to
85
+ /// track and control their state.
86
+ /// - Global variables introduce implicit dependencies that are not visible in function
87
+ /// signatures, making the code harder to understand and maintain.
88
+ /// - Global variables introduce persistent state, complicating unit tests and making them
89
+ /// prone to side effects.
90
+ /// - Global variables create tight coupling between different parts of the program, making it
91
+ /// harder to modify one part without affecting others.
92
+ ///
93
+ /// ### Example
94
+ ///
95
+ /// ```no_run
96
+ /// use std::sync::Mutex;
97
+ ///
98
+ /// struct State {}
99
+ ///
100
+ /// static STATE: Mutex<State> = Mutex::new(State {});
101
+ ///
102
+ /// fn foo() {
103
+ /// // Access global variable `STATE`.
104
+ /// }
105
+ /// ```
106
+ ///
107
+ /// Use instead:
108
+ ///
109
+ /// ```no_run
110
+ /// struct State {}
111
+ ///
112
+ /// fn foo(state: &mut State) {
113
+ /// // Access `state` argument instead of a global variable.
114
+ /// }
115
+ /// ```
116
+ #[ clippy:: version = "1.88.0" ]
117
+ pub GLOBAL_VARIABLES ,
118
+ nursery,
119
+ "declaring global variables"
120
+ }
121
+
77
122
// FIXME: this is a correctness problem but there's no suitable
78
123
// warn-by-default category.
79
124
declare_clippy_lint ! {
@@ -115,7 +160,8 @@ declare_clippy_lint! {
115
160
116
161
#[ derive( Copy , Clone ) ]
117
162
enum Source < ' tcx > {
118
- Item { item : Span , ty : Ty < ' tcx > } ,
163
+ ConstItem { item : Span , ty : Ty < ' tcx > } ,
164
+ StaticItem { item : Span } ,
119
165
Assoc { item : Span } ,
120
166
Expr { expr : Span } ,
121
167
}
@@ -124,11 +170,12 @@ impl Source<'_> {
124
170
#[ must_use]
125
171
fn lint ( & self ) -> ( & ' static Lint , & ' static str , Span ) {
126
172
match self {
127
- Self :: Item { item, .. } | Self :: Assoc { item, .. } => (
173
+ Self :: ConstItem { item, .. } | Self :: Assoc { item, .. } => (
128
174
DECLARE_INTERIOR_MUTABLE_CONST ,
129
175
"a `const` item should not be interior mutable" ,
130
176
* item,
131
177
) ,
178
+ Self :: StaticItem { item } => ( GLOBAL_VARIABLES , "global variable should not be used" , * item) ,
132
179
Self :: Expr { expr } => (
133
180
BORROW_INTERIOR_MUTABLE_CONST ,
134
181
"a `const` item with interior mutability should not be borrowed" ,
@@ -145,7 +192,7 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
145
192
return ; // Don't give suggestions into macros.
146
193
}
147
194
match source {
148
- Source :: Item { ty, .. } => {
195
+ Source :: ConstItem { ty, .. } => {
149
196
let Some ( sync_trait) = cx. tcx . lang_items ( ) . sync_trait ( ) else {
150
197
return ;
151
198
} ;
@@ -157,6 +204,9 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
157
204
) ;
158
205
}
159
206
} ,
207
+ Source :: StaticItem { .. } => {
208
+ diag. help ( "consider passing this as function arguments or using a `thread_local`" ) ;
209
+ } ,
160
210
Source :: Assoc { .. } => ( ) ,
161
211
Source :: Expr { .. } => {
162
212
diag. help ( "assign this const to a local or static variable, and use the variable here" ) ;
@@ -169,7 +219,7 @@ pub struct NonCopyConst<'tcx> {
169
219
interior_mut : InteriorMut < ' tcx > ,
170
220
}
171
221
172
- impl_lint_pass ! ( NonCopyConst <' _> => [ DECLARE_INTERIOR_MUTABLE_CONST , BORROW_INTERIOR_MUTABLE_CONST ] ) ;
222
+ impl_lint_pass ! ( NonCopyConst <' _> => [ DECLARE_INTERIOR_MUTABLE_CONST , GLOBAL_VARIABLES , BORROW_INTERIOR_MUTABLE_CONST ] ) ;
173
223
174
224
impl < ' tcx > NonCopyConst < ' tcx > {
175
225
pub fn new ( tcx : TyCtxt < ' tcx > , conf : & ' static Conf ) -> Self {
@@ -310,14 +360,27 @@ impl<'tcx> NonCopyConst<'tcx> {
310
360
311
361
impl < ' tcx > LateLintPass < ' tcx > for NonCopyConst < ' tcx > {
312
362
fn check_item ( & mut self , cx : & LateContext < ' tcx > , it : & ' tcx Item < ' _ > ) {
313
- if let ItemKind :: Const ( .., body_id) = it. kind {
314
- let ty = cx. tcx . type_of ( it. owner_id ) . instantiate_identity ( ) ;
315
- if !ignored_macro ( cx, it)
316
- && self . interior_mut . is_interior_mut_ty ( cx, ty)
317
- && Self :: is_value_unfrozen_poly ( cx, body_id, ty)
318
- {
319
- lint ( cx, Source :: Item { item : it. span , ty } ) ;
320
- }
363
+ let tcx = cx. tcx ;
364
+
365
+ match it. kind {
366
+ ItemKind :: Const ( .., body_id) => {
367
+ let ty = tcx. type_of ( it. owner_id ) . instantiate_identity ( ) ;
368
+ if !ignored_macro ( cx, it)
369
+ && self . interior_mut . is_interior_mut_ty ( cx, ty)
370
+ && Self :: is_value_unfrozen_poly ( cx, body_id, ty)
371
+ {
372
+ lint ( cx, Source :: ConstItem { item : it. span , ty } ) ;
373
+ }
374
+ } ,
375
+ ItemKind :: Static ( ..) => {
376
+ let ty = tcx. type_of ( it. owner_id ) . instantiate_identity ( ) ;
377
+
378
+ if !tcx. is_thread_local_static ( it. owner_id . to_def_id ( ) ) && self . interior_mut . is_interior_mut_ty ( cx, ty)
379
+ {
380
+ lint ( cx, Source :: StaticItem { item : it. span } ) ;
381
+ }
382
+ } ,
383
+ _ => { } ,
321
384
}
322
385
}
323
386
0 commit comments