fix: single_range_in_vec_init wrongly unmangles macros
This commit is contained in:
parent
c8885d5313
commit
6834ab61b1
5 changed files with 212 additions and 21 deletions
|
|
@ -1,12 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::macros::root_macro_call_first_node;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::source::{SpanRangeExt, snippet_with_context};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_no_std_crate, sym};
|
||||
use rustc_ast::{LitIntType, LitKind, UintTy};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, StructTailExpr};
|
||||
use rustc_hir::{Expr, ExprKind, StructTailExpr};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::DesugaringKind;
|
||||
|
|
@ -87,20 +87,21 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
|
|||
return;
|
||||
};
|
||||
|
||||
let ExprKind::Struct(&qpath, [start, end], StructTailExpr::None) = inner_expr.kind else {
|
||||
let ExprKind::Struct(_, [start, end], StructTailExpr::None) = inner_expr.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
if cx.tcx.qpath_is_lang_item(qpath, LangItem::Range)
|
||||
&& inner_expr.span.is_desugaring(DesugaringKind::RangeExpr)
|
||||
if inner_expr.span.is_desugaring(DesugaringKind::RangeExpr)
|
||||
&& let ty = cx.typeck_results().expr_ty(start.expr)
|
||||
&& let Some(snippet) = span.get_source_text(cx)
|
||||
// `is_from_proc_macro` will skip any `vec![]`. Let's not!
|
||||
&& snippet.starts_with(suggested_type.starts_with())
|
||||
&& snippet.ends_with(suggested_type.ends_with())
|
||||
&& let Some(start_snippet) = start.span.get_source_text(cx)
|
||||
&& let Some(end_snippet) = end.span.get_source_text(cx)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let (start_snippet, _) = snippet_with_context(cx, start.expr.span, span.ctxt(), "..", &mut applicability);
|
||||
let (end_snippet, _) = snippet_with_context(cx, end.expr.span, span.ctxt(), "..", &mut applicability);
|
||||
|
||||
let should_emit_every_value = if let Some(step_def_id) = cx.tcx.get_diagnostic_item(sym::range_step)
|
||||
&& implements_trait(cx, ty, step_def_id, &[])
|
||||
{
|
||||
|
|
@ -131,7 +132,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
|
|||
span,
|
||||
"if you wanted a `Vec` that contains the entire range, try",
|
||||
format!("({start_snippet}..{end_snippet}).collect::<std::vec::Vec<{ty}>>()"),
|
||||
Applicability::MaybeIncorrect,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +141,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
|
|||
inner_expr.span,
|
||||
format!("if you wanted {suggested_type} of len {end_snippet}, try"),
|
||||
format!("{start_snippet}; {end_snippet}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
84
tests/ui/single_range_in_vec_init.1.fixed
Normal file
84
tests/ui/single_range_in_vec_init.1.fixed
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//@aux-build:proc_macros.rs
|
||||
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
|
||||
#![warn(clippy::single_range_in_vec_init)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
||||
macro_rules! a {
|
||||
() => {
|
||||
vec![0..200];
|
||||
};
|
||||
}
|
||||
|
||||
fn awa<T: PartialOrd>(start: T, end: T) {
|
||||
[start..end];
|
||||
}
|
||||
|
||||
fn awa_vec<T: PartialOrd>(start: T, end: T) {
|
||||
vec![start..end];
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Lint
|
||||
(0..200).collect::<std::vec::Vec<i32>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0..200).collect::<std::vec::Vec<i32>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0u8..200).collect::<std::vec::Vec<u8>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0usize..200).collect::<std::vec::Vec<usize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0..200usize).collect::<std::vec::Vec<usize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0u8..200).collect::<std::vec::Vec<u8>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0usize..200).collect::<std::vec::Vec<usize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0..200usize).collect::<std::vec::Vec<usize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
// Only suggest collect
|
||||
(0..200isize).collect::<std::vec::Vec<isize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0..200isize).collect::<std::vec::Vec<isize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
// Do not lint
|
||||
[0..200, 0..100];
|
||||
vec![0..200, 0..100];
|
||||
[0.0..200.0];
|
||||
vec![0.0..200.0];
|
||||
// `Copy` is not implemented for `Range`, so this doesn't matter
|
||||
// FIXME: [0..200; 2];
|
||||
// FIXME: [vec!0..200; 2];
|
||||
|
||||
// Unfortunately skips any macros
|
||||
a!();
|
||||
|
||||
// Skip external macros and procedural macros
|
||||
external! {
|
||||
[0..200];
|
||||
vec![0..200];
|
||||
}
|
||||
with_span! {
|
||||
span
|
||||
[0..200];
|
||||
vec![0..200];
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16042() {
|
||||
use std::ops::Range;
|
||||
|
||||
let input = vec![Range { start: 0, end: 5 }];
|
||||
}
|
||||
|
||||
fn issue16044() {
|
||||
macro_rules! as_i32 {
|
||||
($x:expr) => {
|
||||
$x as i32
|
||||
};
|
||||
}
|
||||
|
||||
let input = (0..as_i32!(10)).collect::<std::vec::Vec<i32>>();
|
||||
//~^ single_range_in_vec_init
|
||||
}
|
||||
84
tests/ui/single_range_in_vec_init.2.fixed
Normal file
84
tests/ui/single_range_in_vec_init.2.fixed
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//@aux-build:proc_macros.rs
|
||||
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
|
||||
#![warn(clippy::single_range_in_vec_init)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
||||
macro_rules! a {
|
||||
() => {
|
||||
vec![0..200];
|
||||
};
|
||||
}
|
||||
|
||||
fn awa<T: PartialOrd>(start: T, end: T) {
|
||||
[start..end];
|
||||
}
|
||||
|
||||
fn awa_vec<T: PartialOrd>(start: T, end: T) {
|
||||
vec![start..end];
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Lint
|
||||
[0; 200];
|
||||
//~^ single_range_in_vec_init
|
||||
vec![0; 200];
|
||||
//~^ single_range_in_vec_init
|
||||
[0u8; 200];
|
||||
//~^ single_range_in_vec_init
|
||||
[0usize; 200];
|
||||
//~^ single_range_in_vec_init
|
||||
[0; 200usize];
|
||||
//~^ single_range_in_vec_init
|
||||
vec![0u8; 200];
|
||||
//~^ single_range_in_vec_init
|
||||
vec![0usize; 200];
|
||||
//~^ single_range_in_vec_init
|
||||
vec![0; 200usize];
|
||||
//~^ single_range_in_vec_init
|
||||
// Only suggest collect
|
||||
(0..200isize).collect::<std::vec::Vec<isize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
(0..200isize).collect::<std::vec::Vec<isize>>();
|
||||
//~^ single_range_in_vec_init
|
||||
// Do not lint
|
||||
[0..200, 0..100];
|
||||
vec![0..200, 0..100];
|
||||
[0.0..200.0];
|
||||
vec![0.0..200.0];
|
||||
// `Copy` is not implemented for `Range`, so this doesn't matter
|
||||
// FIXME: [0..200; 2];
|
||||
// FIXME: [vec!0..200; 2];
|
||||
|
||||
// Unfortunately skips any macros
|
||||
a!();
|
||||
|
||||
// Skip external macros and procedural macros
|
||||
external! {
|
||||
[0..200];
|
||||
vec![0..200];
|
||||
}
|
||||
with_span! {
|
||||
span
|
||||
[0..200];
|
||||
vec![0..200];
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16042() {
|
||||
use std::ops::Range;
|
||||
|
||||
let input = vec![Range { start: 0, end: 5 }];
|
||||
}
|
||||
|
||||
fn issue16044() {
|
||||
macro_rules! as_i32 {
|
||||
($x:expr) => {
|
||||
$x as i32
|
||||
};
|
||||
}
|
||||
|
||||
let input = (0..as_i32!(10)).collect::<std::vec::Vec<i32>>();
|
||||
//~^ single_range_in_vec_init
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
//@aux-build:proc_macros.rs
|
||||
//@no-rustfix: overlapping suggestions
|
||||
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
|
||||
#![warn(clippy::single_range_in_vec_init)]
|
||||
|
||||
|
|
@ -72,3 +71,14 @@ fn issue16042() {
|
|||
|
||||
let input = vec![Range { start: 0, end: 5 }];
|
||||
}
|
||||
|
||||
fn issue16044() {
|
||||
macro_rules! as_i32 {
|
||||
($x:expr) => {
|
||||
$x as i32
|
||||
};
|
||||
}
|
||||
|
||||
let input = vec![0..as_i32!(10)];
|
||||
//~^ single_range_in_vec_init
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: an array of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:25:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:24:5
|
||||
|
|
||||
LL | [0..200];
|
||||
| ^^^^^^^^
|
||||
|
|
@ -18,7 +18,7 @@ LL + [0; 200];
|
|||
|
|
||||
|
||||
error: a `Vec` of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:27:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:26:5
|
||||
|
|
||||
LL | vec![0..200];
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
@ -35,7 +35,7 @@ LL + vec![0; 200];
|
|||
|
|
||||
|
||||
error: an array of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:29:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:28:5
|
||||
|
|
||||
LL | [0u8..200];
|
||||
| ^^^^^^^^^^
|
||||
|
|
@ -52,7 +52,7 @@ LL + [0u8; 200];
|
|||
|
|
||||
|
||||
error: an array of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:31:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:30:5
|
||||
|
|
||||
LL | [0usize..200];
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -69,7 +69,7 @@ LL + [0usize; 200];
|
|||
|
|
||||
|
||||
error: an array of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:33:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:32:5
|
||||
|
|
||||
LL | [0..200usize];
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -86,7 +86,7 @@ LL + [0; 200usize];
|
|||
|
|
||||
|
||||
error: a `Vec` of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:35:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:34:5
|
||||
|
|
||||
LL | vec![0u8..200];
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
@ -103,7 +103,7 @@ LL + vec![0u8; 200];
|
|||
|
|
||||
|
||||
error: a `Vec` of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:37:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:36:5
|
||||
|
|
||||
LL | vec![0usize..200];
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -120,7 +120,7 @@ LL + vec![0usize; 200];
|
|||
|
|
||||
|
||||
error: a `Vec` of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:39:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:38:5
|
||||
|
|
||||
LL | vec![0..200usize];
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -137,7 +137,7 @@ LL + vec![0; 200usize];
|
|||
|
|
||||
|
||||
error: an array of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:42:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:41:5
|
||||
|
|
||||
LL | [0..200isize];
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
@ -149,7 +149,7 @@ LL + (0..200isize).collect::<std::vec::Vec<isize>>();
|
|||
|
|
||||
|
||||
error: a `Vec` of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:44:5
|
||||
--> tests/ui/single_range_in_vec_init.rs:43:5
|
||||
|
|
||||
LL | vec![0..200isize];
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -160,5 +160,17 @@ LL - vec![0..200isize];
|
|||
LL + (0..200isize).collect::<std::vec::Vec<isize>>();
|
||||
|
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: a `Vec` of `Range` that is only one element
|
||||
--> tests/ui/single_range_in_vec_init.rs:82:17
|
||||
|
|
||||
LL | let input = vec![0..as_i32!(10)];
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if you wanted a `Vec` that contains the entire range, try
|
||||
|
|
||||
LL - let input = vec![0..as_i32!(10)];
|
||||
LL + let input = (0..as_i32!(10)).collect::<std::vec::Vec<i32>>();
|
||||
|
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue