Uplift `clippy::double_neg` lint as `double_negations`
Warns about cases like this:
```rust
fn main() {
let x = 1;
let _b = --x; //~ WARN use of a double negation
}
```
The intent is to keep people from thinking that `--x` is a prefix decrement operator. `++x`, `x++` and `x--` are invalid expressions and already have a helpful diagnostic.
I didn't add a machine-applicable suggestion to the lint because it's not entirely clear what the programmer was trying to achieve with the `--x` operation. The code that triggers the lint should always be reviewed manually.
Closes#82987
Receivers which are references to `Option` and `Result`, or who
implement `Deref` to one of those types, will be linted as well.
changelog: [`unnecessary_map_or`]: work with ref and `Deref` to `Option`
and `Result` as well
Fixes#14023
**Note:** this patch must be merged after #13998 – only the second
commit must be reviewed, the first one repeats the patch in #13998 for
mergeability reasons.
I noticed that default PR messages could pass the changelog checking CI.
For example, if a PR is submitted without modifying the PR template, the
following line is mistakenly treated as a valid changelog by the CI:
```
changelog: [`lint_name`]: your change
```
r? flip1995
changelog: none
Get rid of `mir::Const::from_ty_const`
This function is strange, because it turns valtrees into `mir::Const::Value`, but the rest of the const variants stay as type system consts.
All of the callsites except for one in `instsimplify` (array length simplification of `ptr_metadata` call) just go through the valtree arm of the function, so it's easier to just create a `mir::Const` directly for those.
For the instsimplify case, if we have a type system const we should *keep* having a type system const, rather than turning it into a `mir::Const::Value`; it doesn't really matter in practice, though, bc `usize` has no padding, but it feels more principled.
part of https://github.com/rust-lang/rust-clippy/issues/9100
The `obfuscated_if_else` lint currently only triggers for the pattern
`.then_some(..).unwrap_or(..)`, but there're other cases where this lint
should be triggered, one of which is `.then(..).unwrap_or(..)`.
changelog: [`obfuscated_if_else`]: trigger lint for the
`.then(..).unwrap_or(..)` pattern as well
fixes#12895
detects usage of `once_cell::sync::Lazy` and `lazy_static!`,
recommending usage of `std::sync::LazyLock` instead
Many thanks to @J-ZhengLi for putting in most of the work in #12968
----
changelog: new lint [`non_std_lazy_statics`]
changelog: none
`x & 15 == 0` is not equivalent to `x.trailing_zeros() > 4`, as `x =
0b10000` is true for the former and false for the latter.
In fact, clippy itself suggests the following:
```rust
pub fn src(x: i32) -> bool {
x & 15 == 0 // ~error: bit mask could be simplified with a call to `trailing_zeros`
^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4`
}
```
Forbid usage of `hir` `Infer` const/ty variants in ambiguous contexts
The feature `generic_arg_infer` allows providing `_` as an argument to const generics in order to infer them. This introduces a syntactic ambiguity as to whether generic arguments are type or const arguments. In order to get around this we introduced a fourth `GenericArg` variant, `Infer` used to represent `_` as an argument to generic parameters when we don't know if its a type or a const argument.
This made hir visitors that care about `TyKind::Infer` or `ConstArgKind::Infer` very error prone as checking for `TyKind::Infer`s in `visit_ty` would find *some* type infer arguments but not *all* of them as they would sometimes be lowered to `GenericArg::Infer` instead.
Additionally the `visit_infer` method would previously only visit `GenericArg::Infer` not *all* infers (e.g. `TyKind::Infer`), this made it very easy to override `visit_infer` and expect it to visit all infers when in reality it would only visit *some* infers.
---
This PR aims to fix those issues by making the `TyKind` and `ConstArgKind` types generic over whether the infer types/consts are represented by `Ty/ConstArgKind::Infer` or out of line (e.g. by a `GenericArg::Infer` or accessible by overiding `visit_infer`). We then make HIR Visitors convert all const args and types to the versions where infer vars are stored out of line and call `visit_infer` in cases where a `Ty`/`Const` would previously have had a `Ty/ConstArgKind::Infer` variant:
API Summary
```rust
enum AmbigArg {}
enum Ty/ConstArgKind<Unambig = ()> {
...
Infer(Unambig),
}
impl Ty/ConstArg {
fn try_as_ambig_ty/ct(self) -> Option<Ty/ConstArg<AmbigArg>>;
}
impl Ty/ConstArg<AmbigArg> {
fn as_unambig_ty/ct(self) -> Ty/ConstArg;
}
enum InferKind {
Ty(Ty),
Const(ConstArg),
Ambig(InferArg),
}
trait Visitor {
...
fn visit_ty/const_arg(&mut self, Ty/ConstArg<AmbigArg>) -> Self::Result;
fn visit_infer(&mut self, id: HirId, sp: Span, kind: InferKind) -> Self::Result;
}
// blanket impl'd, not meant to be overriden
trait VisitorExt {
fn visit_ty/const_arg_unambig(&mut self, Ty/ConstArg) -> Self::Result;
}
fn walk_unambig_ty/const_arg(&mut V, Ty/ConstArg) -> Self::Result;
fn walk_ty/const_arg(&mut V, Ty/ConstArg<AmbigArg>) -> Self::Result;
```
The end result is that `visit_infer` visits *all* infer args and is also the *only* way to visit an infer arg, `visit_ty` and `visit_const_arg` can now no longer encounter a `Ty/ConstArgKind::Infer`. Representing this in the type system means that it is now very difficult to mess things up, either accessing `TyKind::Infer` "just works" and you won't miss *some* type infers- or it doesn't work and you have to look at `visit_infer` or some `GenericArg::Infer` which forces you to think about the full complexity involved.
Unfortunately there is no lint right now about explicitly matching on uninhabited variants, I can't find the context for why this is the case 🤷♀️
I'm not convinced the framing of un/ambig ty/consts is necessarily the right one but I'm not sure what would be better. I somewhat like calling them full/partial types based on the fact that `Ty<Partial>`/`Ty<Full>` directly specifies how many of the type kinds are actually represented compared to `Ty<Ambig>` which which leaves that to the reader to figure out based on the logical consequences of it the type being in an ambiguous position.
---
tool changes have been modified in their own commits for easier reviewing by anyone getting cc'd from subtree changes. I also attempted to split out "bug fixes arising from the refactoring" into their own commit so they arent lumped in with a big general refactor commit
Fixes#112110
I ran across this message while writing code and thought it was quite
odd. I've simplified it and hopefully made it clearer for non-native
English speakers.
changelog: clarify message for non-obvious precedence
`manual_ok_or` covers the same case that were covered by
`option_map_or_err_ok` which is not deprecated. The latter was in the
"style" category. Also, the lint is machine applicable, and leads to
shorter and more readable code, so "style" is appropriate.
The only difference is that the η-expanded form of `Result::Ok()` was
not covered by `option_map_or_err_ok` while it is by `manual_ok_or`, so
the category change may expose some new occurrences.
Without this check, the lint would suggest that
```rust
match test {
true if option == 5 => 10,
_ => 1,
};
```
is replaced by `if test { 10 } else { 1 }`.
changelog: [`match_bool`]: omit suggestion when guards are present in
`match` expression
Before edition 2024, some temporaries used in scrutinees of a `match`
used as the last expression of a block may outlive some referenced local
variables. Prevent those cases from happening by checking that alive
temporaries with significant drop do have a static lifetime.
The check is performed only for edition 2021 and earlier, and for the
last statement if it would become the last expression of the block.
changelog: [`unnecessary_semicolon`]: prevent borrow errors in editions
lower than 2024
r? @y21
Using `Vec::extend(std::iter::repeat_n(item, N))` allows to use the more
natural number of elements to add `N`, as is probably done in the
original loop, instead of computing the difference between the existing
number of elements and the wanted one.
Before MSRV 1.82, the older suggestion to use `Vec::resize()` is still
issued.
Inspired by #6156 (which predates `repeat_n()`).
changelog: [`same_item_push`]: recommend using `Vec::extend()` to extend
a vector
Before edition 2024, some temporaries used in scrutinees in a `match`
used as the last expression of a block may outlive some referenced
local variables. Prevent those cases from happening by checking that
alive temporaries with significant drop do have a static lifetime.
The check is performed only for edition 2021 and earlier, and for the
last statement if it would become the last expression of the block.