Skip to content

Commit 6bd8d00

Browse files
committed
Make single_range_in_vec_init ignore type annotations and fn arguments
1 parent a959061 commit 6bd8d00

File tree

3 files changed

+88
-15
lines changed

3 files changed

+88
-15
lines changed

clippy_lints/src/single_range_in_vec_init.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_utils::{
2-
diagnostics::span_lint_and_then, get_trait_def_id, higher::VecArgs, macros::root_macro_call_first_node,
3-
source::snippet_opt, ty::implements_trait,
2+
diagnostics::span_lint_and_then, get_parent_expr, get_trait_def_id, higher::VecArgs,
3+
macros::root_macro_call_first_node, peel_blocks, source::snippet_opt, ty::implements_trait,
44
};
55
use rustc_ast::{LitIntType, LitKind, UintTy};
66
use rustc_errors::Applicability;
7-
use rustc_hir::{Expr, ExprKind, LangItem, QPath};
7+
use rustc_hir::{Expr, ExprKind, LangItem, Local, Node, QPath};
88
use rustc_lint::{LateContext, LateLintPass};
99
use rustc_session::{declare_lint_pass, declare_tool_lint};
1010
use std::fmt::{self, Display, Formatter};
@@ -66,7 +66,7 @@ impl Display for SuggestedType {
6666
}
6767

6868
impl LateLintPass<'_> for SingleRangeInVecInit {
69-
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
69+
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
7070
// inner_expr: `vec![0..200]` or `[0..200]`
7171
// ^^^^^^ ^^^^^^^
7272
// span: `vec![0..200]` or `[0..200]`
@@ -90,6 +90,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
9090

9191
if matches!(lang_item, LangItem::Range)
9292
&& let ty = cx.typeck_results().expr_ty(start.expr)
93+
&& !(has_type_annotations(cx, expr) || is_argument(cx, expr))
9394
&& let Some(snippet) = snippet_opt(cx, span)
9495
// `is_from_proc_macro` will skip any `vec![]`. Let's not!
9596
&& snippet.starts_with(suggested_type.starts_with())
@@ -139,9 +140,52 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
139140
Applicability::MaybeIncorrect,
140141
);
141142
}
143+
144+
if let Some(local) = get_local(cx, expr) {
145+
diag.span_suggestion(
146+
local.pat.span.shrink_to_hi(),
147+
"if this is intended, give it type annotations",
148+
format!(": {}", cx.typeck_results().expr_ty(expr)),
149+
Applicability::HasPlaceholders,
150+
);
151+
}
142152
},
143153
);
144154
}
145155
}
146156
}
147157
}
158+
159+
fn get_local<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Local<'tcx>> {
160+
cx.tcx
161+
.hir()
162+
.parent_iter(expr.hir_id)
163+
.find(|p| matches!(p.1, Node::Local(_)))
164+
.map(|local| local.1.expect_local())
165+
}
166+
167+
/// Returns whether `expr` has type annotations if it's a local binding. We should not lint this.
168+
fn has_type_annotations(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
169+
let Some((_, Node::Local(local))) = cx
170+
.tcx
171+
.hir()
172+
.parent_iter(expr.hir_id)
173+
.find(|p| matches!(p.1, Node::Local(_)))
174+
else {
175+
return false;
176+
};
177+
let Some(init) = local.init else {
178+
return false;
179+
};
180+
181+
peel_blocks(init).hir_id == expr.hir_id && local.ty.is_some()
182+
}
183+
184+
/// Returns whether `expr` is used as an argument to a function. We should not lint this.
185+
fn is_argument(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
186+
let Some(parent) = get_parent_expr(cx, expr) else {
187+
return false;
188+
};
189+
190+
matches!(parent.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(..))
191+
}

tests/ui/single_range_in_vec_init.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#[macro_use]
77
extern crate proc_macros;
88

9+
use std::ops::Range;
10+
911
macro_rules! a {
1012
() => {
1113
vec![0..200];
@@ -20,6 +22,8 @@ fn awa_vec<T: PartialOrd>(start: T, end: T) {
2022
vec![start..end];
2123
}
2224

25+
fn do_not_lint_as_argument(_: Vec<Range<usize>>) {}
26+
2327
fn main() {
2428
// Lint
2529
[0..200];
@@ -33,11 +37,17 @@ fn main() {
3337
// Only suggest collect
3438
[0..200isize];
3539
vec![0..200isize];
40+
// Lints, but suggests adding type annotations
41+
let x = vec![0..200];
42+
do_not_lint_as_argument(vec![0..200]);
3643
// Do not lint
3744
[0..200, 0..100];
3845
vec![0..200, 0..100];
3946
[0.0..200.0];
4047
vec![0.0..200.0];
48+
// Issue #11086
49+
let do_not_lint_if_has_type_annotations: Vec<Range<_>> = vec![0..200];
50+
do_not_lint_as_argument(vec![0..200]);
4151
// `Copy` is not implemented for `Range`, so this doesn't matter
4252
// FIXME: [0..200; 2];
4353
// FIXME: [vec!0..200; 2];

tests/ui/single_range_in_vec_init.stderr

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: an array of `Range` that is only one element
2-
--> $DIR/single_range_in_vec_init.rs:25:5
2+
--> $DIR/single_range_in_vec_init.rs:29:5
33
|
44
LL | [0..200];
55
| ^^^^^^^^
@@ -15,7 +15,7 @@ LL | [0; 200];
1515
| ~~~~~~
1616

1717
error: a `Vec` of `Range` that is only one element
18-
--> $DIR/single_range_in_vec_init.rs:26:5
18+
--> $DIR/single_range_in_vec_init.rs:30:5
1919
|
2020
LL | vec![0..200];
2121
| ^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL | vec![0; 200];
3030
| ~~~~~~
3131

3232
error: an array of `Range` that is only one element
33-
--> $DIR/single_range_in_vec_init.rs:27:5
33+
--> $DIR/single_range_in_vec_init.rs:31:5
3434
|
3535
LL | [0u8..200];
3636
| ^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | [0u8; 200];
4545
| ~~~~~~~~
4646

4747
error: an array of `Range` that is only one element
48-
--> $DIR/single_range_in_vec_init.rs:28:5
48+
--> $DIR/single_range_in_vec_init.rs:32:5
4949
|
5050
LL | [0usize..200];
5151
| ^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL | [0usize; 200];
6060
| ~~~~~~~~~~~
6161

6262
error: an array of `Range` that is only one element
63-
--> $DIR/single_range_in_vec_init.rs:29:5
63+
--> $DIR/single_range_in_vec_init.rs:33:5
6464
|
6565
LL | [0..200usize];
6666
| ^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL | [0; 200usize];
7575
| ~~~~~~~~~~~
7676

7777
error: a `Vec` of `Range` that is only one element
78-
--> $DIR/single_range_in_vec_init.rs:30:5
78+
--> $DIR/single_range_in_vec_init.rs:34:5
7979
|
8080
LL | vec![0u8..200];
8181
| ^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | vec![0u8; 200];
9090
| ~~~~~~~~
9191

9292
error: a `Vec` of `Range` that is only one element
93-
--> $DIR/single_range_in_vec_init.rs:31:5
93+
--> $DIR/single_range_in_vec_init.rs:35:5
9494
|
9595
LL | vec![0usize..200];
9696
| ^^^^^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL | vec![0usize; 200];
105105
| ~~~~~~~~~~~
106106

107107
error: a `Vec` of `Range` that is only one element
108-
--> $DIR/single_range_in_vec_init.rs:32:5
108+
--> $DIR/single_range_in_vec_init.rs:36:5
109109
|
110110
LL | vec![0..200usize];
111111
| ^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL | vec![0; 200usize];
120120
| ~~~~~~~~~~~
121121

122122
error: an array of `Range` that is only one element
123-
--> $DIR/single_range_in_vec_init.rs:34:5
123+
--> $DIR/single_range_in_vec_init.rs:38:5
124124
|
125125
LL | [0..200isize];
126126
| ^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL | (0..200isize).collect::<std::vec::Vec<isize>>();
131131
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132132

133133
error: a `Vec` of `Range` that is only one element
134-
--> $DIR/single_range_in_vec_init.rs:35:5
134+
--> $DIR/single_range_in_vec_init.rs:39:5
135135
|
136136
LL | vec![0..200isize];
137137
| ^^^^^^^^^^^^^^^^^
@@ -141,5 +141,24 @@ help: if you wanted a `Vec` that contains the entire range, try
141141
LL | (0..200isize).collect::<std::vec::Vec<isize>>();
142142
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
143143

144-
error: aborting due to 10 previous errors
144+
error: a `Vec` of `Range` that is only one element
145+
--> $DIR/single_range_in_vec_init.rs:41:13
146+
|
147+
LL | let x = vec![0..200];
148+
| ^^^^^^^^^^^^
149+
|
150+
help: if you wanted a `Vec` that contains the entire range, try
151+
|
152+
LL | let x = (0..200).collect::<std::vec::Vec<i32>>();
153+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154+
help: if you wanted a `Vec` of len 200, try
155+
|
156+
LL | let x = vec![0; 200];
157+
| ~~~~~~
158+
help: if this is intended, give it type annotations
159+
|
160+
LL | let x: std::vec::Vec<std::ops::Range<i32>> = vec![0..200];
161+
| +++++++++++++++++++++++++++++++++++++
162+
163+
error: aborting due to 11 previous errors
145164

0 commit comments

Comments
 (0)