correct suggestions in no_std
(#13999)
I opened https://github.com/rust-lang/rust-clippy/pull/13896 before. However, I found that there're more cases where Clippy suggests to use modules that belong to the `std` crate even in a `no_std` environment. Therefore, this PR include the changes I've made in #13896 and new changes to fix cases I found this time to prevent wrong suggestions in `no_std` environments as well. changelog: [`redundant_closure`]: correct suggestion in `no_std` changelog: [`repeat_vec_with_capacity`]: correct suggestion in `no_std` changelog: [`single_range_in_vec_init`]: don't emit suggestion to use `Vec` in `no_std` changelog: [`drain_collect`]: correct suggestion in `no_std` changelog: [`map_with_unused_argument_over_ranges`]: correct suggestion in `no_std` also close #13895
This commit is contained in:
commit
83bde363b6
17 changed files with 157 additions and 23 deletions
|
@ -3,7 +3,9 @@ use clippy_utils::higher::VecArgs;
|
|||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::get_type_diagnostic_name;
|
||||
use clippy_utils::usage::{local_used_after_expr, local_used_in};
|
||||
use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id};
|
||||
use clippy_utils::{
|
||||
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Safety, TyKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
@ -101,19 +103,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
};
|
||||
|
||||
if body.value.span.from_expansion() {
|
||||
if body.params.is_empty() {
|
||||
if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
|
||||
// replace `|| vec![]` with `Vec::new`
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE,
|
||||
expr.span,
|
||||
"redundant closure",
|
||||
"replace the closure with `Vec::new`",
|
||||
"std::vec::Vec::new".into(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if body.params.is_empty()
|
||||
&& let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value)
|
||||
{
|
||||
let vec_crate = if is_no_std_crate(cx) { "alloc" } else { "std" };
|
||||
// replace `|| vec![]` with `Vec::new`
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE,
|
||||
expr.span,
|
||||
"redundant closure",
|
||||
"replace the closure with `Vec::new`",
|
||||
format!("{vec_crate}::vec::Vec::new"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// skip `foo(|| macro!())`
|
||||
return;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::methods::DRAIN_COLLECT;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_range_full;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::{is_range_full, std_or_core};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -58,12 +58,13 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re
|
|||
.then_some("Vec")
|
||||
.or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String"))
|
||||
.or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs))
|
||||
&& let Some(exec_context) = std_or_core(cx)
|
||||
{
|
||||
let recv = snippet(cx, recv.span, "<expr>");
|
||||
let sugg = if let ty::Ref(..) = recv_ty.kind() {
|
||||
format!("std::mem::take({recv})")
|
||||
format!("{exec_context}::mem::take({recv})")
|
||||
} else {
|
||||
format!("std::mem::take(&mut {recv})")
|
||||
format!("{exec_context}::mem::take(&mut {recv})")
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{eager_or_lazy, higher, usage};
|
||||
use clippy_utils::{eager_or_lazy, higher, std_or_core, usage};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
|
@ -75,6 +75,7 @@ pub(super) fn check(
|
|||
} = body_hir
|
||||
&& !usage::BindingUsageFinder::are_params_used(cx, body_hir)
|
||||
&& let Some(count) = extract_count_with_applicability(cx, range, &mut applicability)
|
||||
&& let Some(exec_context) = std_or_core(cx)
|
||||
{
|
||||
let method_to_use_name;
|
||||
let new_span;
|
||||
|
@ -105,7 +106,7 @@ pub(super) fn check(
|
|||
let mut parts = vec![
|
||||
(
|
||||
receiver.span.to(method_call_span),
|
||||
format!("std::iter::{method_to_use_name}"),
|
||||
format!("{exec_context}::iter::{method_to_use_name}"),
|
||||
),
|
||||
new_span,
|
||||
];
|
||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::macros::matching_root_macro_call;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::{expr_or_init, fn_def_id};
|
||||
use clippy_utils::{expr_or_init, fn_def_id, std_or_core};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -93,6 +93,7 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
&& let ExprKind::Call(_, [repeat_expr]) = expr.kind
|
||||
&& fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did))
|
||||
&& !repeat_expr.span.from_expansion()
|
||||
&& let Some(exec_context) = std_or_core(cx)
|
||||
{
|
||||
emit_lint(
|
||||
cx,
|
||||
|
@ -100,7 +101,10 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
"iter::repeat",
|
||||
"none of the yielded `Vec`s will have the requested capacity",
|
||||
"if you intended to create an iterator that yields `Vec`s with an initial capacity, try",
|
||||
format!("std::iter::repeat_with(|| {})", snippet(cx, repeat_expr.span, "..")),
|
||||
format!(
|
||||
"{exec_context}::iter::repeat_with(|| {})",
|
||||
snippet(cx, repeat_expr.span, "..")
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::get_trait_def_id;
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::macros::root_macro_call_first_node;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_trait_def_id, is_no_std_crate};
|
||||
use rustc_ast::{LitIntType, LitKind, UintTy};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr};
|
||||
|
@ -125,7 +125,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
|
|||
span,
|
||||
format!("{suggested_type} of `Range` that is only one element"),
|
||||
|diag| {
|
||||
if should_emit_every_value {
|
||||
if should_emit_every_value && !is_no_std_crate(cx) {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"if you wanted a `Vec` that contains the entire range, try",
|
||||
|
|
8
tests/ui/drain_collect_nostd.fixed
Normal file
8
tests/ui/drain_collect_nostd.fixed
Normal file
|
@ -0,0 +1,8 @@
|
|||
#![warn(clippy::drain_collect)]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
|
||||
core::mem::take(v)
|
||||
}
|
8
tests/ui/drain_collect_nostd.rs
Normal file
8
tests/ui/drain_collect_nostd.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#![warn(clippy::drain_collect)]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
|
||||
v.drain(..).collect()
|
||||
}
|
11
tests/ui/drain_collect_nostd.stderr
Normal file
11
tests/ui/drain_collect_nostd.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error: you seem to be trying to move all elements into a new `Vec`
|
||||
--> tests/ui/drain_collect_nostd.rs:7:5
|
||||
|
|
||||
LL | v.drain(..).collect()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `core::mem::take(v)`
|
||||
|
|
||||
= note: `-D clippy::drain-collect` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::drain_collect)]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
10
tests/ui/eta_nostd.fixed
Normal file
10
tests/ui/eta_nostd.fixed
Normal file
|
@ -0,0 +1,10 @@
|
|||
#![warn(clippy::redundant_closure)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn issue_13895() {
|
||||
let _: Option<Vec<u8>> = true.then(alloc::vec::Vec::new);
|
||||
}
|
10
tests/ui/eta_nostd.rs
Normal file
10
tests/ui/eta_nostd.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#![warn(clippy::redundant_closure)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn issue_13895() {
|
||||
let _: Option<Vec<u8>> = true.then(|| vec![]);
|
||||
}
|
11
tests/ui/eta_nostd.stderr
Normal file
11
tests/ui/eta_nostd.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error: redundant closure
|
||||
--> tests/ui/eta_nostd.rs:9:40
|
||||
|
|
||||
LL | let _: Option<Vec<u8>> = true.then(|| vec![]);
|
||||
| ^^^^^^^^^ help: replace the closure with `Vec::new`: `alloc::vec::Vec::new`
|
||||
|
|
||||
= note: `-D clippy::redundant-closure` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#![warn(clippy::map_with_unused_argument_over_ranges)]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn nostd(v: &mut [i32]) {
|
||||
let _: Vec<_> = core::iter::repeat_n(3 + 1, 10).collect();
|
||||
}
|
8
tests/ui/map_with_unused_argument_over_ranges_nostd.rs
Normal file
8
tests/ui/map_with_unused_argument_over_ranges_nostd.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#![warn(clippy::map_with_unused_argument_over_ranges)]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn nostd(v: &mut [i32]) {
|
||||
let _: Vec<_> = (0..10).map(|_| 3 + 1).collect();
|
||||
}
|
15
tests/ui/map_with_unused_argument_over_ranges_nostd.stderr
Normal file
15
tests/ui/map_with_unused_argument_over_ranges_nostd.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error: map of a closure that does not depend on its parameter over a range
|
||||
--> tests/ui/map_with_unused_argument_over_ranges_nostd.rs:7:21
|
||||
|
|
||||
LL | let _: Vec<_> = (0..10).map(|_| 3 + 1).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::map-with-unused-argument-over-ranges` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::map_with_unused_argument_over_ranges)]`
|
||||
help: remove the explicit range and use `repeat_n`
|
||||
|
|
||||
LL | let _: Vec<_> = core::iter::repeat_n(3 + 1, 10).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
10
tests/ui/repeat_vec_with_capacity_nostd.fixed
Normal file
10
tests/ui/repeat_vec_with_capacity_nostd.fixed
Normal file
|
@ -0,0 +1,10 @@
|
|||
#![warn(clippy::repeat_vec_with_capacity)]
|
||||
#![allow(clippy::manual_repeat_n)]
|
||||
#![no_std]
|
||||
use core::iter;
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn nostd() {
|
||||
let _: Vec<Vec<u8>> = core::iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect();
|
||||
}
|
10
tests/ui/repeat_vec_with_capacity_nostd.rs
Normal file
10
tests/ui/repeat_vec_with_capacity_nostd.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#![warn(clippy::repeat_vec_with_capacity)]
|
||||
#![allow(clippy::manual_repeat_n)]
|
||||
#![no_std]
|
||||
use core::iter;
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fn nostd() {
|
||||
let _: Vec<Vec<u8>> = iter::repeat(Vec::with_capacity(42)).take(123).collect();
|
||||
}
|
16
tests/ui/repeat_vec_with_capacity_nostd.stderr
Normal file
16
tests/ui/repeat_vec_with_capacity_nostd.stderr
Normal file
|
@ -0,0 +1,16 @@
|
|||
error: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity
|
||||
--> tests/ui/repeat_vec_with_capacity_nostd.rs:9:27
|
||||
|
|
||||
LL | let _: Vec<Vec<u8>> = iter::repeat(Vec::with_capacity(42)).take(123).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: none of the yielded `Vec`s will have the requested capacity
|
||||
= note: `-D clippy::repeat-vec-with-capacity` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::repeat_vec_with_capacity)]`
|
||||
help: if you intended to create an iterator that yields `Vec`s with an initial capacity, try
|
||||
|
|
||||
LL | let _: Vec<Vec<u8>> = core::iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue