@@ -74,6 +74,51 @@ declare_clippy_lint! {
7474 "declaring `const` with interior mutability"
7575}
7676
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+
77122// FIXME: this is a correctness problem but there's no suitable
78123// warn-by-default category.
79124declare_clippy_lint ! {
@@ -115,7 +160,8 @@ declare_clippy_lint! {
115160
116161#[ derive( Copy , Clone ) ]
117162enum Source < ' tcx > {
118- Item { item : Span , ty : Ty < ' tcx > } ,
163+ ConstItem { item : Span , ty : Ty < ' tcx > } ,
164+ StaticItem { item : Span } ,
119165 Assoc { item : Span } ,
120166 Expr { expr : Span } ,
121167}
@@ -124,11 +170,12 @@ impl Source<'_> {
124170 #[ must_use]
125171 fn lint ( & self ) -> ( & ' static Lint , & ' static str , Span ) {
126172 match self {
127- Self :: Item { item, .. } | Self :: Assoc { item, .. } => (
173+ Self :: ConstItem { item, .. } | Self :: Assoc { item, .. } => (
128174 DECLARE_INTERIOR_MUTABLE_CONST ,
129175 "a `const` item should not be interior mutable" ,
130176 * item,
131177 ) ,
178+ Self :: StaticItem { item } => ( GLOBAL_VARIABLES , "global variable should not be used" , * item) ,
132179 Self :: Expr { expr } => (
133180 BORROW_INTERIOR_MUTABLE_CONST ,
134181 "a `const` item with interior mutability should not be borrowed" ,
@@ -145,7 +192,7 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
145192 return ; // Don't give suggestions into macros.
146193 }
147194 match source {
148- Source :: Item { ty, .. } => {
195+ Source :: ConstItem { ty, .. } => {
149196 let Some ( sync_trait) = cx. tcx . lang_items ( ) . sync_trait ( ) else {
150197 return ;
151198 } ;
@@ -157,6 +204,9 @@ fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
157204 ) ;
158205 }
159206 } ,
207+ Source :: StaticItem { .. } => {
208+ diag. help ( "consider passing this as function arguments or using a `thread_local`" ) ;
209+ } ,
160210 Source :: Assoc { .. } => ( ) ,
161211 Source :: Expr { .. } => {
162212 diag. help ( "assign this const to a local or static variable, and use the variable here" ) ;
@@ -169,7 +219,7 @@ pub struct NonCopyConst<'tcx> {
169219 interior_mut : InteriorMut < ' tcx > ,
170220}
171221
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 ] ) ;
173223
174224impl < ' tcx > NonCopyConst < ' tcx > {
175225 pub fn new ( tcx : TyCtxt < ' tcx > , conf : & ' static Conf ) -> Self {
@@ -310,14 +360,27 @@ impl<'tcx> NonCopyConst<'tcx> {
310360
311361impl < ' tcx > LateLintPass < ' tcx > for NonCopyConst < ' tcx > {
312362 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+ _ => { } ,
321384 }
322385 }
323386
0 commit comments