Skip to content

Commit 612f974

Browse files
committed
Better suggestion for array_into_iter in for loop.
1 parent fae4169 commit 612f974

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

compiler/rustc_lint/src/array_into_iter.rs

+44-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc_hir as hir;
44
use rustc_middle::ty;
55
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
66
use rustc_span::symbol::sym;
7+
use rustc_span::Span;
78

89
declare_lint! {
910
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
@@ -30,13 +31,29 @@ declare_lint! {
3031
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
3132
}
3233

33-
declare_lint_pass!(
34-
/// Checks for instances of calling `into_iter` on arrays.
35-
ArrayIntoIter => [ARRAY_INTO_ITER]
36-
);
34+
#[derive(Copy, Clone, Default)]
35+
pub struct ArrayIntoIter {
36+
for_expr_span: Span,
37+
}
38+
39+
impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
3740

3841
impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
3942
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
43+
// Save the span of expressions in `for _ in expr` syntax,
44+
// so we can give a better suggestion for those later.
45+
if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
46+
if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
47+
if let hir::ExprKind::Path(hir::QPath::LangItem(
48+
hir::LangItem::IntoIterIntoIter,
49+
_,
50+
)) = &path.kind
51+
{
52+
self.for_expr_span = arg.span;
53+
}
54+
}
55+
}
56+
4057
// We only care about method call expressions.
4158
if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
4259
if call.ident.name != sym::into_iter {
@@ -92,27 +109,37 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
92109
_ => bug!("array type coerced to something other than array or slice"),
93110
};
94111
cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
95-
lint.build(&format!(
112+
let mut diag = lint.build(&format!(
96113
"this method call resolves to `<&{} as IntoIterator>::into_iter` \
97114
(due to backwards compatibility), \
98115
but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
99116
target, target,
100-
))
101-
.span_suggestion(
117+
));
118+
diag.span_suggestion(
102119
call.ident.span,
103120
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
104121
"iter".into(),
105122
Applicability::MachineApplicable,
106-
)
107-
.multipart_suggestion(
108-
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
109-
vec![
110-
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
111-
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
112-
],
113-
Applicability::MaybeIncorrect,
114-
)
115-
.emit();
123+
);
124+
if self.for_expr_span == expr.span {
125+
let expr_span = expr.span.ctxt().outer_expn_data().call_site;
126+
diag.span_suggestion(
127+
receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
128+
"or remove `.into_iter()` to iterate by value",
129+
String::new(),
130+
Applicability::MaybeIncorrect,
131+
);
132+
} else {
133+
diag.multipart_suggestion(
134+
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
135+
vec![
136+
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
137+
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
138+
],
139+
Applicability::MaybeIncorrect,
140+
);
141+
}
142+
diag.emit();
116143
})
117144
}
118145
}

compiler/rustc_lint/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ macro_rules! late_lint_passes {
163163
// FIXME: Turn the computation of types which implement Debug into a query
164164
// and change this to a module lint pass
165165
MissingDebugImplementations: MissingDebugImplementations::default(),
166-
ArrayIntoIter: ArrayIntoIter,
166+
ArrayIntoIter: ArrayIntoIter::default(),
167167
ClashingExternDeclarations: ClashingExternDeclarations::new(),
168168
DropTraitConstraints: DropTraitConstraints,
169169
TemporaryCStringAsPtr: TemporaryCStringAsPtr,

0 commit comments

Comments
 (0)