1- use crate :: utils:: { higher:: if_block, is_type_diagnostic_item, span_lint_and_then, usage:: is_potentially_mutated} ;
1+ use crate :: utils:: {
2+ differing_macro_contexts, higher:: if_block, is_type_diagnostic_item, span_lint_and_then,
3+ usage:: is_potentially_mutated,
4+ } ;
25use if_chain:: if_chain;
36use rustc_hir:: intravisit:: { walk_expr, walk_fn, FnKind , NestedVisitorMap , Visitor } ;
47use rustc_hir:: { BinOpKind , Body , Expr , ExprKind , FnDecl , HirId , Path , QPath , UnOp } ;
@@ -73,6 +76,8 @@ struct UnwrapInfo<'tcx> {
7376 ident : & ' tcx Path < ' tcx > ,
7477 /// The check, like `x.is_ok()`
7578 check : & ' tcx Expr < ' tcx > ,
79+ /// The branch where the check takes place, like `if x.is_ok() { .. }`
80+ branch : & ' tcx Expr < ' tcx > ,
7681 /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
7782 safe_to_unwrap : bool ,
7883}
@@ -82,19 +87,20 @@ struct UnwrapInfo<'tcx> {
8287fn collect_unwrap_info < ' a , ' tcx > (
8388 cx : & ' a LateContext < ' a , ' tcx > ,
8489 expr : & ' tcx Expr < ' _ > ,
90+ branch : & ' tcx Expr < ' _ > ,
8591 invert : bool ,
8692) -> Vec < UnwrapInfo < ' tcx > > {
8793 if let ExprKind :: Binary ( op, left, right) = & expr. kind {
8894 match ( invert, op. node ) {
8995 ( false , BinOpKind :: And ) | ( false , BinOpKind :: BitAnd ) | ( true , BinOpKind :: Or ) | ( true , BinOpKind :: BitOr ) => {
90- let mut unwrap_info = collect_unwrap_info ( cx, left, invert) ;
91- unwrap_info. append ( & mut collect_unwrap_info ( cx, right, invert) ) ;
96+ let mut unwrap_info = collect_unwrap_info ( cx, left, branch , invert) ;
97+ unwrap_info. append ( & mut collect_unwrap_info ( cx, right, branch , invert) ) ;
9298 return unwrap_info;
9399 } ,
94100 _ => ( ) ,
95101 }
96102 } else if let ExprKind :: Unary ( UnOp :: UnNot , expr) = & expr. kind {
97- return collect_unwrap_info ( cx, expr, !invert) ;
103+ return collect_unwrap_info ( cx, expr, branch , !invert) ;
98104 } else {
99105 if_chain ! {
100106 if let ExprKind :: MethodCall ( method_name, _, args) = & expr. kind;
@@ -111,7 +117,7 @@ fn collect_unwrap_info<'a, 'tcx>(
111117 _ => unreachable!( ) ,
112118 } ;
113119 let safe_to_unwrap = unwrappable != invert;
114- return vec![ UnwrapInfo { ident: path, check: expr, safe_to_unwrap } ] ;
120+ return vec![ UnwrapInfo { ident: path, check: expr, branch , safe_to_unwrap } ] ;
115121 }
116122 }
117123 }
@@ -121,7 +127,7 @@ fn collect_unwrap_info<'a, 'tcx>(
121127impl < ' a , ' tcx > UnwrappableVariablesVisitor < ' a , ' tcx > {
122128 fn visit_branch ( & mut self , cond : & ' tcx Expr < ' _ > , branch : & ' tcx Expr < ' _ > , else_branch : bool ) {
123129 let prev_len = self . unwrappables . len ( ) ;
124- for unwrap_info in collect_unwrap_info ( self . cx , cond, else_branch) {
130+ for unwrap_info in collect_unwrap_info ( self . cx , cond, branch , else_branch) {
125131 if is_potentially_mutated ( unwrap_info. ident , cond, self . cx )
126132 || is_potentially_mutated ( unwrap_info. ident , branch, self . cx )
127133 {
@@ -158,6 +164,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
158164 let call_to_unwrap = method_name. ident. name == sym!( unwrap) ;
159165 if let Some ( unwrappable) = self . unwrappables. iter( )
160166 . find( |u| u. ident. res == path. res) ;
167+ // Span contexts should not differ with the conditional branch
168+ if !differing_macro_contexts( unwrappable. branch. span, expr. span) ;
169+ if !differing_macro_contexts( unwrappable. branch. span, unwrappable. check. span) ;
161170 then {
162171 if call_to_unwrap == unwrappable. safe_to_unwrap {
163172 span_lint_and_then(
0 commit comments