@@ -203,108 +203,106 @@ fn expr_return_none_or_err(
203203 }
204204}
205205
206- impl QuestionMark {
207- fn inside_try_block ( & self ) -> bool {
208- self . try_block_depth_stack . last ( ) > Some ( & 0 )
209- }
210-
211- /// Checks if the given expression on the given context matches the following structure:
212- ///
213- /// ```ignore
214- /// if option.is_none() {
215- /// return None;
216- /// }
217- /// ```
218- ///
219- /// ```ignore
220- /// if result.is_err() {
221- /// return result;
222- /// }
223- /// ```
224- ///
225- /// If it matches, it will suggest to use the question mark operator instead
226- fn check_is_none_or_err_and_early_return < ' tcx > ( & self , cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
227- if !self . inside_try_block ( )
228- && let Some ( higher:: If { cond, then, r#else } ) = higher:: If :: hir ( expr)
229- && !is_else_clause ( cx. tcx , expr)
230- && let ExprKind :: MethodCall ( segment, caller, ..) = & cond. kind
231- && let caller_ty = cx. typeck_results ( ) . expr_ty ( caller)
232- && let if_block = IfBlockType :: IfIs ( caller, caller_ty, segment. ident . name , then)
233- && ( is_early_return ( sym:: Option , cx, & if_block) || is_early_return ( sym:: Result , cx, & if_block) )
234- {
235- let mut applicability = Applicability :: MachineApplicable ;
236- let receiver_str = snippet_with_applicability ( cx, caller. span , ".." , & mut applicability) ;
237- let by_ref = !caller_ty. is_copy_modulo_regions ( cx. tcx , cx. param_env )
238- && !matches ! ( caller. kind, ExprKind :: Call ( ..) | ExprKind :: MethodCall ( ..) ) ;
239- let sugg = if let Some ( else_inner) = r#else {
240- if eq_expr_value ( cx, caller, peel_blocks ( else_inner) ) {
241- format ! ( "Some({receiver_str}?)" )
242- } else {
243- return ;
244- }
206+ /// Checks if the given expression on the given context matches the following structure:
207+ ///
208+ /// ```ignore
209+ /// if option.is_none() {
210+ /// return None;
211+ /// }
212+ /// ```
213+ ///
214+ /// ```ignore
215+ /// if result.is_err() {
216+ /// return result;
217+ /// }
218+ /// ```
219+ ///
220+ /// If it matches, it will suggest to use the question mark operator instead
221+ fn check_is_none_or_err_and_early_return < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
222+ if let Some ( higher:: If { cond, then, r#else } ) = higher:: If :: hir ( expr)
223+ && !is_else_clause ( cx. tcx , expr)
224+ && let ExprKind :: MethodCall ( segment, caller, ..) = & cond. kind
225+ && let caller_ty = cx. typeck_results ( ) . expr_ty ( caller)
226+ && let if_block = IfBlockType :: IfIs ( caller, caller_ty, segment. ident . name , then)
227+ && ( is_early_return ( sym:: Option , cx, & if_block) || is_early_return ( sym:: Result , cx, & if_block) )
228+ {
229+ let mut applicability = Applicability :: MachineApplicable ;
230+ let receiver_str = snippet_with_applicability ( cx, caller. span , ".." , & mut applicability) ;
231+ let by_ref = !caller_ty. is_copy_modulo_regions ( cx. tcx , cx. param_env )
232+ && !matches ! ( caller. kind, ExprKind :: Call ( ..) | ExprKind :: MethodCall ( ..) ) ;
233+ let sugg = if let Some ( else_inner) = r#else {
234+ if eq_expr_value ( cx, caller, peel_blocks ( else_inner) ) {
235+ format ! ( "Some({receiver_str}?)" )
245236 } else {
246- format ! ( "{receiver_str}{}?;" , if by_ref { ".as_ref()" } else { "" } )
247- } ;
237+ return ;
238+ }
239+ } else {
240+ format ! ( "{receiver_str}{}?;" , if by_ref { ".as_ref()" } else { "" } )
241+ } ;
248242
249- span_lint_and_sugg (
250- cx,
251- QUESTION_MARK ,
252- expr. span ,
253- "this block may be rewritten with the `?` operator" ,
254- "replace it with" ,
255- sugg,
256- applicability,
257- ) ;
258- }
243+ span_lint_and_sugg (
244+ cx,
245+ QUESTION_MARK ,
246+ expr. span ,
247+ "this block may be rewritten with the `?` operator" ,
248+ "replace it with" ,
249+ sugg,
250+ applicability,
251+ ) ;
259252 }
253+ }
260254
261- fn check_if_let_some_or_err_and_early_return < ' tcx > ( & self , cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
262- if !self . inside_try_block ( )
263- && let Some ( higher:: IfLet {
264- let_pat,
265- let_expr,
266- if_then,
267- if_else,
268- ..
269- } ) = higher:: IfLet :: hir ( cx, expr)
270- && !is_else_clause ( cx. tcx , expr)
271- && let PatKind :: TupleStruct ( ref path1, [ field] , ddpos) = let_pat. kind
272- && ddpos. as_opt_usize ( ) . is_none ( )
273- && let PatKind :: Binding ( BindingAnnotation ( by_ref, _) , bind_id, ident, None ) = field. kind
274- && let caller_ty = cx. typeck_results ( ) . expr_ty ( let_expr)
275- && let if_block = IfBlockType :: IfLet (
276- cx. qpath_res ( path1, let_pat. hir_id ) ,
277- caller_ty,
278- ident. name ,
279- let_expr,
280- if_then,
281- if_else,
282- )
283- && ( ( is_early_return ( sym:: Option , cx, & if_block) && path_to_local_id ( peel_blocks ( if_then) , bind_id) )
284- || is_early_return ( sym:: Result , cx, & if_block) )
285- && if_else
286- . map ( |e| eq_expr_value ( cx, let_expr, peel_blocks ( e) ) )
287- . filter ( |e| * e)
288- . is_none ( )
289- {
290- let mut applicability = Applicability :: MachineApplicable ;
291- let receiver_str = snippet_with_applicability ( cx, let_expr. span , ".." , & mut applicability) ;
292- let requires_semi = matches ! ( cx. tcx. parent_hir_node( expr. hir_id) , Node :: Stmt ( _) ) ;
293- let sugg = format ! (
294- "{receiver_str}{}?{}" ,
295- if by_ref == ByRef :: Yes { ".as_ref()" } else { "" } ,
296- if requires_semi { ";" } else { "" }
297- ) ;
298- span_lint_and_sugg (
299- cx,
300- QUESTION_MARK ,
301- expr. span ,
302- "this block may be rewritten with the `?` operator" ,
303- "replace it with" ,
304- sugg,
305- applicability,
306- ) ;
307- }
255+ fn check_if_let_some_or_err_and_early_return < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
256+ if let Some ( higher:: IfLet {
257+ let_pat,
258+ let_expr,
259+ if_then,
260+ if_else,
261+ ..
262+ } ) = higher:: IfLet :: hir ( cx, expr)
263+ && !is_else_clause ( cx. tcx , expr)
264+ && let PatKind :: TupleStruct ( ref path1, [ field] , ddpos) = let_pat. kind
265+ && ddpos. as_opt_usize ( ) . is_none ( )
266+ && let PatKind :: Binding ( BindingAnnotation ( by_ref, _) , bind_id, ident, None ) = field. kind
267+ && let caller_ty = cx. typeck_results ( ) . expr_ty ( let_expr)
268+ && let if_block = IfBlockType :: IfLet (
269+ cx. qpath_res ( path1, let_pat. hir_id ) ,
270+ caller_ty,
271+ ident. name ,
272+ let_expr,
273+ if_then,
274+ if_else,
275+ )
276+ && ( ( is_early_return ( sym:: Option , cx, & if_block) && path_to_local_id ( peel_blocks ( if_then) , bind_id) )
277+ || is_early_return ( sym:: Result , cx, & if_block) )
278+ && if_else
279+ . map ( |e| eq_expr_value ( cx, let_expr, peel_blocks ( e) ) )
280+ . filter ( |e| * e)
281+ . is_none ( )
282+ {
283+ let mut applicability = Applicability :: MachineApplicable ;
284+ let receiver_str = snippet_with_applicability ( cx, let_expr. span , ".." , & mut applicability) ;
285+ let requires_semi = matches ! ( cx. tcx. parent_hir_node( expr. hir_id) , Node :: Stmt ( _) ) ;
286+ let sugg = format ! (
287+ "{receiver_str}{}?{}" ,
288+ if by_ref == ByRef :: Yes { ".as_ref()" } else { "" } ,
289+ if requires_semi { ";" } else { "" }
290+ ) ;
291+ span_lint_and_sugg (
292+ cx,
293+ QUESTION_MARK ,
294+ expr. span ,
295+ "this block may be rewritten with the `?` operator" ,
296+ "replace it with" ,
297+ sugg,
298+ applicability,
299+ ) ;
300+ }
301+ }
302+
303+ impl QuestionMark {
304+ fn inside_try_block ( & self ) -> bool {
305+ self . try_block_depth_stack . last ( ) > Some ( & 0 )
308306 }
309307}
310308
@@ -324,15 +322,18 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
324322 return ;
325323 }
326324
327- if !in_constant ( cx, stmt. hir_id ) {
325+ if !self . inside_try_block ( ) && ! in_constant ( cx, stmt. hir_id ) {
328326 check_let_some_else_return_none ( cx, stmt) ;
329327 }
330328 self . check_manual_let_else ( cx, stmt) ;
331329 }
332330 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
333- if !in_constant ( cx, expr. hir_id ) && is_lint_allowed ( cx, QUESTION_MARK_USED , expr. hir_id ) {
334- self . check_is_none_or_err_and_early_return ( cx, expr) ;
335- self . check_if_let_some_or_err_and_early_return ( cx, expr) ;
331+ if !self . inside_try_block ( )
332+ && !in_constant ( cx, expr. hir_id )
333+ && is_lint_allowed ( cx, QUESTION_MARK_USED , expr. hir_id )
334+ {
335+ check_is_none_or_err_and_early_return ( cx, expr) ;
336+ check_if_let_some_or_err_and_early_return ( cx, expr) ;
336337 }
337338 }
338339
0 commit comments