11use clippy_utils:: desugar_await;
22use clippy_utils:: diagnostics:: span_lint_and_then;
3- use clippy_utils:: visitors:: { Descend , Visitable , for_each_expr} ;
4- use core:: ops:: ControlFlow :: Continue ;
53use hir:: def:: { DefKind , Res } ;
64use hir:: { BlockCheckMode , ExprKind , QPath , UnOp } ;
7- use rustc_ast:: Mutability ;
5+ use rustc_ast:: { BorrowKind , Mutability } ;
86use rustc_hir as hir;
7+ use rustc_hir:: intravisit:: { Visitor , walk_body, walk_expr} ;
98use rustc_lint:: { LateContext , LateLintPass } ;
10- use rustc_middle:: ty;
9+ use rustc_middle:: hir:: nested_filter;
10+ use rustc_middle:: ty:: { self , TypeckResults } ;
1111use rustc_session:: declare_lint_pass;
1212use rustc_span:: { DesugaringKind , Span } ;
1313
@@ -70,8 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
7070 {
7171 return ;
7272 }
73- let mut unsafe_ops = vec ! [ ] ;
74- collect_unsafe_exprs ( cx, block, & mut unsafe_ops) ;
73+ let unsafe_ops = UnsafeExprCollector :: collect_unsafe_exprs ( cx, block) ;
7574 if unsafe_ops. len ( ) > 1 {
7675 span_lint_and_then (
7776 cx,
@@ -91,25 +90,47 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
9190 }
9291}
9392
94- fn collect_unsafe_exprs < ' tcx > (
95- cx : & LateContext < ' tcx > ,
96- node : impl Visitable < ' tcx > ,
97- unsafe_ops : & mut Vec < ( & ' static str , Span ) > ,
98- ) {
99- for_each_expr ( cx, node, |expr| {
93+ struct UnsafeExprCollector < ' cx , ' tcx > {
94+ cx : & ' cx LateContext < ' tcx > ,
95+ typeck_results : & ' tcx TypeckResults < ' tcx > ,
96+ unsafe_ops : Vec < ( & ' static str , Span ) > ,
97+ }
98+
99+ impl < ' cx , ' tcx > UnsafeExprCollector < ' cx , ' tcx > {
100+ fn collect_unsafe_exprs ( cx : & ' cx LateContext < ' tcx > , block : & ' tcx hir:: Block < ' tcx > ) -> Vec < ( & ' static str , Span ) > {
101+ let mut collector = Self {
102+ cx,
103+ typeck_results : cx. typeck_results ( ) ,
104+ unsafe_ops : vec ! [ ] ,
105+ } ;
106+ collector. visit_block ( block) ;
107+ collector. unsafe_ops
108+ }
109+ }
110+
111+ impl < ' tcx > Visitor < ' tcx > for UnsafeExprCollector < ' _ , ' tcx > {
112+ type NestedFilter = nested_filter:: OnlyBodies ;
113+
114+ fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
100115 match expr. kind {
101116 // The `await` itself will desugar to two unsafe calls, but we should ignore those.
102117 // Instead, check the expression that is `await`ed
103118 _ if let Some ( e) = desugar_await ( expr) => {
104- collect_unsafe_exprs ( cx, e, unsafe_ops) ;
105- return Continue ( Descend :: No ) ;
119+ return self . visit_expr ( e) ;
106120 } ,
107121
108- ExprKind :: InlineAsm ( _) => unsafe_ops. push ( ( "inline assembly used here" , expr. span ) ) ,
122+ ExprKind :: InlineAsm ( _) => self . unsafe_ops . push ( ( "inline assembly used here" , expr. span ) ) ,
123+
124+ ExprKind :: AddrOf ( BorrowKind :: Raw , _, mut inner) => {
125+ while let ExprKind :: Field ( prefix, _) = inner. kind {
126+ inner = prefix;
127+ }
128+ return self . visit_expr ( inner) ;
129+ } ,
109130
110131 ExprKind :: Field ( e, _) => {
111- if cx . typeck_results ( ) . expr_ty ( e) . is_union ( ) {
112- unsafe_ops. push ( ( "union field access occurs here" , expr. span ) ) ;
132+ if self . typeck_results . expr_ty ( e) . is_union ( ) {
133+ self . unsafe_ops . push ( ( "union field access occurs here" , expr. span ) ) ;
113134 }
114135 } ,
115136
@@ -127,32 +148,32 @@ fn collect_unsafe_exprs<'tcx>(
127148 ..
128149 } ,
129150 ) ) => {
130- unsafe_ops. push ( ( "access of a mutable static occurs here" , expr. span ) ) ;
151+ self . unsafe_ops
152+ . push ( ( "access of a mutable static occurs here" , expr. span ) ) ;
131153 } ,
132154
133- ExprKind :: Unary ( UnOp :: Deref , e) if cx . typeck_results ( ) . expr_ty_adjusted ( e) . is_raw_ptr ( ) => {
134- unsafe_ops. push ( ( "raw pointer dereference occurs here" , expr. span ) ) ;
155+ ExprKind :: Unary ( UnOp :: Deref , e) if self . typeck_results . expr_ty_adjusted ( e) . is_raw_ptr ( ) => {
156+ self . unsafe_ops . push ( ( "raw pointer dereference occurs here" , expr. span ) ) ;
135157 } ,
136158
137159 ExprKind :: Call ( path_expr, _) => {
138- let sig = match * cx . typeck_results ( ) . expr_ty ( path_expr) . kind ( ) {
139- ty:: FnDef ( id, _) => cx. tcx . fn_sig ( id) . skip_binder ( ) ,
140- ty:: FnPtr ( sig_tys, hdr) => sig_tys. with ( hdr) ,
141- _ => return Continue ( Descend :: Yes ) ,
160+ let opt_sig = match * self . typeck_results . expr_ty ( path_expr) . kind ( ) {
161+ ty:: FnDef ( id, _) => Some ( self . cx . tcx . fn_sig ( id) . skip_binder ( ) ) ,
162+ ty:: FnPtr ( sig_tys, hdr) => Some ( sig_tys. with ( hdr) ) ,
163+ _ => None ,
142164 } ;
143- if sig. safety ( ) . is_unsafe ( ) {
144- unsafe_ops. push ( ( "unsafe function call occurs here" , expr. span ) ) ;
165+ if opt_sig . is_some_and ( | sig| sig . safety ( ) . is_unsafe ( ) ) {
166+ self . unsafe_ops . push ( ( "unsafe function call occurs here" , expr. span ) ) ;
145167 }
146168 } ,
147169
148170 ExprKind :: MethodCall ( ..) => {
149- if let Some ( sig ) = cx
150- . typeck_results ( )
171+ let opt_sig = self
172+ . typeck_results
151173 . type_dependent_def_id ( expr. hir_id )
152- . map ( |def_id| cx. tcx . fn_sig ( def_id) )
153- && sig. skip_binder ( ) . safety ( ) . is_unsafe ( )
154- {
155- unsafe_ops. push ( ( "unsafe method call occurs here" , expr. span ) ) ;
174+ . map ( |def_id| self . cx . tcx . fn_sig ( def_id) ) ;
175+ if opt_sig. is_some_and ( |sig| sig. skip_binder ( ) . safety ( ) . is_unsafe ( ) ) {
176+ self . unsafe_ops . push ( ( "unsafe method call occurs here" , expr. span ) ) ;
156177 }
157178 } ,
158179
@@ -173,15 +194,26 @@ fn collect_unsafe_exprs<'tcx>(
173194 }
174195 ) )
175196 ) {
176- unsafe_ops . push ( ( "modification of a mutable static occurs here" , expr . span ) ) ;
177- collect_unsafe_exprs ( cx , rhs , unsafe_ops ) ;
178- return Continue ( Descend :: No ) ;
197+ self . unsafe_ops
198+ . push ( ( "modification of a mutable static occurs here" , expr . span ) ) ;
199+ return self . visit_expr ( rhs ) ;
179200 }
180201 } ,
181202
182203 _ => { } ,
183204 }
184205
185- Continue :: < ( ) , _ > ( Descend :: Yes )
186- } ) ;
206+ walk_expr ( self , expr) ;
207+ }
208+
209+ fn visit_body ( & mut self , body : & hir:: Body < ' tcx > ) {
210+ let saved_typeck_results = self . typeck_results ;
211+ self . typeck_results = self . cx . tcx . typeck_body ( body. id ( ) ) ;
212+ walk_body ( self , body) ;
213+ self . typeck_results = saved_typeck_results;
214+ }
215+
216+ fn maybe_tcx ( & mut self ) -> Self :: MaybeTyCtxt {
217+ self . cx . tcx
218+ }
187219}
0 commit comments