@@ -6,6 +6,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment};
66use rustc_session:: lint:: FutureIncompatibilityReason ;
77use rustc_span:: edition:: Edition ;
88use rustc_span:: symbol:: sym;
9+ use rustc_span:: Span ;
910
1011declare_lint ! {
1112 /// The `array_into_iter` lint detects calling `into_iter` on arrays.
@@ -36,13 +37,29 @@ declare_lint! {
3637 } ;
3738}
3839
39- declare_lint_pass ! (
40- /// Checks for instances of calling `into_iter` on arrays.
41- ArrayIntoIter => [ ARRAY_INTO_ITER ]
42- ) ;
40+ #[ derive( Copy , Clone , Default ) ]
41+ pub struct ArrayIntoIter {
42+ for_expr_span : Span ,
43+ }
44+
45+ impl_lint_pass ! ( ArrayIntoIter => [ ARRAY_INTO_ITER ] ) ;
4346
4447impl < ' tcx > LateLintPass < ' tcx > for ArrayIntoIter {
4548 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) {
49+ // Save the span of expressions in `for _ in expr` syntax,
50+ // so we can give a better suggestion for those later.
51+ if let hir:: ExprKind :: Match ( arg, [ _] , hir:: MatchSource :: ForLoopDesugar ) = & expr. kind {
52+ if let hir:: ExprKind :: Call ( path, [ arg] ) = & arg. kind {
53+ if let hir:: ExprKind :: Path ( hir:: QPath :: LangItem (
54+ hir:: LangItem :: IntoIterIntoIter ,
55+ _,
56+ ) ) = & path. kind
57+ {
58+ self . for_expr_span = arg. span ;
59+ }
60+ }
61+ }
62+
4663 // We only care about method call expressions.
4764 if let hir:: ExprKind :: MethodCall ( call, span, args, _) = & expr. kind {
4865 if call. ident . name != sym:: into_iter {
@@ -98,27 +115,37 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
98115 _ => bug ! ( "array type coerced to something other than array or slice" ) ,
99116 } ;
100117 cx. struct_span_lint ( ARRAY_INTO_ITER , * span, |lint| {
101- lint. build ( & format ! (
118+ let mut diag = lint. build ( & format ! (
102119 "this method call resolves to `<&{} as IntoIterator>::into_iter` \
103120 (due to backwards compatibility), \
104121 but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
105122 target, target,
106- ) )
107- . span_suggestion (
123+ ) ) ;
124+ diag . span_suggestion (
108125 call. ident . span ,
109126 "use `.iter()` instead of `.into_iter()` to avoid ambiguity" ,
110127 "iter" . into ( ) ,
111128 Applicability :: MachineApplicable ,
112- )
113- . multipart_suggestion (
114- "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value" ,
115- vec ! [
116- ( expr. span. shrink_to_lo( ) , "IntoIterator::into_iter(" . into( ) ) ,
117- ( receiver_arg. span. shrink_to_hi( ) . to( expr. span. shrink_to_hi( ) ) , ")" . into( ) ) ,
118- ] ,
119- Applicability :: MaybeIncorrect ,
120- )
121- . emit ( ) ;
129+ ) ;
130+ if self . for_expr_span == expr. span {
131+ let expr_span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
132+ diag. span_suggestion (
133+ receiver_arg. span . shrink_to_hi ( ) . to ( expr_span. shrink_to_hi ( ) ) ,
134+ "or remove `.into_iter()` to iterate by value" ,
135+ String :: new ( ) ,
136+ Applicability :: MaybeIncorrect ,
137+ ) ;
138+ } else {
139+ diag. multipart_suggestion (
140+ "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value" ,
141+ vec ! [
142+ ( expr. span. shrink_to_lo( ) , "IntoIterator::into_iter(" . into( ) ) ,
143+ ( receiver_arg. span. shrink_to_hi( ) . to( expr. span. shrink_to_hi( ) ) , ")" . into( ) ) ,
144+ ] ,
145+ Applicability :: MaybeIncorrect ,
146+ ) ;
147+ }
148+ diag. emit ( ) ;
122149 } )
123150 }
124151 }
0 commit comments