1
1
use super :: SAME_ITEM_PUSH ;
2
2
use clippy_utils:: diagnostics:: span_lint_and_help;
3
3
use clippy_utils:: path_to_local;
4
- use clippy_utils:: source:: snippet_with_macro_callsite ;
4
+ use clippy_utils:: source:: snippet_with_context ;
5
5
use clippy_utils:: ty:: { implements_trait, is_type_diagnostic_item} ;
6
6
use if_chain:: if_chain;
7
7
use rustc_data_structures:: fx:: FxHashSet ;
8
+ use rustc_errors:: Applicability ;
8
9
use rustc_hir:: def:: { DefKind , Res } ;
9
10
use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
10
11
use rustc_hir:: { BindingAnnotation , Block , Expr , ExprKind , HirId , Mutability , Node , Pat , PatKind , Stmt , StmtKind } ;
11
12
use rustc_lint:: LateContext ;
12
13
use rustc_span:: symbol:: sym;
14
+ use rustc_span:: SyntaxContext ;
13
15
use std:: iter:: Iterator ;
14
16
15
17
/// Detects for loop pushing the same item into a Vec
@@ -20,9 +22,10 @@ pub(super) fn check<'tcx>(
20
22
body : & ' tcx Expr < ' _ > ,
21
23
_: & ' tcx Expr < ' _ > ,
22
24
) {
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 ;
26
29
27
30
span_lint_and_help (
28
31
cx,
@@ -43,7 +46,7 @@ pub(super) fn check<'tcx>(
43
46
walk_expr ( & mut same_item_push_visitor, body) ;
44
47
if_chain ! {
45
48
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;
47
50
let vec_ty = cx. typeck_results( ) . expr_ty( vec) ;
48
51
let ty = vec_ty. walk( ) . nth( 1 ) . unwrap( ) . expect_ty( ) ;
49
52
if cx
@@ -69,11 +72,11 @@ pub(super) fn check<'tcx>(
69
72
then {
70
73
match init. kind {
71
74
// 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 ) ,
73
76
// immutable bindings that are initialized with constant
74
77
ExprKind :: Path ( ref path) => {
75
78
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 ) ;
77
80
}
78
81
}
79
82
_ => { } ,
@@ -82,11 +85,11 @@ pub(super) fn check<'tcx>(
82
85
}
83
86
} ,
84
87
// constant
85
- Res :: Def ( DefKind :: Const , ..) => emit_lint( cx, vec, pushed_item) ,
88
+ Res :: Def ( DefKind :: Const , ..) => emit_lint( cx, vec, pushed_item, ctxt ) ,
86
89
_ => { } ,
87
90
}
88
91
} ,
89
- ExprKind :: Lit ( ..) => emit_lint( cx, vec, pushed_item) ,
92
+ ExprKind :: Lit ( ..) => emit_lint( cx, vec, pushed_item, ctxt ) ,
90
93
_ => { } ,
91
94
}
92
95
}
@@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> {
98
101
non_deterministic_expr : bool ,
99
102
multiple_pushes : bool ,
100
103
// 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 ) > ,
102
105
cx : & ' a LateContext < ' tcx > ,
103
106
used_locals : FxHashSet < HirId > ,
104
107
}
@@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
118
121
if_chain ! {
119
122
if !self . non_deterministic_expr;
120
123
if !self . multiple_pushes;
121
- if let Some ( ( vec, _) ) = self . vec_push;
124
+ if let Some ( ( vec, _, _ ) ) = self . vec_push;
122
125
if let Some ( hir_id) = path_to_local( vec) ;
123
126
then {
124
127
!self . used_locals. contains( & hir_id)
@@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
173
176
174
177
// Given some statement, determine if that statement is a push on a Vec. If it is, return
175
178
// 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 ) > {
177
183
if_chain ! {
178
184
// Extract method being called
179
185
if let StmtKind :: Semi ( semi_stmt) = & stmt. kind;
@@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
184
190
if is_type_diagnostic_item( cx, cx. typeck_results( ) . expr_ty( self_expr) , sym:: Vec ) ;
185
191
if path. ident. name. as_str( ) == "push" ;
186
192
then {
187
- return Some ( ( self_expr, pushed_item) )
193
+ return Some ( ( self_expr, pushed_item, semi_stmt . span . ctxt ( ) ) )
188
194
}
189
195
}
190
196
None
0 commit comments