Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::use_self::USE_SELF_INFO,
crate::useless_concat::USELESS_CONCAT_INFO,
crate::useless_conversion::USELESS_CONVERSION_INFO,
crate::vec::USELESS_VEC_INFO,
crate::useless_vec::USELESS_VEC_INFO,
crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
crate::visibility::NEEDLESS_PUB_SELF_INFO,
crate::visibility::PUB_WITHOUT_SHORTHAND_INFO,
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ mod upper_case_acronyms;
mod use_self;
mod useless_concat;
mod useless_conversion;
mod vec;
mod useless_vec;
mod vec_init_then_push;
mod visibility;
mod volatile_composites;
Expand Down Expand Up @@ -530,7 +530,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
store.register_late_pass(move |_| Box::new(transmute::Transmute::new(conf)));
store.register_late_pass(move |_| Box::new(cognitive_complexity::CognitiveComplexity::new(conf)));
store.register_late_pass(move |_| Box::new(escape::BoxedLocal::new(conf)));
store.register_late_pass(move |_| Box::new(vec::UselessVec::new(conf)));
store.register_late_pass(move |_| Box::new(useless_vec::UselessVec::new(conf)));
store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented::new(conf)));
store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
store.register_late_pass(|_| Box::new(derive::Derive));
Expand Down
4 changes: 1 addition & 3 deletions clippy_lints/src/ptr/ptr_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::PTR_ARG;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, sym};
use clippy_utils::{get_expr_use_or_unification_node, is_allowed_vec_method, is_lint_allowed, sym};
use hir::LifetimeKind;
use rustc_abi::ExternAbi;
use rustc_errors::Applicability;
Expand All @@ -23,8 +23,6 @@ use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::{fmt, iter};

use crate::vec::is_allowed_vec_method;

pub(super) fn check_body<'tcx>(
cx: &LateContext<'tcx>,
body: &Body<'tcx>,
Expand Down
23 changes: 6 additions & 17 deletions clippy_lints/src/vec.rs → clippy_lints/src/useless_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, higher, is_in_test, span_contains_comment, sym};
use clippy_utils::{get_parent_expr, higher, is_allowed_vec_method, is_in_test, span_contains_comment};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
Expand Down Expand Up @@ -144,8 +144,9 @@ impl UselessVec {
VecToArray::Impossible
},
// search for `for _ in vec![...]`
Node::Expr(Expr { span, .. })
if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) =>
Node::Expr(expr)
if expr.span.is_desugaring(DesugaringKind::ForLoop)
&& self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) =>
{
VecToArray::Possible
},
Expand Down Expand Up @@ -276,9 +277,8 @@ impl SuggestedType {
assert!(args_span.is_none_or(|s| !s.from_expansion()));
assert!(len_span.is_none_or(|s| !s.from_expansion()));

let maybe_args = args_span
.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"))
.map_or(String::new(), |x| x.to_owned());
let maybe_args = args_span.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"));
let maybe_args = maybe_args.as_deref().unwrap_or_default();
let maybe_len = len_span
.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local"))
.map(|st| format!("; {st}"))
Expand All @@ -301,17 +301,6 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
matches!(cx.typeck_results().expr_ty_adjusted(e).kind(), ty::Ref(_, ty, _) if ty.is_slice())
}

/// Checks if the given expression is a method call to a `Vec` method
/// that also exists on slices. If this returns true, it means that
/// this expression does not actually require a `Vec` and could just work with an array.
pub fn is_allowed_vec_method(e: &Expr<'_>) -> bool {
if let ExprKind::MethodCall(path, _, [], _) = e.kind {
matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len)
} else {
false
}
}

fn suggest_type(expr: &Expr<'_>) -> SuggestedType {
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
Expand Down
11 changes: 11 additions & 0 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3523,3 +3523,14 @@ pub fn is_expr_async_block(expr: &Expr<'_>) -> bool {
pub fn can_use_if_let_chains(cx: &LateContext<'_>, msrv: Msrv) -> bool {
cx.tcx.sess.edition().at_least_rust_2024() && msrv.meets(cx, msrvs::LET_CHAINS)
}

/// Checks if the given expression is a method call to a `Vec` method
/// that also exists on slices. If this returns true, it means that
/// this expression does not actually require a `Vec` and could just work with an array.
pub fn is_allowed_vec_method(e: &Expr<'_>) -> bool {
if let ExprKind::MethodCall(path, _, [], _) = e.kind {
matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len)
} else {
false
}
}
38 changes: 18 additions & 20 deletions tests/ui/vec.fixed → tests/ui/useless_vec.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![warn(clippy::useless_vec)]
#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)]

use std::rc::Rc;

Expand Down Expand Up @@ -39,17 +38,14 @@ fn main() {
on_mut_slice(&mut [1, 2]);
//~^ useless_vec

on_slice(&[1, 2]);
//~^ useless_vec
on_slice(&[1, 2]);
on_mut_slice(&mut [1, 2]);
//~^ useless_vec
#[rustfmt::skip]
on_slice(&[1, 2]);
//~^ useless_vec
on_slice(&[1, 2]);
on_mut_slice(&mut [1, 2]);
//~^ useless_vec
#[allow(clippy::nonstandard_macro_braces)] // not an `expect` as it will only lint _before_ the fix
{
on_slice(&[1, 2]);
//~^ useless_vec
on_mut_slice(&mut [1, 2]);
//~^ useless_vec
};

on_slice(&[1; 2]);
//~^ useless_vec
Expand All @@ -75,22 +71,24 @@ fn main() {
on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`

// Ok
// Ok, size of `vec` higher than `too_large_for_stack`
for a in vec![1; 201] {
println!("{:?}", a);
println!("{a:?}");
}

// https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246
let _x: i32 = [1, 2, 3].iter().sum();
//~^ useless_vec

// Do lint
let mut x = [1, 2, 3];
//~^ useless_vec
x.fill(123);
dbg!(x[0]);
dbg!(x.len());
dbg!(x.iter().sum::<i32>());
// Do lint, only used as slice
{
let mut x = [1, 2, 3];
//~^ useless_vec
x.fill(123);
dbg!(x[0]);
dbg!(x.len());
dbg!(x.iter().sum::<i32>());
}

let _x: &[i32] = &[1, 2, 3];
//~^ useless_vec
Expand Down
Loading