-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
new lint: unnecessary_reserve
#14114
base: master
Are you sure you want to change the base?
new lint: unnecessary_reserve
#14114
Conversation
unnecessary_reserve
/// let array: &[usize] = &[1, 2]; | ||
/// vec.extend(array); | ||
/// ``` | ||
#[clippy::version = "1.64.0"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current version is "1.86.0".
/// | ||
/// This lint checks for a call to `reserve` before `extend` on a `Vec` or `VecDeque`. | ||
/// ### Why is this bad? | ||
/// Since Rust 1.62, `extend` implicitly calls `reserve` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can omit "Since Rust 1.62", since it is more than two years old, while checking the MSRV is a good idea, talking about it in the description may not be necessary.
impl_lint_pass!(UnnecessaryReserve => [UNNECESSARY_RESERVE]); | ||
|
||
pub struct UnnecessaryReserve { | ||
msrv: Msrv, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lint also needs to be added to clippy_config/src/conf.rs
.
/// ``` | ||
#[clippy::version = "1.64.0"] | ||
pub UNNECESSARY_RESERVE, | ||
pedantic, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be pedantic
or complexity
?
let acceptable_types = [sym::Vec, sym::VecDeque]; | ||
acceptable_types.iter().any(|&acceptable_ty| { | ||
match cx.typeck_results().expr_ty(struct_calling_on).peel_refs().kind() { | ||
ty::Adt(def, _) => cx.tcx.is_diagnostic_item(acceptable_ty, def.did()), | ||
_ => false, | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cx.typeck_results()
should be called once. Also, using expr_ty_adjusted()
would let you handle cases where the Vec
or VecDeque
is behind a smart pointer such as Box
(and you should add a test case for this).
I think you can match in a simpler way by:
- Moving
adt_def_id()
fromclippy_utils::ty::type_certainty
toclippy_utils::ty
, making it public and adding documentation ("Check ifty
with references peeled is anAdt
and return itsDefId
."). Fix the references by importingsuper::adt_def_id()
in thetype_certainty
module. - Using
adt_def_id()
in your function, for example:
let acceptable_types = [sym::Vec, sym::VecDeque]; | |
acceptable_types.iter().any(|&acceptable_ty| { | |
match cx.typeck_results().expr_ty(struct_calling_on).peel_refs().kind() { | |
ty::Adt(def, _) => cx.tcx.is_diagnostic_item(acceptable_ty, def.did()), | |
_ => false, | |
} | |
}) | |
if let Some(did) = adt_def_id(cx.typeck_results().expr_ty_adjusted(struct_calling_on)) { | |
matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Vec | sym::VecDeque)) | |
} else { | |
false | |
} |
struct_expr: &Expr<'tcx>, | ||
args_a: &Expr<'tcx>, | ||
) -> Option<rustc_span::Span> { | ||
let args_a_kind = &args_a.kind; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to use args_a.kind
directly at line 115, this is clearer and will not be more costly.
let mut read_found = false; | ||
let mut spanless_eq = SpanlessEq::new(cx); | ||
|
||
let _: Option<!> = for_each_expr(cx, block, |expr: &Expr<'tcx>| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, this will suggest to remove a call to reserve()
which follows a call to extend()
as well. It would be better to check only statements following the call to reserve()
, as right now there is a risk of getting many false positives.
@samueltardieu Samuel, really appreciate your review and points! |
resurrection of #10157
fixes #8982
changelog: [
unnecessary_reserve
]: add new lint unnecessary_reserve