Skip to content

Commit 1f7a351

Browse files
committed
refactor flow of check_expr in useless_vec
1 parent e539250 commit 1f7a351

File tree

2 files changed

+62
-55
lines changed

2 files changed

+62
-55
lines changed

clippy_lints/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ extern crate clippy_utils;
5050
#[macro_use]
5151
extern crate declare_clippy_lint;
5252

53-
use std::collections::{BTreeMap, BTreeSet};
53+
use std::collections::BTreeMap;
5454

5555
use rustc_data_structures::fx::FxHashSet;
5656
use rustc_lint::{Lint, LintId};
@@ -725,7 +725,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
725725
too_large_for_stack,
726726
msrv: msrv(),
727727
span_to_lint_map: BTreeMap::new(),
728-
lintable_exprs: BTreeSet::new(),
729728
})
730729
});
731730
store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));

clippy_lints/src/vec.rs

+61-53
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{BTreeMap, BTreeSet};
1+
use std::collections::BTreeMap;
22
use std::ops::ControlFlow;
33

44
use clippy_config::msrvs::{self, Msrv};
@@ -14,15 +14,14 @@ use rustc_lint::{LateContext, LateLintPass};
1414
use rustc_middle::ty::layout::LayoutOf;
1515
use rustc_middle::ty::{self, Ty};
1616
use rustc_session::impl_lint_pass;
17-
use rustc_span::{sym, Span};
17+
use rustc_span::{sym, DesugaringKind, Span};
1818

1919
#[expect(clippy::module_name_repetitions)]
2020
#[derive(Clone)]
2121
pub struct UselessVec {
2222
pub too_large_for_stack: u64,
2323
pub msrv: Msrv,
2424
pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
25-
pub lintable_exprs: BTreeSet<HirId>,
2625
}
2726

2827
declare_clippy_lint! {
@@ -72,61 +71,70 @@ pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
7271

7372
impl<'tcx> LateLintPass<'tcx> for UselessVec {
7473
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
75-
// search for `let foo = vec![_]` expressions where all uses of `foo`
76-
// adjust to slices or call a method that exist on slices (e.g. len)
77-
if let Some(vec_args) = higher::VecArgs::hir(cx, expr)
78-
&& let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
79-
// for now ignore locals with type annotations.
80-
// this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
81-
&& local.ty.is_none()
82-
&& let PatKind::Binding(_, id, ..) = local.pat.kind
83-
&& is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr)))
84-
{
85-
let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
86-
// allow indexing into a vec and some set of allowed method calls that exist on slices, too
87-
if let Some(parent) = get_parent_expr(cx, expr)
88-
&& (adjusts_to_slice(cx, expr)
89-
|| matches!(parent.kind, ExprKind::Index(..))
90-
|| is_allowed_vec_method(cx, parent))
91-
{
92-
ControlFlow::Continue(())
74+
if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
75+
// search for `let foo = vec![_]` expressions where all uses of `foo`
76+
// adjust to slices or call a method that exist on slices (e.g. len)
77+
if let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
78+
// for now ignore locals with type annotations.
79+
// this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
80+
&& local.ty.is_none()
81+
&& let PatKind::Binding(_, id, ..) = local.pat.kind
82+
&& is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr.peel_borrows())))
83+
{
84+
let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
85+
// allow indexing into a vec and some set of allowed method calls that exist on slices, too
86+
if let Some(parent) = get_parent_expr(cx, expr)
87+
&& (adjusts_to_slice(cx, expr)
88+
|| matches!(parent.kind, ExprKind::Index(..))
89+
|| is_allowed_vec_method(cx, parent))
90+
{
91+
ControlFlow::Continue(())
92+
} else {
93+
ControlFlow::Break(())
94+
}
95+
})
96+
.is_continue();
97+
98+
let span = expr.span.ctxt().outer_expn_data().call_site;
99+
if only_slice_uses {
100+
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array);
93101
} else {
94-
ControlFlow::Break(())
102+
self.span_to_lint_map.insert(span, None);
95103
}
96-
})
97-
.is_continue();
98-
99-
if only_slice_uses {
104+
}
105+
// if the local pattern has a specified type, do not lint.
106+
else if let Some(_) = higher::VecArgs::hir(cx, expr)
107+
&& let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
108+
&& local.ty.is_some()
109+
{
110+
let span = expr.span.ctxt().outer_expn_data().call_site;
111+
self.span_to_lint_map.insert(span, None);
112+
}
113+
// search for `for _ in vec![...]`
114+
else if let Some(parent) = get_parent_expr(cx, expr)
115+
&& parent.span.is_desugaring(DesugaringKind::ForLoop)
116+
&& self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
117+
{
118+
// report the error around the `vec!` not inside `<std macros>:`
100119
let span = expr.span.ctxt().outer_expn_data().call_site;
101-
self.lintable_exprs.insert(expr.hir_id);
102120
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array);
103121
}
104-
}
105-
// search for `for _ in vec![…]`
106-
else if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr)
107-
&& let Some(vec_args) = higher::VecArgs::hir(cx, arg)
108-
&& self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
109-
{
110-
// report the error around the `vec!` not inside `<std macros>:`
111-
let span = arg.span.ctxt().outer_expn_data().call_site;
112-
self.lintable_exprs.insert(arg.hir_id);
113-
self.check_vec_macro(cx, &vec_args, span, arg.hir_id, SuggestedType::Array);
114-
}
115-
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
116-
else if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
117-
let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
118-
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
119-
(SuggestedType::SliceRef(mutability), expr.span)
120-
} else {
121-
// `expr` is the `vec![_]` expansion, so suggest `[_]`
122-
// and also use the span of the actual `vec![_]` expression
123-
(SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site)
124-
};
125-
126-
if adjusts_to_slice(cx, expr) {
127-
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, suggest_slice);
128-
} else if !self.lintable_exprs.contains(&expr.hir_id) {
129-
self.span_to_lint_map.insert(span, None);
122+
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
123+
else {
124+
let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
125+
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
126+
(SuggestedType::SliceRef(mutability), expr.span)
127+
} else {
128+
// `expr` is the `vec![_]` expansion, so suggest `[_]`
129+
// and also use the span of the actual `vec![_]` expression
130+
(SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site)
131+
};
132+
133+
if adjusts_to_slice(cx, expr) {
134+
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, suggest_slice);
135+
} else {
136+
self.span_to_lint_map.insert(span, None);
137+
}
130138
}
131139
}
132140
}

0 commit comments

Comments
 (0)