11use super :: SAME_ITEM_PUSH ;
22use clippy_utils:: diagnostics:: span_lint_and_help;
33use clippy_utils:: path_to_local;
4- use clippy_utils:: source:: snippet_with_macro_callsite ;
4+ use clippy_utils:: source:: snippet_with_context ;
55use clippy_utils:: ty:: { implements_trait, is_type_diagnostic_item} ;
66use if_chain:: if_chain;
77use rustc_data_structures:: fx:: FxHashSet ;
8+ use rustc_errors:: Applicability ;
89use rustc_hir:: def:: { DefKind , Res } ;
910use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
1011use rustc_hir:: { BindingAnnotation , Block , Expr , ExprKind , HirId , Mutability , Node , Pat , PatKind , Stmt , StmtKind } ;
1112use rustc_lint:: LateContext ;
1213use rustc_span:: symbol:: sym;
14+ use rustc_span:: SyntaxContext ;
1315use std:: iter:: Iterator ;
1416
1517/// Detects for loop pushing the same item into a Vec
@@ -20,9 +22,10 @@ pub(super) fn check<'tcx>(
2022 body : & ' tcx Expr < ' _ > ,
2123 _: & ' tcx Expr < ' _ > ,
2224) {
23- fn emit_lint ( cx : & LateContext < ' _ > , vec : & Expr < ' _ > , pushed_item : & Expr < ' _ > ) {
24- let vec_str = snippet_with_macro_callsite ( cx, vec. span , "" ) ;
25- let item_str = snippet_with_macro_callsite ( cx, pushed_item. span , "" ) ;
25+ fn emit_lint ( cx : & LateContext < ' _ > , vec : & Expr < ' _ > , pushed_item : & Expr < ' _ > , ctxt : SyntaxContext ) {
26+ let mut app = Applicability :: Unspecified ;
27+ let vec_str = snippet_with_context ( cx, vec. span , ctxt, "" , & mut app) . 0 ;
28+ let item_str = snippet_with_context ( cx, pushed_item. span , ctxt, "" , & mut app) . 0 ;
2629
2730 span_lint_and_help (
2831 cx,
@@ -43,7 +46,7 @@ pub(super) fn check<'tcx>(
4346 walk_expr ( & mut same_item_push_visitor, body) ;
4447 if_chain ! {
4548 if same_item_push_visitor. should_lint( ) ;
46- if let Some ( ( vec, pushed_item) ) = same_item_push_visitor. vec_push;
49+ if let Some ( ( vec, pushed_item, ctxt ) ) = same_item_push_visitor. vec_push;
4750 let vec_ty = cx. typeck_results( ) . expr_ty( vec) ;
4851 let ty = vec_ty. walk( ) . nth( 1 ) . unwrap( ) . expect_ty( ) ;
4952 if cx
@@ -69,11 +72,11 @@ pub(super) fn check<'tcx>(
6972 then {
7073 match init. kind {
7174 // immutable bindings that are initialized with literal
72- ExprKind :: Lit ( ..) => emit_lint( cx, vec, pushed_item) ,
75+ ExprKind :: Lit ( ..) => emit_lint( cx, vec, pushed_item, ctxt ) ,
7376 // immutable bindings that are initialized with constant
7477 ExprKind :: Path ( ref path) => {
7578 if let Res :: Def ( DefKind :: Const , ..) = cx. qpath_res( path, init. hir_id) {
76- emit_lint( cx, vec, pushed_item) ;
79+ emit_lint( cx, vec, pushed_item, ctxt ) ;
7780 }
7881 }
7982 _ => { } ,
@@ -82,11 +85,11 @@ pub(super) fn check<'tcx>(
8285 }
8386 } ,
8487 // constant
85- Res :: Def ( DefKind :: Const , ..) => emit_lint( cx, vec, pushed_item) ,
88+ Res :: Def ( DefKind :: Const , ..) => emit_lint( cx, vec, pushed_item, ctxt ) ,
8689 _ => { } ,
8790 }
8891 } ,
89- ExprKind :: Lit ( ..) => emit_lint( cx, vec, pushed_item) ,
92+ ExprKind :: Lit ( ..) => emit_lint( cx, vec, pushed_item, ctxt ) ,
9093 _ => { } ,
9194 }
9295 }
@@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> {
98101 non_deterministic_expr : bool ,
99102 multiple_pushes : bool ,
100103 // this field holds the last vec push operation visited, which should be the only push seen
101- vec_push : Option < ( & ' tcx Expr < ' tcx > , & ' tcx Expr < ' tcx > ) > ,
104+ vec_push : Option < ( & ' tcx Expr < ' tcx > , & ' tcx Expr < ' tcx > , SyntaxContext ) > ,
102105 cx : & ' a LateContext < ' tcx > ,
103106 used_locals : FxHashSet < HirId > ,
104107}
@@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
118121 if_chain ! {
119122 if !self . non_deterministic_expr;
120123 if !self . multiple_pushes;
121- if let Some ( ( vec, _) ) = self . vec_push;
124+ if let Some ( ( vec, _, _ ) ) = self . vec_push;
122125 if let Some ( hir_id) = path_to_local( vec) ;
123126 then {
124127 !self . used_locals. contains( & hir_id)
@@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
173176
174177// Given some statement, determine if that statement is a push on a Vec. If it is, return
175178// the Vec being pushed into and the item being pushed
176- fn get_vec_push < ' tcx > ( cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) -> Option < ( & ' tcx Expr < ' tcx > , & ' tcx Expr < ' tcx > ) > {
179+ fn get_vec_push < ' tcx > (
180+ cx : & LateContext < ' tcx > ,
181+ stmt : & ' tcx Stmt < ' _ > ,
182+ ) -> Option < ( & ' tcx Expr < ' tcx > , & ' tcx Expr < ' tcx > , SyntaxContext ) > {
177183 if_chain ! {
178184 // Extract method being called
179185 if let StmtKind :: Semi ( semi_stmt) = & stmt. kind;
@@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
184190 if is_type_diagnostic_item( cx, cx. typeck_results( ) . expr_ty( self_expr) , sym:: Vec ) ;
185191 if path. ident. name. as_str( ) == "push" ;
186192 then {
187- return Some ( ( self_expr, pushed_item) )
193+ return Some ( ( self_expr, pushed_item, semi_stmt . span . ctxt ( ) ) )
188194 }
189195 }
190196 None
0 commit comments