@@ -2,14 +2,13 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_D
22use clippy_utils:: diagnostics:: { span_lint, span_lint_and_note} ;
33use clippy_utils:: macros:: { is_panic, root_macro_call_first_node} ;
44use clippy_utils:: ty:: { get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item} ;
5- use clippy_utils:: visitors:: Visitable ;
5+ use clippy_utils:: visitors:: for_each_expr ;
66use clippy_utils:: { fulfill_or_allowed, is_doc_hidden, method_chain_args, return_ty} ;
7- use rustc_hir:: intravisit:: { self , Visitor } ;
8- use rustc_hir:: { AnonConst , BodyId , Expr , FnSig , OwnerId , Safety } ;
7+ use rustc_hir:: { BodyId , FnSig , OwnerId , Safety } ;
98use rustc_lint:: LateContext ;
10- use rustc_middle:: hir:: nested_filter:: OnlyBodies ;
119use rustc_middle:: ty;
1210use rustc_span:: { Span , sym} ;
11+ use std:: ops:: ControlFlow ;
1312
1413pub fn check (
1514 cx : & LateContext < ' _ > ,
@@ -51,7 +50,7 @@ pub fn check(
5150 }
5251 if !headers. panics
5352 && let Some ( body_id) = body_id
54- && let Some ( panic_span) = FindPanicUnwrap :: find_span ( cx, body_id)
53+ && let Some ( panic_span) = find_panic ( cx, body_id)
5554 {
5655 span_lint_and_note (
5756 cx,
@@ -96,65 +95,38 @@ pub fn check(
9695 }
9796}
9897
99- struct FindPanicUnwrap < ' a , ' tcx > {
100- cx : & ' a LateContext < ' tcx > ,
101- panic_span : Option < Span > ,
102- typeck_results : & ' tcx ty:: TypeckResults < ' tcx > ,
103- }
104-
105- impl < ' a , ' tcx > FindPanicUnwrap < ' a , ' tcx > {
106- pub fn find_span ( cx : & ' a LateContext < ' tcx > , body_id : BodyId ) -> Option < Span > {
107- let mut vis = Self {
108- cx,
109- panic_span : None ,
110- typeck_results : cx. tcx . typeck_body ( body_id) ,
111- } ;
112- cx. tcx . hir_body ( body_id) . visit ( & mut vis) ;
113- vis. panic_span
114- }
115- }
116-
117- impl < ' tcx > Visitor < ' tcx > for FindPanicUnwrap < ' _ , ' tcx > {
118- type NestedFilter = OnlyBodies ;
119-
120- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' _ > ) {
121- if self . panic_span . is_some ( ) {
122- return ;
123- }
124-
125- if let Some ( macro_call) = root_macro_call_first_node ( self . cx , expr) {
126- if ( is_panic ( self . cx , macro_call. def_id )
98+ fn find_panic ( cx : & LateContext < ' _ > , body_id : BodyId ) -> Option < Span > {
99+ let mut panic_span = None ;
100+ let typeck = cx. tcx . typeck_body ( body_id) ;
101+ for_each_expr ( cx, cx. tcx . hir_body ( body_id) , |expr| {
102+ if let Some ( macro_call) = root_macro_call_first_node ( cx, expr)
103+ && ( is_panic ( cx, macro_call. def_id )
127104 || matches ! (
128- self . cx. tcx. get_diagnostic_name( macro_call. def_id) ,
105+ cx. tcx. get_diagnostic_name( macro_call. def_id) ,
129106 Some ( sym:: assert_macro | sym:: assert_eq_macro | sym:: assert_ne_macro)
130107 ) )
131- && !self . cx . tcx . hir_is_inside_const_context ( expr. hir_id )
132- && !fulfill_or_allowed ( self . cx , MISSING_PANICS_DOC , [ expr. hir_id ] )
133- {
134- self . panic_span = Some ( macro_call . span ) ;
135- }
108+ && !cx. tcx . hir_is_inside_const_context ( expr. hir_id )
109+ && !fulfill_or_allowed ( cx, MISSING_PANICS_DOC , [ expr. hir_id ] )
110+ && panic_span . is_none ( )
111+ {
112+ panic_span = Some ( macro_call . span ) ;
136113 }
137114
138115 // check for `unwrap` and `expect` for both `Option` and `Result`
139- if let Some ( arglists) = method_chain_args ( expr, & [ "unwrap" ] ) . or ( method_chain_args ( expr, & [ "expect" ] ) ) {
140- let receiver_ty = self . typeck_results . expr_ty ( arglists[ 0 ] . 0 ) . peel_refs ( ) ;
141- if matches ! (
142- get_type_diagnostic_name( self . cx, receiver_ty) ,
116+ if let Some ( arglists) = method_chain_args ( expr, & [ "unwrap" ] ) . or_else ( || method_chain_args ( expr, & [ "expect" ] ) )
117+ && let receiver_ty = typeck . expr_ty ( arglists[ 0 ] . 0 ) . peel_refs ( )
118+ && matches ! (
119+ get_type_diagnostic_name( cx, receiver_ty) ,
143120 Some ( sym:: Option | sym:: Result )
144- ) && !fulfill_or_allowed ( self . cx , MISSING_PANICS_DOC , [ expr. hir_id ] )
145- {
146- self . panic_span = Some ( expr. span ) ;
147- }
121+ )
122+ && !fulfill_or_allowed ( cx, MISSING_PANICS_DOC , [ expr. hir_id ] )
123+ && panic_span. is_none ( )
124+ {
125+ panic_span = Some ( expr. span ) ;
148126 }
149127
150- // and check sub-expressions
151- intravisit:: walk_expr ( self , expr) ;
152- }
153-
154- // Panics in const blocks will cause compilation to fail.
155- fn visit_anon_const ( & mut self , _: & ' tcx AnonConst ) { }
156-
157- fn maybe_tcx ( & mut self ) -> Self :: MaybeTyCtxt {
158- self . cx . tcx
159- }
128+ // Visit all nodes to fulfill any `#[expect]`s after the first linted panic
129+ ControlFlow :: < !> :: Continue ( ( ) )
130+ } ) ;
131+ panic_span
160132}
0 commit comments