find expansions more efficiently

This commit is contained in:
y21 2023-07-09 22:32:58 +02:00
parent 2820d980cb
commit f47165c703
4 changed files with 44 additions and 22 deletions

View File

@ -40,6 +40,7 @@ declare_clippy_lint! {
#[derive(Default)]
pub struct UselessConversion {
try_desugar_arm: Vec<HirId>,
expn_depth: u32,
}
impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);
@ -102,21 +103,11 @@ fn into_iter_deep_call<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -
(expr, depth)
}
/// Checks if the given `expr` is an argument of a macro invocation.
/// This is a slow-ish operation, so consider calling this late
/// to avoid slowing down the lint in the happy path when not emitting a warning
fn is_macro_argument(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let Some(parent) = get_parent_expr(cx, expr) {
parent.span.from_expansion() || is_macro_argument(cx, parent)
} else {
false
}
}
#[expect(clippy::too_many_lines)]
impl<'tcx> LateLintPass<'tcx> for UselessConversion {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if e.span.from_expansion() {
self.expn_depth += 1;
return;
}
@ -185,7 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
&& let Some(&into_iter_param) = sig.inputs().get(kind.param_pos(arg_pos))
&& let ty::Param(param) = into_iter_param.kind()
&& let Some(span) = into_iter_bound(cx, parent_fn_did, into_iter_did, param.index)
&& !is_macro_argument(cx, e)
&& self.expn_depth == 0
{
// Get the "innermost" `.into_iter()` call, e.g. given this expression:
// `foo.into_iter().into_iter()`
@ -321,5 +312,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
if Some(&e.hir_id) == self.try_desugar_arm.last() {
self.try_desugar_arm.pop();
}
if e.span.from_expansion() {
self.expn_depth -= 1;
}
}
}

View File

@ -153,6 +153,20 @@ fn main() {
let _ = vec![s4, s4, s4].into_iter();
}
#[allow(dead_code)]
fn issue11065_fp() {
use std::option::IntoIter;
fn takes_into_iter(_: impl IntoIterator<Item = i32>) {}
macro_rules! x {
($e:expr) => {
takes_into_iter($e);
let _: IntoIter<i32> = $e; // removing `.into_iter()` leads to a type error here
};
}
x!(Some(5).into_iter());
}
#[allow(dead_code)]
fn explicit_into_iter_fn_arg() {
fn a<T>(_: T) {}

View File

@ -153,6 +153,20 @@ fn main() {
let _ = vec![s4, s4, s4].into_iter().into_iter();
}
#[allow(dead_code)]
fn issue11065_fp() {
use std::option::IntoIter;
fn takes_into_iter(_: impl IntoIterator<Item = i32>) {}
macro_rules! x {
($e:expr) => {
takes_into_iter($e);
let _: IntoIter<i32> = $e; // removing `.into_iter()` leads to a type error here
};
}
x!(Some(5).into_iter());
}
#[allow(dead_code)]
fn explicit_into_iter_fn_arg() {
fn a<T>(_: T) {}

View File

@ -119,61 +119,61 @@ LL | let _ = vec![s4, s4, s4].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> $DIR/useless_conversion.rs:169:7
--> $DIR/useless_conversion.rs:183:7
|
LL | b(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> $DIR/useless_conversion.rs:159:13
--> $DIR/useless_conversion.rs:173:13
|
LL | fn b<T: IntoIterator<Item = i32>>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> $DIR/useless_conversion.rs:170:7
--> $DIR/useless_conversion.rs:184:7
|
LL | c(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> $DIR/useless_conversion.rs:160:18
--> $DIR/useless_conversion.rs:174:18
|
LL | fn c(_: impl IntoIterator<Item = i32>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> $DIR/useless_conversion.rs:171:7
--> $DIR/useless_conversion.rs:185:7
|
LL | d(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> $DIR/useless_conversion.rs:163:12
--> $DIR/useless_conversion.rs:177:12
|
LL | T: IntoIterator<Item = i32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> $DIR/useless_conversion.rs:174:7
--> $DIR/useless_conversion.rs:188:7
|
LL | b(vec![1, 2].into_iter().into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> $DIR/useless_conversion.rs:159:13
--> $DIR/useless_conversion.rs:173:13
|
LL | fn b<T: IntoIterator<Item = i32>>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> $DIR/useless_conversion.rs:175:7
--> $DIR/useless_conversion.rs:189:7
|
LL | b(vec![1, 2].into_iter().into_iter().into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> $DIR/useless_conversion.rs:159:13
--> $DIR/useless_conversion.rs:173:13
|
LL | fn b<T: IntoIterator<Item = i32>>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^