Merge commit '09ac14c901abc43bd0d617ae4a44e8a4fed98d9c' into clippyup

This commit is contained in:
Philipp Krones 2023-11-02 17:35:56 +01:00
commit 257147a779
No known key found for this signature in database
GPG Key ID: 1CA0DF2AF59D68A5
418 changed files with 4900 additions and 3588 deletions

View File

@ -60,7 +60,7 @@ jobs:
working-directory: clippy_lints
- name: Test clippy_utils
run: cargo test --features deny-warnings,internal
run: cargo test --features deny-warnings
working-directory: clippy_utils
- name: Test rustc_tools_util

View File

@ -120,9 +120,13 @@ jobs:
working-directory: clippy_lints
- name: Test clippy_utils
run: cargo test --features deny-warnings,internal
run: cargo test --features deny-warnings
working-directory: clippy_utils
- name: Test clippy_config
run: cargo test --features deny-warnings
working-directory: clippy_config
- name: Test rustc_tools_util
run: cargo test --features deny-warnings
working-directory: rustc_tools_util

View File

@ -5528,6 +5528,7 @@ Released 2018-09-13
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
[`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
@ -5560,6 +5561,7 @@ Released 2018-09-13
[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
[`unused_enumerate_index`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_enumerate_index
[`unused_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs
[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
@ -5589,6 +5591,7 @@ Released 2018-09-13
[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
[`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator

View File

@ -21,11 +21,12 @@ name = "clippy-driver"
path = "src/driver.rs"
[dependencies]
clippy_config = { path = "clippy_config" }
clippy_lints = { path = "clippy_lints" }
rustc_tools_util = "0.3.0"
tempfile = { version = "3.2", optional = true }
termize = "0.1"
color-print = "0.3.4" # Sync version with Cargo
color-print = "0.3.4"
anstream = "0.5.0"
[dev-dependencies]

View File

@ -26,7 +26,7 @@ arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
A type, say `SomeType`, listed in this configuration has the same behavior of
`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -49,7 +49,7 @@ Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the
arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
```
**Default Value:** `[]` (`Vec<[String; 2]>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -65,7 +65,7 @@ Suppress checking of the passed type names in unary operations like "negation" (
arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
```
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -75,7 +75,7 @@ arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
## `avoid-breaking-exported-api`
Suppress lints whenever the suggested change would cause breakage for other crates.
**Default Value:** `true` (`bool`)
**Default Value:** `true`
---
**Affected lints:**
@ -98,9 +98,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
## `msrv`
The minimum rust version that the project supports
**Default Value:** `Msrv { stack: [] }` (`crate::Msrv`)
The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
---
**Affected lints:**
@ -157,7 +155,7 @@ The minimum rust version that the project supports
## `cognitive-complexity-threshold`
The maximum cognitive complexity a function can have
**Default Value:** `25` (`u64`)
**Default Value:** `25`
---
**Affected lints:**
@ -167,7 +165,7 @@ The maximum cognitive complexity a function can have
## `excessive-nesting-threshold`
The maximum amount of nesting a block can reside in
**Default Value:** `0` (`u64`)
**Default Value:** `0`
---
**Affected lints:**
@ -179,7 +177,7 @@ The list of disallowed names to lint about. NB: `bar` is not here since it has l
`".."` can be used as part of the list to indicate that the configured values should be appended to the
default configuration of Clippy. By default, any configuration will replace the default value.
**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
**Default Value:** `["foo", "baz", "quux"]`
---
**Affected lints:**
@ -189,7 +187,7 @@ default configuration of Clippy. By default, any configuration will replace the
## `semicolon-inside-block-ignore-singleline`
Whether to lint only if it's multiline.
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -199,7 +197,7 @@ Whether to lint only if it's multiline.
## `semicolon-outside-block-ignore-multiline`
Whether to lint only if it's singleline.
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -213,9 +211,7 @@ default configuration of Clippy. By default, any configuration will replace the
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
Default list:
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`)
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
---
**Affected lints:**
@ -225,7 +221,7 @@ Default list:
## `too-many-arguments-threshold`
The maximum number of argument a function or method can have
**Default Value:** `7` (`u64`)
**Default Value:** `7`
---
**Affected lints:**
@ -235,7 +231,7 @@ The maximum number of argument a function or method can have
## `type-complexity-threshold`
The maximum complexity a type can have
**Default Value:** `250` (`u64`)
**Default Value:** `250`
---
**Affected lints:**
@ -245,7 +241,7 @@ The maximum complexity a type can have
## `single-char-binding-names-threshold`
The maximum number of single char bindings a scope may have
**Default Value:** `4` (`u64`)
**Default Value:** `4`
---
**Affected lints:**
@ -255,7 +251,7 @@ The maximum number of single char bindings a scope may have
## `too-large-for-stack`
The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
**Default Value:** `200` (`u64`)
**Default Value:** `200`
---
**Affected lints:**
@ -266,7 +262,7 @@ The maximum size of objects (in bytes) that will be linted. Larger objects are o
## `enum-variant-name-threshold`
The minimum number of enum variants for the lints about variant names to trigger
**Default Value:** `3` (`u64`)
**Default Value:** `3`
---
**Affected lints:**
@ -276,7 +272,7 @@ The minimum number of enum variants for the lints about variant names to trigger
## `struct-field-name-threshold`
The minimum number of struct fields for the lints about field names to trigger
**Default Value:** `3` (`u64`)
**Default Value:** `3`
---
**Affected lints:**
@ -286,7 +282,7 @@ The minimum number of struct fields for the lints about field names to trigger
## `enum-variant-size-threshold`
The maximum size of an enum's variant to avoid box suggestion
**Default Value:** `200` (`u64`)
**Default Value:** `200`
---
**Affected lints:**
@ -296,7 +292,7 @@ The maximum size of an enum's variant to avoid box suggestion
## `verbose-bit-mask-threshold`
The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
**Default Value:** `1` (`u64`)
**Default Value:** `1`
---
**Affected lints:**
@ -306,7 +302,7 @@ The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
## `literal-representation-threshold`
The lower bound for linting decimal literals
**Default Value:** `16384` (`u64`)
**Default Value:** `16384`
---
**Affected lints:**
@ -314,9 +310,8 @@ The lower bound for linting decimal literals
## `trivial-copy-size-limit`
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
**Default Value:** `None` (`Option<u64>`)
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
reference. By default there is no limit
---
**Affected lints:**
@ -326,7 +321,7 @@ The maximum size (in bytes) to consider a `Copy` type for passing by value inste
## `pass-by-value-size-limit`
The minimum size (in bytes) to consider a type for passing by reference instead of by value.
**Default Value:** `256` (`u64`)
**Default Value:** `256`
---
**Affected lints:**
@ -336,7 +331,7 @@ The minimum size (in bytes) to consider a type for passing by reference instead
## `too-many-lines-threshold`
The maximum number of lines a function or method can have
**Default Value:** `100` (`u64`)
**Default Value:** `100`
---
**Affected lints:**
@ -346,7 +341,7 @@ The maximum number of lines a function or method can have
## `array-size-threshold`
The maximum allowed size for arrays on the stack
**Default Value:** `512000` (`u64`)
**Default Value:** `512000`
---
**Affected lints:**
@ -357,7 +352,7 @@ The maximum allowed size for arrays on the stack
## `stack-size-threshold`
The maximum allowed stack size for functions in bytes
**Default Value:** `512000` (`u64`)
**Default Value:** `512000`
---
**Affected lints:**
@ -367,7 +362,7 @@ The maximum allowed stack size for functions in bytes
## `vec-box-size-threshold`
The size of the boxed type in bytes, where boxing in a `Vec` is allowed
**Default Value:** `4096` (`u64`)
**Default Value:** `4096`
---
**Affected lints:**
@ -377,7 +372,7 @@ The size of the boxed type in bytes, where boxing in a `Vec` is allowed
## `max-trait-bounds`
The maximum number of bounds a trait can have to be linted
**Default Value:** `3` (`u64`)
**Default Value:** `3`
---
**Affected lints:**
@ -387,7 +382,7 @@ The maximum number of bounds a trait can have to be linted
## `max-struct-bools`
The maximum number of bool fields a struct can have
**Default Value:** `3` (`u64`)
**Default Value:** `3`
---
**Affected lints:**
@ -397,7 +392,7 @@ The maximum number of bool fields a struct can have
## `max-fn-params-bools`
The maximum number of bool parameters a function can have
**Default Value:** `3` (`u64`)
**Default Value:** `3`
---
**Affected lints:**
@ -407,7 +402,7 @@ The maximum number of bool parameters a function can have
## `warn-on-all-wildcard-imports`
Whether to allow certain wildcard imports (prelude, super in tests).
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -417,7 +412,7 @@ Whether to allow certain wildcard imports (prelude, super in tests).
## `disallowed-macros`
The list of disallowed macros, written as fully qualified paths.
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -427,7 +422,7 @@ The list of disallowed macros, written as fully qualified paths.
## `disallowed-methods`
The list of disallowed methods, written as fully qualified paths.
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -437,7 +432,7 @@ The list of disallowed methods, written as fully qualified paths.
## `disallowed-types`
The list of disallowed types, written as fully qualified paths.
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -447,7 +442,7 @@ The list of disallowed types, written as fully qualified paths.
## `unreadable-literal-lint-fractions`
Should the fraction of a decimal be linted to include separators.
**Default Value:** `true` (`bool`)
**Default Value:** `true`
---
**Affected lints:**
@ -457,7 +452,7 @@ Should the fraction of a decimal be linted to include separators.
## `upper-case-acronyms-aggressive`
Enables verbose mode. Triggers if there is more than one uppercase char next to each other
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -468,7 +463,7 @@ Enables verbose mode. Triggers if there is more than one uppercase char next to
Whether the matches should be considered by the lint, and whether there should
be filtering for common types.
**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`)
**Default Value:** `"WellKnownTypes"`
---
**Affected lints:**
@ -478,11 +473,11 @@ be filtering for common types.
## `cargo-ignore-publish`
For internal testing only, ignores the current `publish` settings in the Cargo manifest.
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
* [`_cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata)
* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata)
## `standard-macro-braces`
@ -492,7 +487,7 @@ A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If
could be used with a full path two `MacroMatcher`s have to be added one with the full path
`crate_name::macro_name` and one with just the macro name.
**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -502,7 +497,7 @@ could be used with a full path two `MacroMatcher`s have to be added one with the
## `enforced-import-renames`
The list of imports to always rename, a fully qualified path followed by the rename.
**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -512,7 +507,7 @@ The list of imports to always rename, a fully qualified path followed by the ren
## `allowed-scripts`
The list of unicode scripts allowed to be used in the scope.
**Default Value:** `["Latin"]` (`Vec<String>`)
**Default Value:** `["Latin"]`
---
**Affected lints:**
@ -522,7 +517,7 @@ The list of unicode scripts allowed to be used in the scope.
## `enable-raw-pointer-heuristic-for-send`
Whether to apply the raw pointer heuristic to determine if a type is `Send`.
**Default Value:** `true` (`bool`)
**Default Value:** `true`
---
**Affected lints:**
@ -534,7 +529,7 @@ When Clippy suggests using a slice pattern, this is the maximum number of elemen
the slice pattern that is suggested. If more elements are necessary, the lint is suppressed.
For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
**Default Value:** `3` (`u64`)
**Default Value:** `3`
---
**Affected lints:**
@ -544,7 +539,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
## `await-holding-invalid-types`
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -554,7 +549,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
## `max-include-file-size`
The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
**Default Value:** `1000000` (`u64`)
**Default Value:** `1000000`
---
**Affected lints:**
@ -564,7 +559,7 @@ The maximum size of a file included via `include_bytes!()` or `include_str!()`,
## `allow-expect-in-tests`
Whether `expect` should be allowed in test functions or `#[cfg(test)]`
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -574,7 +569,7 @@ Whether `expect` should be allowed in test functions or `#[cfg(test)]`
## `allow-unwrap-in-tests`
Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -584,7 +579,7 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
## `allow-dbg-in-tests`
Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -594,7 +589,7 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
## `allow-print-in-tests`
Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -605,7 +600,7 @@ Whether print macros (ex. `println!`) should be allowed in test functions or `#[
## `large-error-threshold`
The maximum size of the `Err`-variant in a `Result` returned from a function
**Default Value:** `128` (`u64`)
**Default Value:** `128`
---
**Affected lints:**
@ -616,7 +611,7 @@ The maximum size of the `Err`-variant in a `Result` returned from a function
A list of paths to types that should be treated like `Arc`, i.e. ignored but
for the generic parameters for determining interior mutability
**Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
**Default Value:** `["bytes::Bytes"]`
---
**Affected lints:**
@ -627,7 +622,7 @@ for the generic parameters for determining interior mutability
## `allow-mixed-uninlined-format-args`
Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
**Default Value:** `true` (`bool`)
**Default Value:** `true`
---
**Affected lints:**
@ -641,7 +636,7 @@ suggested counterparts are unavailable in constant code. This
configuration will cause restriction lints to trigger even
if no suggestion can be made.
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -652,7 +647,7 @@ if no suggestion can be made.
Whether to **only** check for missing documentation in items visible within the current
crate. For example, `pub(crate)` items.
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -662,7 +657,7 @@ crate. For example, `pub(crate)` items.
## `future-size-threshold`
The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
**Default Value:** `16384` (`u64`)
**Default Value:** `16384`
---
**Affected lints:**
@ -672,7 +667,7 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large
## `unnecessary-box-size`
The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
**Default Value:** `128` (`u64`)
**Default Value:** `128`
---
**Affected lints:**
@ -682,7 +677,7 @@ The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::u
## `allow-private-module-inception`
Whether to allow module inception if it's not public.
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -694,7 +689,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used
the list to indicate, that the configured values should be appended to the default
configuration of Clippy. By default, any configuration will replace the default value.
**Default Value:** `{"j", "z", "i", "y", "n", "x", "w"}` (`rustc_data_structures::fx::FxHashSet<String>`)
**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]`
---
**Affected lints:**
@ -704,7 +699,7 @@ configuration of Clippy. By default, any configuration will replace the default
## `min-ident-chars-threshold`
Minimum chars an ident can have, anything below or equal to this will be linted.
**Default Value:** `1` (`u64`)
**Default Value:** `1`
---
**Affected lints:**
@ -714,7 +709,7 @@ Minimum chars an ident can have, anything below or equal to this will be linted.
## `accept-comment-above-statement`
Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
**Default Value:** `true` (`bool`)
**Default Value:** `true`
---
**Affected lints:**
@ -724,7 +719,7 @@ Whether to accept a safety comment to be placed above the statement containing t
## `accept-comment-above-attributes`
Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
**Default Value:** `true` (`bool`)
**Default Value:** `true`
---
**Affected lints:**
@ -734,7 +729,7 @@ Whether to accept a safety comment to be placed above the attributes for the `un
## `allow-one-hash-in-raw-strings`
Whether to allow `r#""#` when `r""` can be used
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**
@ -745,7 +740,7 @@ Whether to allow `r#""#` when `r""` can be used
The maximum number of segments a path can have before being linted, anything above this will
be linted.
**Default Value:** `2` (`u64`)
**Default Value:** `2`
---
**Affected lints:**
@ -755,7 +750,7 @@ be linted.
## `absolute-paths-allowed-crates`
Which crates to allow absolute paths from
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -765,7 +760,7 @@ Which crates to allow absolute paths from
## `allowed-dotfiles`
Additional dotfiles (files or directories starting with a dot) to allow
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
**Default Value:** `[]`
---
**Affected lints:**
@ -774,7 +769,7 @@ Additional dotfiles (files or directories starting with a dot) to allow
## `enforce-iter-loop-reborrow`
#### Example
```
```no_run
let mut vec = vec![1, 2, 3];
let rmvec = &mut vec;
for _ in rmvec.iter() {}
@ -782,14 +777,14 @@ for _ in rmvec.iter_mut() {}
```
Use instead:
```
```no_run
let mut vec = vec![1, 2, 3];
let rmvec = &mut vec;
for _ in &*rmvec {}
for _ in &mut *rmvec {}
```
**Default Value:** `false` (`bool`)
**Default Value:** `false`
---
**Affected lints:**

View File

@ -0,0 +1,21 @@
[package]
name = "clippy_config"
version = "0.1.75"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rustc-semver = "1.1"
serde = { version = "1.0", features = ["derive"] }
toml = "0.7.3"
[dev-dependencies]
walkdir = "2.3"
[features]
deny-warnings = []
[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)]
rustc_private = true

View File

@ -1,11 +1,11 @@
//! Read configurations files.
#![allow(clippy::module_name_repetitions)]
use crate::msrvs::Msrv;
use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename};
use crate::ClippyConfiguration;
use rustc_data_structures::fx::FxHashSet;
use rustc_session::Session;
use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext};
use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
use serde::Deserialize;
use serde::de::{IgnoredAny, IntoDeserializer, MapAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt::{Debug, Display, Formatter};
use std::ops::Range;
use std::path::PathBuf;
@ -38,43 +38,12 @@
const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
#[derive(Clone, Debug, Deserialize)]
pub struct Rename {
pub path: String,
pub rename: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum DisallowedPath {
Simple(String),
WithReason { path: String, reason: Option<String> },
}
impl DisallowedPath {
pub fn path(&self) -> &str {
let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
path
}
pub fn reason(&self) -> Option<String> {
match self {
Self::WithReason {
reason: Some(reason), ..
} => Some(format!("{reason} (from clippy.toml)")),
_ => None,
}
}
}
/// Conf with parse errors
#[derive(Default)]
pub struct TryConf {
pub conf: Conf,
pub errors: Vec<ConfError>,
pub warnings: Vec<ConfError>,
struct TryConf {
conf: Conf,
errors: Vec<ConfError>,
warnings: Vec<ConfError>,
}
impl TryConf {
@ -88,9 +57,9 @@ fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self {
}
#[derive(Debug)]
pub struct ConfError {
pub message: String,
pub span: Span,
struct ConfError {
message: String,
span: Span,
}
impl ConfError {
@ -112,10 +81,31 @@ fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) ->
}
}
macro_rules! wrap_option {
() => {
None
};
($x:literal) => {
Some($x)
};
}
macro_rules! default_text {
($value:expr) => {{
let mut text = String::new();
$value.serialize(toml::ser::ValueSerializer::new(&mut text)).unwrap();
text
}};
($value:expr, $override:expr) => {
$override.to_string()
};
}
macro_rules! define_Conf {
($(
$(#[doc = $doc:literal])+
$(#[conf_deprecated($dep:literal, $new_conf:ident)])?
$(#[default_text = $default_text:expr])?
($name:ident: $ty:ty = $default:expr),
)*) => {
/// Clippy lint configuration
@ -124,6 +114,7 @@ pub struct Conf {
}
mod defaults {
use super::*;
$(pub fn $name() -> $ty { $default })*
}
@ -190,31 +181,21 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapA
}
}
pub mod metadata {
use crate::utils::ClippyConfiguration;
pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
vec![
$(
{
let deprecation_reason = wrap_option!($($dep)?);
macro_rules! wrap_option {
() => (None);
($x:literal) => (Some($x));
}
pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
vec![
$(
{
let deprecation_reason = wrap_option!($($dep)?);
ClippyConfiguration::new(
stringify!($name),
stringify!($ty),
format!("{:?}", super::defaults::$name()),
concat!($($doc, '\n',)*),
deprecation_reason,
)
},
)+
]
}
ClippyConfiguration::new(
stringify!($name),
default_text!(defaults::$name() $(, $default_text)?),
concat!($($doc, '\n',)*),
deprecation_reason,
)
},
)+
]
}
};
}
@ -236,7 +217,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
///
/// A type, say `SomeType`, listed in this configuration has the same behavior of
/// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
(arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
(arithmetic_side_effects_allowed: FxHashSet<String> = <_>::default()),
/// Lint: ARITHMETIC_SIDE_EFFECTS.
///
/// Suppress checking of the passed type pair names in binary operations like addition or
@ -263,15 +244,16 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// ```toml
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
/// ```
(arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
(arithmetic_side_effects_allowed_unary: FxHashSet<String> = <_>::default()),
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN.
///
/// Suppress lints whenever the suggested change would cause breakage for other crates.
(avoid_breaking_exported_api: bool = true),
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE.
///
/// The minimum rust version that the project supports
(msrv: crate::Msrv = crate::Msrv::empty()),
/// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
#[default_text = ""]
(msrv: Msrv = Msrv::empty()),
/// DEPRECATED LINT: BLACKLISTED_NAME.
///
/// Use the Disallowed Names lint instead
@ -295,7 +277,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
/// `".."` can be used as part of the list to indicate that the configured values should be appended to the
/// default configuration of Clippy. By default, any configuration will replace the default value.
(disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
(disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
/// Lint: SEMICOLON_INSIDE_BLOCK.
///
/// Whether to lint only if it's multiline.
@ -311,9 +293,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// default configuration of Clippy. By default, any configuration will replace the default value. For example:
/// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
/// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
///
/// Default list:
(doc_valid_idents: Vec<String> = super::DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
(doc_valid_idents: Vec<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
/// Lint: TOO_MANY_ARGUMENTS.
///
/// The maximum number of argument a function or method can have
@ -352,7 +332,9 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
(literal_representation_threshold: u64 = 16384),
/// Lint: TRIVIALLY_COPY_PASS_BY_REF.
///
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
/// reference. By default there is no limit
#[default_text = ""]
(trivial_copy_size_limit: Option<u64> = None),
/// Lint: LARGE_TYPES_PASSED_BY_VALUE.
///
@ -393,15 +375,15 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// Lint: DISALLOWED_MACROS.
///
/// The list of disallowed macros, written as fully qualified paths.
(disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
(disallowed_macros: Vec<DisallowedPath> = Vec::new()),
/// Lint: DISALLOWED_METHODS.
///
/// The list of disallowed methods, written as fully qualified paths.
(disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
(disallowed_methods: Vec<DisallowedPath> = Vec::new()),
/// Lint: DISALLOWED_TYPES.
///
/// The list of disallowed types, written as fully qualified paths.
(disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
(disallowed_types: Vec<DisallowedPath> = Vec::new()),
/// Lint: UNREADABLE_LITERAL.
///
/// Should the fraction of a decimal be linted to include separators.
@ -414,9 +396,8 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
///
/// Whether the matches should be considered by the lint, and whether there should
/// be filtering for common types.
(matches_for_let_else: crate::manual_let_else::MatchLintBehaviour =
crate::manual_let_else::MatchLintBehaviour::WellKnownTypes),
/// Lint: _CARGO_COMMON_METADATA.
(matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes),
/// Lint: CARGO_COMMON_METADATA.
///
/// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
(cargo_ignore_publish: bool = false),
@ -427,11 +408,11 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
/// could be used with a full path two `MacroMatcher`s have to be added one with the full path
/// `crate_name::macro_name` and one with just the macro name.
(standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
(standard_macro_braces: Vec<MacroMatcher> = Vec::new()),
/// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
///
/// The list of imports to always rename, a fully qualified path followed by the rename.
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
(enforced_import_renames: Vec<Rename> = Vec::new()),
/// Lint: DISALLOWED_SCRIPT_IDENTS.
///
/// The list of unicode scripts allowed to be used in the scope.
@ -447,7 +428,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
(max_suggested_slice_pattern_length: u64 = 3),
/// Lint: AWAIT_HOLDING_INVALID_TYPE.
(await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
(await_holding_invalid_types: Vec<DisallowedPath> = Vec::new()),
/// Lint: LARGE_INCLUDE_FILE.
///
/// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
@ -511,8 +492,8 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
/// the list to indicate, that the configured values should be appended to the default
/// configuration of Clippy. By default, any configuration will replace the default value.
(allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet<String> =
super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
(allowed_idents_below_min_chars: FxHashSet<String> =
DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
/// Lint: MIN_IDENT_CHARS.
///
/// Minimum chars an ident can have, anything below or equal to this will be linted.
@ -537,19 +518,17 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// Lint: ABSOLUTE_PATHS.
///
/// Which crates to allow absolute paths from
(absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
rustc_data_structures::fx::FxHashSet::default()),
(absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default()),
/// Lint: PATH_ENDS_WITH_EXT.
///
/// Additional dotfiles (files or directories starting with a dot) to allow
(allowed_dotfiles: rustc_data_structures::fx::FxHashSet<String> =
rustc_data_structures::fx::FxHashSet::default()),
(allowed_dotfiles: FxHashSet<String> = FxHashSet::default()),
/// Lint: EXPLICIT_ITER_LOOP
///
/// Whether to recommend using implicit into iter for reborrowed values.
///
/// #### Example
/// ```
/// ```no_run
/// let mut vec = vec![1, 2, 3];
/// let rmvec = &mut vec;
/// for _ in rmvec.iter() {}
@ -557,7 +536,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// ```
///
/// Use instead:
/// ```
/// ```no_run
/// let mut vec = vec![1, 2, 3];
/// let rmvec = &mut vec;
/// for _ in &*rmvec {}
@ -779,7 +758,7 @@ mod tests {
#[test]
fn configs_are_tested() {
let mut names: FxHashSet<String> = super::metadata::get_configuration_metadata()
let mut names: FxHashSet<String> = crate::get_configuration_metadata()
.into_iter()
.map(|meta| meta.name.replace('_', "-"))
.collect();

View File

@ -0,0 +1,23 @@
#![feature(rustc_private, let_chains)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(
clippy::must_use_candidate,
clippy::missing_panics_doc,
rustc::untranslatable_diagnostic_trivial
)]
extern crate rustc_ast;
extern crate rustc_data_structures;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
extern crate rustc_session;
extern crate rustc_span;
mod conf;
mod metadata;
pub mod msrvs;
pub mod types;
pub use conf::{get_configuration_metadata, lookup_conf_file, Conf};
pub use metadata::ClippyConfiguration;

View File

@ -0,0 +1,116 @@
use std::fmt::{self, Write};
#[derive(Debug, Clone, Default)]
pub struct ClippyConfiguration {
pub name: String,
pub default: String,
pub lints: Vec<String>,
pub doc: String,
pub deprecation_reason: Option<&'static str>,
}
impl fmt::Display for ClippyConfiguration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "- `{}`: {}", self.name, self.doc)?;
if !self.default.is_empty() {
write!(f, " (default: `{}`)", self.default)?;
}
Ok(())
}
}
impl ClippyConfiguration {
pub fn new(
name: &'static str,
default: String,
doc_comment: &'static str,
deprecation_reason: Option<&'static str>,
) -> Self {
let (lints, doc) = parse_config_field_doc(doc_comment)
.unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
Self {
name: to_kebab(name),
lints,
doc,
default,
deprecation_reason,
}
}
pub fn to_markdown_paragraph(&self) -> String {
let mut out = format!(
"## `{}`\n{}\n\n",
self.name,
self.doc
.lines()
.map(|line| line.strip_prefix(" ").unwrap_or(line))
.collect::<Vec<_>>()
.join("\n"),
);
if !self.default.is_empty() {
write!(out, "**Default Value:** `{}`\n\n", self.default).unwrap();
}
write!(
out,
"---\n**Affected lints:**\n{}\n\n",
self.lints
.iter()
.map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
.map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
.collect::<Vec<_>>()
.join("\n"),
)
.unwrap();
out
}
pub fn to_markdown_link(&self) -> String {
const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html";
format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name)
}
}
/// This parses the field documentation of the config struct.
///
/// ```rust, ignore
/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
/// ```
///
/// Would yield:
/// ```rust, ignore
/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
/// ```
fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
const DOC_START: &str = " Lint: ";
if doc_comment.starts_with(DOC_START)
&& let Some(split_pos) = doc_comment.find('.')
{
let mut doc_comment = doc_comment.to_string();
let mut documentation = doc_comment.split_off(split_pos);
// Extract lints
doc_comment.make_ascii_lowercase();
let lints: Vec<String> = doc_comment
.split_off(DOC_START.len())
.split(", ")
.map(str::to_string)
.collect();
// Format documentation correctly
// split off leading `.` from lint name list and indent for correct formatting
documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
Some((lints, documentation))
} else {
None
}
}
/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
fn to_kebab(config_name: &str) -> String {
config_name.replace('_', "-")
}

View File

@ -1,10 +1,9 @@
use rustc_ast::Attribute;
use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::{sym, Symbol};
use serde::Deserialize;
use crate::attrs::get_unique_attr;
macro_rules! msrv_aliases {
($($major:literal,$minor:literal,$patch:literal {
$($name:ident),* $(,)?
@ -101,7 +100,16 @@ pub fn meets(&self, required: RustcVersion) -> bool {
}
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
let sym_msrv = Symbol::intern("msrv");
let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
if let Some(msrv_attr) = msrv_attrs.next() {
if let Some(duplicate) = msrv_attrs.last() {
sess.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
.span_note(msrv_attr.span, "first definition found here")
.emit();
}
if let Some(msrv) = msrv_attr.value_str() {
if let Ok(version) = RustcVersion::parse(msrv.as_str()) {
return Some(version);

View File

@ -0,0 +1,142 @@
use serde::de::{self, Deserializer, Visitor};
use serde::{ser, Deserialize, Serialize};
use std::fmt;
use std::hash::{Hash, Hasher};
#[derive(Clone, Debug, Deserialize)]
pub struct Rename {
pub path: String,
pub rename: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum DisallowedPath {
Simple(String),
WithReason { path: String, reason: Option<String> },
}
impl DisallowedPath {
pub fn path(&self) -> &str {
let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
path
}
pub fn reason(&self) -> Option<String> {
match self {
Self::WithReason {
reason: Some(reason), ..
} => Some(format!("{reason} (from clippy.toml)")),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum MatchLintBehaviour {
AllTypes,
WellKnownTypes,
Never,
}
#[derive(Clone, Debug)]
pub struct MacroMatcher {
pub name: String,
pub braces: (String, String),
}
impl Hash for MacroMatcher {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for MacroMatcher {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for MacroMatcher {}
impl<'de> Deserialize<'de> for MacroMatcher {
fn deserialize<D>(deser: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Name,
Brace,
}
struct MacVisitor;
impl<'de> Visitor<'de> for MacVisitor {
type Value = MacroMatcher;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("struct MacroMatcher")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mut name = None;
let mut brace: Option<String> = None;
while let Some(key) = map.next_key()? {
match key {
Field::Name => {
if name.is_some() {
return Err(de::Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
},
Field::Brace => {
if brace.is_some() {
return Err(de::Error::duplicate_field("brace"));
}
brace = Some(map.next_value()?);
},
}
}
let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?;
Ok(MacroMatcher {
name,
braces: [("(", ")"), ("{", "}"), ("[", "]")]
.into_iter()
.find(|b| b.0 == brace)
.map(|(o, c)| (o.to_owned(), c.to_owned()))
.ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
})
}
}
const FIELDS: &[&str] = &["name", "brace"];
deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor)
}
}
// these impls are never actually called but are used by the various config options that default to
// empty lists
macro_rules! unimplemented_serialize {
($($t:ty,)*) => {
$(
impl Serialize for $t {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
Err(ser::Error::custom("unimplemented"))
}
}
)*
}
}
unimplemented_serialize! {
DisallowedPath,
Rename,
MacroMatcher,
}

View File

@ -199,7 +199,6 @@ fn get_clap_config() -> ArgMatches {
"cargo",
"nursery",
"internal",
"internal_warn",
]),
Arg::new("type").long("type").help("What directory the lint belongs in"),
Arg::new("msrv")

View File

@ -346,11 +346,11 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String {
/// ### Why is this bad?
///
/// ### Example
/// ```rust
/// ```no_run
/// // example code where clippy issues a warning
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// // example code which does not raise clippy warning
/// ```
#[clippy::version = "{}"]

View File

@ -588,7 +588,7 @@ fn usable_lints(lints: &[Self]) -> Vec<Self> {
.collect()
}
/// Returns all internal lints (not `internal_warn` lints)
/// Returns all internal lints
#[must_use]
fn internal_lints(lints: &[Self]) -> Vec<Self> {
lints.iter().filter(|l| l.group == "internal").cloned().collect()

View File

@ -11,6 +11,7 @@ edition = "2021"
[dependencies]
arrayvec = { version = "0.7", default-features = false }
cargo_metadata = "0.15.3"
clippy_config = { path = "../clippy_config" }
clippy_utils = { path = "../clippy_utils" }
declare_clippy_lint = { path = "../declare_clippy_lint" }
if_chain = "1.0"
@ -32,9 +33,9 @@ url = "2.2"
walkdir = "2.3"
[features]
deny-warnings = ["clippy_utils/deny-warnings"]
deny-warnings = ["clippy_config/deny-warnings", "clippy_utils/deny-warnings"]
# build clippy with internal lints enabled, off by default
internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"]
internal = ["serde_json", "tempfile", "regex"]
[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)]

View File

@ -24,11 +24,11 @@
/// using absolute paths is the proper way of referencing items in one.
///
/// ### Example
/// ```rust
/// ```no_run
/// let x = std::f64::consts::PI;
/// ```
/// Use any of the below instead, or anything else:
/// ```rust
/// ```no_run
/// use std::f64;
/// use std::f64::consts;
/// use std::f64::consts::PI;

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{trim_span, walk_span_to_context};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
use rustc_errors::Applicability;
@ -17,11 +17,11 @@
/// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
///
/// ### Example
/// ```rust
/// ```no_run
/// let _ = 'a'..'z';
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let _ = 'a'..='z';
/// ```
#[clippy::version = "1.68.0"]
@ -82,33 +82,20 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg
(
Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
)
| (
) | (
Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
)
| (
) | (
Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
)
)
&& !in_external_macro(cx.sess(), span)
{
span_lint_and_then(
cx,
ALMOST_COMPLETE_RANGE,
span,
"almost complete ascii range",
|diag| {
if let Some((span, sugg)) = sugg {
diag.span_suggestion(
span,
"use an inclusive range",
sugg,
Applicability::MaybeIncorrect,
);
}
span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| {
if let Some((span, sugg)) = sugg {
diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect);
}
);
});
}
}

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@ -24,12 +24,12 @@
/// issue](https://github.com/rust-lang/rust/issues).
///
/// ### Example
/// ```rust
/// ```no_run
/// let x = 3.14;
/// let y = 1_f64 / x;
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let x = std::f32::consts::PI;
/// let y = std::f64::consts::FRAC_1_PI;
/// ```

View File

@ -18,7 +18,7 @@
/// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::cell::RefCell;
/// # use std::sync::Arc;
///
@ -62,19 +62,21 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
ARC_WITH_NON_SEND_SYNC,
expr.span,
"usage of an `Arc` that is not `Send` or `Sync`",
|diag| with_forced_trimmed_paths!({
if !is_send {
diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`"));
}
if !is_sync {
diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`"));
}
|diag| {
with_forced_trimmed_paths!({
if !is_send {
diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`"));
}
if !is_sync {
diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`"));
}
diag.note(format!("required for `{ty}` to implement `Send` and `Sync`"));
diag.note(format!("required for `{ty}` to implement `Send` and `Sync`"));
diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`");
}
));
diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`");
});
},
);
}
}
}

View File

@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
return;
}
}
let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""};
let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
let mut app = Applicability::MachineApplicable;
match method_segment.ident.as_str() {
"is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
@ -74,7 +74,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
),
app,
);
}
},
"is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
span_lint_and_sugg(
cx,
@ -88,7 +88,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
),
app,
);
}
},
_ => (),
};
}

View File

@ -2,7 +2,7 @@
use clippy_utils::source::snippet;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath};
use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -15,7 +15,7 @@
/// An await is likely missing.
///
/// ### Example
/// ```rust
/// ```no_run
/// async fn foo() {}
///
/// fn bar() {
@ -26,7 +26,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// async fn foo() {}
///
/// fn bar() {

View File

@ -1,9 +1,9 @@
//! checks for attributes
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_from_proc_macro;
use clippy_utils::macros::{is_panic, macro_backtrace};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
use if_chain::if_chain;
use rustc_ast::token::{Token, TokenKind};
@ -129,7 +129,7 @@
/// a valid semver. Failing that, the contained information is useless.
///
/// ### Example
/// ```rust
/// ```no_run
/// #[deprecated(since = "forever")]
/// fn something_else() { /* ... */ }
/// ```
@ -156,14 +156,14 @@
/// currently works for basic cases but is not perfect.
///
/// ### Example
/// ```rust
/// ```no_run
/// #[allow(dead_code)]
///
/// fn not_quite_good_code() { }
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// // Good (as inner attribute)
/// #![allow(dead_code)]
///
@ -198,25 +198,25 @@
/// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`).
///
/// ### Example
/// ```rust
/// ```no_run
/// /// Some doc comment with a blank line after it.
///
/// fn not_quite_good_code() { }
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// /// Good (no blank line)
/// fn this_is_fine() { }
/// ```
///
/// ```rust
/// ```no_run
/// // Good (convert to a regular comment)
///
/// fn this_is_fine_too() { }
/// ```
///
/// ```rust
/// ```no_run
/// //! Good (convert to a comment on an inner attribute)
///
/// fn this_is_fine_as_well() { }
@ -236,12 +236,12 @@
/// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
///
/// ### Example
/// ```rust
/// ```no_run
/// #![deny(clippy::restriction)]
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #![deny(clippy::as_conversions)]
/// ```
#[clippy::version = "1.47.0"]
@ -265,13 +265,13 @@
/// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
///
/// ### Example
/// ```rust
/// ```no_run
/// #[cfg_attr(rustfmt, rustfmt_skip)]
/// fn main() { }
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #[rustfmt::skip]
/// fn main() { }
/// ```
@ -290,13 +290,13 @@
/// by the conditional compilation engine.
///
/// ### Example
/// ```rust
/// ```no_run
/// #[cfg(linux)]
/// fn conditional() { }
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # mod hidden {
/// #[cfg(target_os = "linux")]
/// fn conditional() { }
@ -325,14 +325,14 @@
/// ensure that others understand the reasoning
///
/// ### Example
/// ```rust
/// ```no_run
/// #![feature(lint_reasons)]
///
/// #![allow(clippy::some_lint)]
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #![feature(lint_reasons)]
///
/// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
@ -352,7 +352,7 @@
/// panicking with the expected message, and not another unrelated panic.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn random() -> i32 { 0 }
///
/// #[should_panic]
@ -363,7 +363,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// fn random() -> i32 { 0 }
///
/// #[should_panic = "attempt to divide by zero"]
@ -386,13 +386,13 @@
/// If there is only one condition, no need to wrap it into `any` or `all` combinators.
///
/// ### Example
/// ```rust
/// ```no_run
/// #[cfg(any(unix))]
/// pub struct Bar;
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #[cfg(unix)]
/// pub struct Bar;
/// ```
@ -409,16 +409,16 @@
///
/// ### Why is this bad?
/// Misspelling `feature` as `features` can be sometimes hard to spot. It
/// may cause conditional compilation not work quitely.
/// may cause conditional compilation not work quietly.
///
/// ### Example
/// ```rust
/// ```no_run
/// #[cfg(features = "some-feature")]
/// fn conditional() { }
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #[cfg(feature = "some-feature")]
/// fn conditional() { }
/// ```
@ -602,9 +602,26 @@ fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) {
if let AttrArgs::Delimited(args) = &normal_attr.item.args
&& let mut tt_iter = args.tokens.trees()
&& let Some(TokenTree::Token(Token { kind: TokenKind::Ident(sym::expected, _), .. }, _)) = tt_iter.next()
&& let Some(TokenTree::Token(Token { kind: TokenKind::Eq, .. }, _)) = tt_iter.next()
&& let Some(TokenTree::Token(Token { kind: TokenKind::Literal(_), .. }, _)) = tt_iter.next()
&& let Some(TokenTree::Token(
Token {
kind: TokenKind::Ident(sym::expected, _),
..
},
_,
)) = tt_iter.next()
&& let Some(TokenTree::Token(
Token {
kind: TokenKind::Eq, ..
},
_,
)) = tt_iter.next()
&& let Some(TokenTree::Token(
Token {
kind: TokenKind::Literal(_),
..
},
_,
)) = tt_iter.next()
{
// `#[should_panic(expected = "..")]` found, good
return;
@ -914,7 +931,9 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
for item in items {
if let NestedMetaItem::MetaItem(meta) = item {
if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() {
if meta.has_name(sym!(features))
&& let Some(val) = meta.value_str()
{
span_lint_and_sugg(
cx,
MAYBE_MISUSED_CFG,
@ -933,16 +952,16 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
}
fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
if attr.has_name(sym::cfg) &&
let Some(items) = attr.meta_item_list()
if attr.has_name(sym::cfg)
&& let Some(items) = attr.meta_item_list()
{
check_nested_cfg(cx, &items);
}
}
fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) {
if attr.has_name(sym::cfg) &&
let Some(items) = attr.meta_item_list()
if attr.has_name(sym::cfg)
&& let Some(items) = attr.meta_item_list()
{
check_nested_misused_cfg(cx, &items);
}

View File

@ -1,15 +1,14 @@
use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_hir::{CoroutineSource, Body, CoroutineKind};
use rustc_hir::{Body, CoroutineKind, CoroutineSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::CoroutineLayout;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use crate::utils::conf::DisallowedPath;
declare_clippy_lint! {
/// ### What it does
/// Checks for calls to await while holding a non-async-aware MutexGuard.
@ -29,7 +28,7 @@
/// to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::sync::Mutex;
/// # async fn baz() {}
/// async fn foo(x: &Mutex<u32>) {
@ -47,7 +46,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::sync::Mutex;
/// # async fn baz() {}
/// async fn foo(x: &Mutex<u32>) {
@ -87,7 +86,7 @@
/// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::cell::RefCell;
/// # async fn baz() {}
/// async fn foo(x: &RefCell<u32>) {
@ -105,7 +104,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::cell::RefCell;
/// # async fn baz() {}
/// async fn foo(x: &RefCell<u32>) {
@ -151,7 +150,7 @@
/// ]
/// ```
///
/// ```rust
/// ```no_run
/// # async fn baz() {}
/// struct CustomLockType;
/// struct OtherCustomLockType;

View File

@ -21,7 +21,7 @@
/// Style, using blocks in the condition makes it hard to read.
///
/// ### Examples
/// ```rust
/// ```no_run
/// # fn somefunc() -> bool { true };
/// if { true } { /* ... */ }
///
@ -29,7 +29,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # fn somefunc() -> bool { true };
/// if true { /* ... */ }
///

View File

@ -18,13 +18,13 @@
/// It is shorter to use the equivalent.
///
/// ### Example
/// ```rust
/// ```no_run
/// assert_eq!("a".is_empty(), false);
/// assert_ne!("a".is_empty(), true);
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// assert!(!"a".is_empty());
/// ```
#[clippy::version = "1.53.0"]

View File

@ -21,7 +21,7 @@
/// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
///
/// ### Example
/// ```rust
/// ```no_run
/// # let condition = false;
/// if condition {
/// 1_i64
@ -30,12 +30,12 @@
/// };
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # let condition = false;
/// i64::from(condition);
/// ```
/// or
/// ```rust
/// ```no_run
/// # let condition = false;
/// condition as i64;
/// ```
@ -55,7 +55,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
}
fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr)
if let Some(If {
cond,
then,
r#else: Some(r#else),
}) = If::hir(expr)
&& let Some(then_lit) = int_literal(then)
&& let Some(else_lit) = int_literal(r#else)
{
@ -90,19 +94,18 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>
let into_snippet = snippet.clone().maybe_par();
let as_snippet = snippet.as_ty(ty);
span_lint_and_then(cx,
span_lint_and_then(
cx,
BOOL_TO_INT_WITH_IF,
expr.span,
"boolean to int conversion using if",
|diag| {
diag.span_suggestion(
expr.span,
"replace with from",
suggestion,
applicability,
);
diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options"));
});
diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
diag.note(format!(
"`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
));
},
);
};
}
@ -110,7 +113,7 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>
fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
if let ExprKind::Block(block, _) = expr.kind
&& let Block {
stmts: [], // Shouldn't lint if statements with side effects
stmts: [], // Shouldn't lint if statements with side effects
expr: Some(expr),
..
} = block

View File

@ -472,8 +472,9 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
self.bool_expr(e);
},
ExprKind::Unary(UnOp::Not, inner) => {
if let ExprKind::Unary(UnOp::Not, ex) = inner.kind &&
!self.cx.typeck_results().node_types()[ex.hir_id].is_bool() {
if let ExprKind::Unary(UnOp::Not, ex) = inner.kind
&& !self.cx.typeck_results().node_types()[ex.hir_id].is_bool()
{
return;
}
if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
@ -500,10 +501,10 @@ struct NotSimplificationVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind &&
!inner.span.from_expansion() &&
let Some(suggestion) = simplify_not(self.cx, inner)
&& self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind
&& !inner.span.from_expansion()
&& let Some(suggestion) = simplify_not(self.cx, inner)
&& self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
{
span_lint_and_sugg(
self.cx,

View File

@ -19,7 +19,7 @@
///
/// ### Known problems
/// False negative on such code:
/// ```
/// ```no_run
/// let x = &12;
/// let addr_x = &x as *const _ as usize;
/// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.
@ -28,14 +28,14 @@
/// ```
///
/// ### Example
/// ```rust
/// ```no_run
/// let s = &String::new();
///
/// let a: &String = &* s;
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # let s = &String::new();
/// let a: &String = s;
/// ```

View File

@ -24,11 +24,11 @@
/// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
///
/// ### Example
/// ```rust
/// ```no_run
/// let x: Box<String> = Box::new(Default::default());
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let x: Box<String> = Box::default();
/// ```
#[clippy::version = "1.66.0"]
@ -61,9 +61,9 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
} else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
} else {
return
return;
},
Applicability::MachineApplicable
Applicability::MachineApplicable,
);
}
}
@ -110,7 +110,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
Node::Expr(Expr {
kind: ExprKind::Call(path, args),
..
}) | Node::Block(Block {
})
| Node::Block(Block {
expr:
Some(Expr {
kind: ExprKind::Call(path, args),
@ -119,10 +120,10 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
..
}),
) => {
if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
let Some(sig) = expr_sig(cx, path) &&
let Some(input) = sig.input(index) &&
!cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
&& let Some(sig) = expr_sig(cx, path)
&& let Some(input) = sig.input(index)
&& !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
{
input.no_bound_vars().is_some()
} else {

View File

@ -9,12 +9,19 @@
use super::AS_PTR_CAST_MUT;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind()
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) =
cx.typeck_results().node_type(cast_expr.hir_id).kind()
if let ty::RawPtr(
ptrty @ TypeAndMut {
mutbl: Mutability::Mut, ..
},
) = cast_to.kind()
&& let ty::RawPtr(TypeAndMut {
mutbl: Mutability::Not, ..
}) = cx.typeck_results().node_type(cast_expr.hir_id).kind()
&& let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
&& method_name.ident.name == rustc_span::sym::as_ptr
&& let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
&& let Some(as_ptr_did) = cx
.typeck_results()
.type_dependent_def_id(cast_expr.peel_blocks().hir_id)
&& let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity()
&& let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
&& let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
@ -30,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
&format!("casting the result of `as_ptr` to *{ptrty}"),
"replace with",
format!("{recv}.as_mut_ptr()"),
applicability
applicability,
);
}
}

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};

View File

@ -1,6 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_constant;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_isize_or_usize;
use rustc_errors::Applicability;

View File

@ -26,8 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
// There probably is no obvious reason to do this, just to be consistent with `as` cases.
&& !is_hir_ty_cfg_dependant(cx, cast_to)
{
let (cast_from, cast_to) =
(cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
}
}
@ -81,9 +80,9 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
cx.tcx.get_diagnostic_name(def_id),
Some(
sym::ptr_write_unaligned
| sym::ptr_read_unaligned
| sym::intrinsics_unaligned_volatile_load
| sym::intrinsics_unaligned_volatile_store
| sym::ptr_read_unaligned
| sym::intrinsics_unaligned_volatile_load
| sym::intrinsics_unaligned_volatile_store
)
)
{

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source;
use if_chain::if_chain;
use rustc_ast::Mutability;

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use if_chain::if_chain;
use rustc_errors::Applicability;

View File

@ -22,8 +22,8 @@
mod utils;
mod zero_ptr;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::is_hir_ty_cfg_dependant;
use clippy_utils::msrvs::{self, Msrv};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@ -45,7 +45,7 @@
/// those places in the code.
///
/// ### Example
/// ```rust
/// ```no_run
/// let x = u64::MAX;
/// x as f64;
/// ```
@ -67,7 +67,7 @@
/// as a one-time check to see where numerical wrapping can arise.
///
/// ### Example
/// ```rust
/// ```no_run
/// let y: i8 = -1;
/// y as u128; // will return 18446744073709551615
/// ```
@ -90,13 +90,13 @@
/// checks could be beneficial.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn as_u8(x: u64) -> u8 {
/// x as u8
/// }
/// ```
/// Use instead:
/// ```
/// ```no_run
/// fn as_u8(x: u64) -> u8 {
/// if let Ok(x) = u8::try_from(x) {
/// x
@ -132,7 +132,7 @@
/// example below.
///
/// ### Example
/// ```rust
/// ```no_run
/// u32::MAX as i32; // will yield a value of `-1`
/// ```
#[clippy::version = "pre 1.29.0"]
@ -155,7 +155,7 @@
/// people reading the code to know that the conversion is lossless.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn as_u64(x: u8) -> u64 {
/// x as u64
/// }
@ -163,7 +163,7 @@
///
/// Using `::from` would look like this:
///
/// ```rust
/// ```no_run
/// fn as_u64(x: u8) -> u64 {
/// u64::from(x)
/// }
@ -191,14 +191,14 @@
/// intermediate references, raw pointers and trait objects may or may not work.
///
/// ### Example
/// ```rust
/// ```no_run
/// let _ = 2i32 as i32;
/// let _ = 0.5 as f32;
/// ```
///
/// Better:
///
/// ```rust
/// ```no_run
/// let _ = 2_i32;
/// let _ = 0.5_f32;
/// ```
@ -223,7 +223,7 @@
/// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
///
/// ### Example
/// ```rust
/// ```no_run
/// let _ = (&1u8 as *const u8) as *const u16;
/// let _ = (&mut 1u8 as *mut u8) as *mut u16;
///
@ -249,13 +249,13 @@
/// Casting to isize also doesn't make sense since there are no signed addresses.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn fun() -> i32 { 1 }
/// let _ = fun as i64;
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # fn fun() -> i32 { 1 }
/// let _ = fun as usize;
/// ```
@ -276,7 +276,7 @@
/// a comment) to perform the truncation.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn fn1() -> i16 {
/// 1
/// };
@ -284,7 +284,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// // Cast to usize first, then comment with the reason for the truncation
/// fn fn1() -> i16 {
/// 1
@ -310,7 +310,7 @@
/// pointer casts in your code.
///
/// ### Example
/// ```rust
/// ```no_run
/// // fn1 is cast as `usize`
/// fn fn1() -> u16 {
/// 1
@ -319,7 +319,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// // maybe you intended to call the function?
/// fn fn2() -> u16 {
/// 1
@ -378,14 +378,14 @@
/// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
///
/// ### Example
/// ```rust
/// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr: *mut u32 = &mut 42_u32;
/// let _ = ptr as *const i32;
/// let _ = mut_ptr as *mut i32;
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr: *mut u32 = &mut 42_u32;
/// let _ = ptr.cast::<i32>();
@ -408,13 +408,13 @@
/// type.
///
/// ### Example
/// ```rust
/// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr = ptr as *mut u32;
/// let ptr = mut_ptr as *const u32;
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr = ptr.cast_mut();
/// let ptr = mut_ptr.cast_const();
@ -434,7 +434,7 @@
/// The resulting integral value will not match the value of the variant it came from.
///
/// ### Example
/// ```rust
/// ```no_run
/// enum E { X = 256 };
/// let _ = E::X as u8;
/// ```
@ -457,7 +457,7 @@
///
/// ### Example
/// // Missing data
/// ```rust
/// ```no_run
/// let a = [1_i32, 2, 3, 4];
/// let p = &a as *const [i32] as *const [u8];
/// unsafe {
@ -465,7 +465,7 @@
/// }
/// ```
/// // Undefined Behavior (note: also potential alignment issues)
/// ```rust
/// ```no_run
/// let a = [1_u8, 2, 3, 4];
/// let p = &a as *const [u8] as *const [u32];
/// unsafe {
@ -473,7 +473,7 @@
/// }
/// ```
/// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
/// ```rust
/// ```no_run
/// let a = [1_i32, 2, 3, 4];
/// let old_ptr = &a as *const [i32];
/// // The data pointer is cast to a pointer to the target `u8` not `[u8]`
@ -497,7 +497,7 @@
/// The cast is easily confused with casting a c-like enum value to an integer.
///
/// ### Example
/// ```rust
/// ```no_run
/// enum E { X(i32) };
/// let _ = E::X as usize;
/// ```
@ -515,12 +515,12 @@
/// The `unsigned_abs()` method avoids panic when called on the MIN value.
///
/// ### Example
/// ```rust
/// ```no_run
/// let x: i32 = -42;
/// let y: u32 = x.abs() as u32;
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let x: i32 = -42;
/// let y: u32 = x.unsigned_abs();
/// ```
@ -541,13 +541,13 @@
/// The lint is allowed by default as using `_` is less wordy than always specifying the type.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn foo(n: usize) {}
/// let n: u16 = 256;
/// foo(n as _);
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// fn foo(n: usize) {}
/// let n: u16 = 256;
/// foo(n as usize);
@ -570,7 +570,7 @@
/// Read the `ptr::addr_of` docs for more information.
///
/// ### Example
/// ```rust
/// ```no_run
/// let val = 1;
/// let p = &val as *const i32;
///
@ -578,7 +578,7 @@
/// let p_mut = &mut val_mut as *mut i32;
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let val = 1;
/// let p = std::ptr::addr_of!(val);
///
@ -627,13 +627,13 @@
/// mutability is used, making it unlikely that having it as a mutable pointer is correct.
///
/// ### Example
/// ```rust
/// ```no_run
/// let mut vec = Vec::<u8>::with_capacity(1);
/// let ptr = vec.as_ptr() as *mut u8;
/// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let mut vec = Vec::<u8>::with_capacity(1);
/// let ptr = vec.as_mut_ptr();
/// unsafe { ptr.write(4) };
@ -675,12 +675,12 @@
/// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
///
/// ### Example
/// ```rust
/// ```no_run
/// let a = 0 as *const u32;
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let a = std::ptr::null::<u32>();
/// ```
#[clippy::version = "pre 1.29.0"]

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
msrv: &Msrv,
) {
if_chain! {
if msrv.meets(POINTER_CAST_CONSTNESS);
if msrv.meets(msrvs::POINTER_CAST_CONSTNESS);
if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind();
if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind();
if matches!((from_mutbl, to_mutbl),

View File

@ -97,7 +97,9 @@ pub(super) fn check<'tcx>(
}
// skip cast of fn call that returns type alias
if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
if let ExprKind::Cast(inner, ..) = expr.kind
&& is_cast_from_ty_alias(cx, inner, cast_from)
{
return false;
}
@ -189,11 +191,10 @@ fn lint_unnecessary_cast(
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let ExprKind::MethodCall(..) = parent_expr.kind
&& literal_str.starts_with('-')
{
format!("({literal_str}_{cast_to})")
} else {
format!("{literal_str}_{cast_to}")
{
format!("({literal_str}_{cast_to})")
} else {
format!("{literal_str}_{cast_to}")
};
span_lint_and_sugg(
@ -269,7 +270,9 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
&& let Some(parent) = get_parent_node(cx.tcx, hir_id)
&& let Node::Local(l) = parent
{
if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) {
if let Some(e) = l.init
&& is_cast_from_ty_alias(cx, e, cast_from)
{
return ControlFlow::Break::<()>(());
}

View File

@ -1,7 +1,7 @@
//! lint on manually implemented checked conversions that could be transformed into `try_from`
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
use if_chain::if_chain;
@ -19,13 +19,13 @@
/// Reduces the readability of statements & is error prone.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let foo: u32 = 5;
/// foo <= i32::MAX as u32;
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # let foo = 1;
/// # #[allow(unused)]
/// i32::try_from(foo).is_ok();

View File

@ -32,7 +32,7 @@
/// makes code look more complex than it really is.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let (x, y) = (true, true);
/// if x {
/// if y {
@ -42,7 +42,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # let (x, y) = (true, true);
/// if x && y {
/// // …

View File

@ -20,7 +20,7 @@
/// instead.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let samples = vec![3, 1, 2];
/// let mut sorted_samples = samples.clone();
/// sorted_samples.sort();
@ -29,7 +29,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # let samples = vec![3, 1, 2];
/// let mut sorted_samples = samples.clone();
/// sorted_samples.sort();

View File

@ -18,7 +18,7 @@
/// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
///
/// ### Example
/// ```rust
/// ```no_run
/// #[macro_export]
/// macro_rules! print_message {
/// () => {
@ -28,7 +28,7 @@
/// pub const MESSAGE: &str = "Hello!";
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// #[macro_export]
/// macro_rules! print_message {
/// () => {

View File

@ -6,8 +6,6 @@
#[cfg(feature = "internal")]
crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
@ -30,6 +28,8 @@
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
@ -37,6 +37,8 @@
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO,
crate::absolute_paths::ABSOLUTE_PATHS_INFO,
crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
@ -272,6 +274,7 @@
crate::loops::NEVER_LOOP_INFO,
crate::loops::SAME_ITEM_PUSH_INFO,
crate::loops::SINGLE_ELEMENT_LOOP_INFO,
crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
crate::loops::WHILE_LET_LOOP_INFO,
crate::loops::WHILE_LET_ON_ITERATOR_INFO,
@ -428,6 +431,7 @@
crate::methods::TYPE_ID_ON_BOX_INFO,
crate::methods::UNINIT_ASSUMED_INIT_INFO,
crate::methods::UNIT_HASH_INFO,
crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO,
crate::methods::UNNECESSARY_FILTER_MAP_INFO,
crate::methods::UNNECESSARY_FIND_MAP_INFO,
crate::methods::UNNECESSARY_FOLD_INFO,
@ -441,6 +445,7 @@
crate::methods::USELESS_ASREF_INFO,
crate::methods::VEC_RESIZE_TO_ZERO_INFO,
crate::methods::VERBOSE_FILE_READS_INFO,
crate::methods::WAKER_CLONE_WAKE_INFO,
crate::methods::WRONG_SELF_CONVENTION_INFO,
crate::methods::ZST_OFFSET_INFO,
crate::min_ident_chars::MIN_IDENT_CHARS_INFO,

View File

@ -23,12 +23,12 @@
/// generic `Default`.
///
/// ### Example
/// ```rust
/// ```no_run
/// let s: String = Default::default();
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let s = String::default();
/// ```
#[clippy::version = "pre 1.29.0"]
@ -49,7 +49,7 @@
/// Assignments to patterns that are of tuple type are not linted.
///
/// ### Example
/// ```
/// ```no_run
/// # #[derive(Default)]
/// # struct A { i: i32 }
/// let mut a: A = Default::default();
@ -57,7 +57,7 @@
/// ```
///
/// Use instead:
/// ```
/// ```no_run
/// # #[derive(Default)]
/// # struct A { i: i32 }
/// let a = A {

View File

@ -17,7 +17,7 @@
/// This adds code complexity and an unnecessary function call.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::marker::PhantomData;
/// #[derive(Default)]
/// struct S<T> {
@ -29,7 +29,7 @@
/// };
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::marker::PhantomData;
/// struct S<T> {
/// _marker: PhantomData<T>

View File

@ -14,12 +14,12 @@
/// ### Why is this bad?
/// `std::iter::empty()` is the more idiomatic way.
/// ### Example
/// ```rust
/// ```no_run
/// let _ = std::iter::Empty::<usize>::default();
/// let iter: std::iter::Empty<usize> = std::iter::Empty::default();
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let _ = std::iter::empty::<usize>();
/// let iter: std::iter::Empty<usize> = std::iter::empty();
/// ```
@ -68,7 +68,10 @@ fn make_sugg(
_ => None,
})
{
format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0)
format!(
"std::iter::empty::<{}>()",
snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0
)
} else {
"std::iter::empty()".to_owned()
}

View File

@ -31,13 +31,13 @@
/// This lint can only be allowed at the function level or above.
///
/// ### Example
/// ```rust
/// ```no_run
/// let i = 10;
/// let f = 1.23;
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let i = 10i32;
/// let f = 1.23f64;
/// ```

View File

@ -17,7 +17,7 @@
/// specified layout. These cases may lead to undefined behavior in unsafe blocks.
///
/// ### Example
/// ```rust
/// ```no_run
/// union Foo {
/// a: i32,
/// b: u32,
@ -30,7 +30,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// #[repr(C)]
/// union Foo {
/// a: i32,

View File

@ -29,14 +29,14 @@
/// when not part of a method chain.
///
/// ### Example
/// ```rust
/// ```no_run
/// use std::ops::Deref;
/// let a: &mut String = &mut String::from("foo");
/// let b: &str = a.deref();
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let a: &mut String = &mut String::from("foo");
/// let b = &*a;
/// ```
@ -68,7 +68,7 @@
/// in such a case can change the semantics of the code.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn fun(_a: &i32) {}
///
/// let x: &i32 = &&&&&&5;
@ -76,7 +76,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # fn fun(_a: &i32) {}
/// let x: &i32 = &5;
/// fun(x);
@ -95,7 +95,7 @@
/// The address-of operator at the use site is clearer about the need for a reference.
///
/// ### Example
/// ```rust
/// ```no_run
/// let x = Some("");
/// if let Some(ref x) = x {
/// // use `x` here
@ -103,7 +103,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let x = Some("");
/// if let Some(x) = x {
/// // use `&x` here
@ -123,12 +123,12 @@
/// This unnecessarily complicates the code.
///
/// ### Example
/// ```rust
/// ```no_run
/// let x = String::new();
/// let y: &str = &*x;
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let x = String::new();
/// let y: &str = &x;
/// ```
@ -353,23 +353,26 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// priority.
if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
&& let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
&& let arg_ty
= cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
&& let arg_ty = cx
.tcx
.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
&& let args = cx
.typeck_results()
.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
&& let impl_ty = if cx.tcx.fn_sig(fn_id)
.instantiate_identity()
.skip_binder()
.inputs()[0].is_ref()
{
// Trait methods taking `&self`
sub_ty
} else {
// Trait methods taking `self`
arg_ty
} && impl_ty.is_ref()
.node_args_opt(hir_id)
.map(|args| &args[1..])
.unwrap_or_default()
&& let impl_ty =
if cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder().inputs()[0]
.is_ref()
{
// Trait methods taking `&self`
sub_ty
} else {
// Trait methods taking `self`
arg_ty
}
&& impl_ty.is_ref()
&& implements_trait(
cx,
impl_ty,
@ -414,9 +417,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let (required_refs, msg) = if can_auto_borrow {
(1, if deref_count == 1 { borrow_msg } else { deref_msg })
} else if let Some(&Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
..
}) = next_adjust
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
..
}) = next_adjust
&& matches!(mutability, AutoBorrowMutability::Mut { .. })
&& !stability.is_reborrow_stable()
{
@ -705,9 +708,11 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
{
match parent.kind {
ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _)
if child.hir_id == e.hir_id => true,
ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar)
| ExprKind::Field(_, _) => true,
if child.hir_id == e.hir_id =>
{
true
},
ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) | ExprKind::Field(_, _) => true,
_ => false,
}
} else {

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::indent_of;
use clippy_utils::{is_default_equivalent, peel_blocks};
use rustc_errors::Applicability;
@ -21,7 +21,7 @@
/// It is less concise.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Foo {
/// bar: bool
/// }
@ -36,7 +36,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #[derive(Default)]
/// struct Foo {
/// bar: bool

View File

@ -173,7 +173,7 @@
/// `Eq` themselves.
///
/// ### Example
/// ```rust
/// ```no_run
/// #[derive(PartialEq)]
/// struct Foo {
/// i_am_eq: i32,
@ -181,7 +181,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// #[derive(PartialEq, Eq)]
/// struct Foo {
/// i_am_eq: i32,

View File

@ -1,3 +1,4 @@
use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::macro_backtrace;
use rustc_ast::Attribute;
@ -8,8 +9,6 @@
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{ExpnId, Span};
use crate::utils::conf;
declare_clippy_lint! {
/// ### What it does
/// Denies the configured macros in clippy.toml
@ -35,7 +34,7 @@
/// { path = "serde::Serialize", reason = "no serializing" },
/// ]
/// ```
/// ```
/// ```no_run
/// use serde::Serialize;
///
/// // Example code where clippy issues a warning
@ -55,13 +54,13 @@
}
pub struct DisallowedMacros {
conf_disallowed: Vec<conf::DisallowedPath>,
conf_disallowed: Vec<DisallowedPath>,
disallowed: DefIdMap<usize>,
seen: FxHashSet<ExpnId>,
}
impl DisallowedMacros {
pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
Self {
conf_disallowed,
disallowed: DefIdMap::default(),

View File

@ -1,13 +1,11 @@
use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use crate::utils::conf;
declare_clippy_lint! {
/// ### What it does
/// Denies the configured methods and functions in clippy.toml
@ -59,12 +57,12 @@
#[derive(Clone, Debug)]
pub struct DisallowedMethods {
conf_disallowed: Vec<conf::DisallowedPath>,
conf_disallowed: Vec<DisallowedPath>,
disallowed: DefIdMap<usize>,
}
impl DisallowedMethods {
pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
Self {
conf_disallowed,
disallowed: DefIdMap::default(),

View File

@ -15,7 +15,7 @@
/// avoided.
///
/// ### Example
/// ```rust
/// ```no_run
/// let foo = 3.14;
/// ```
#[clippy::version = "pre 1.29.0"]

View File

@ -30,7 +30,7 @@
/// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents
///
/// ### Example
/// ```rust
/// ```no_run
/// // Assuming that `clippy.toml` contains the following line:
/// // allowed-scripts = ["Latin", "Cyrillic"]
/// let counter = 10; // OK, latin is allowed.

View File

@ -1,5 +1,5 @@
use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
@ -8,8 +8,6 @@
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
use crate::utils::conf;
declare_clippy_lint! {
/// ### What it does
/// Denies the configured types in clippy.toml.
@ -50,15 +48,16 @@
style,
"use of disallowed types"
}
#[derive(Clone, Debug)]
pub struct DisallowedTypes {
conf_disallowed: Vec<conf::DisallowedPath>,
conf_disallowed: Vec<DisallowedPath>,
def_ids: FxHashMap<DefId, usize>,
prim_tys: FxHashMap<PrimTy, usize>,
}
impl DisallowedTypes {
pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
Self {
conf_disallowed,
def_ids: FxHashMap::default(),
@ -123,7 +122,7 @@ fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTrait
}
}
fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) {
span_lint_and_then(
cx,
DISALLOWED_TYPES,

View File

@ -58,14 +58,14 @@
/// would fail.
///
/// ### Examples
/// ```rust
/// ```no_run
/// /// Do something with the foo_bar parameter. See also
/// /// that::other::module::foo.
/// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
/// fn doit(foo_bar: usize) {}
/// ```
///
/// ```rust
/// ```no_run
/// // Link text with `[]` brackets should be written as following:
/// /// Consume the array and return the inner
/// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
@ -88,7 +88,7 @@
/// preconditions, so that users can be sure they are using them safely.
///
/// ### Examples
/// ```rust
/// ```no_run
///# type Universe = ();
/// /// This function should really be documented
/// pub unsafe fn start_apocalypse(u: &mut Universe) {
@ -98,7 +98,7 @@
///
/// At least write a line about safety:
///
/// ```rust
/// ```no_run
///# type Universe = ();
/// /// # Safety
/// ///
@ -126,7 +126,7 @@
/// Since the following function returns a `Result` it has an `# Errors` section in
/// its doc comment:
///
/// ```rust
/// ```no_run
///# use std::io;
/// /// # Errors
/// ///
@ -155,7 +155,7 @@
/// Since the following function may panic it has a `# Panics` section in
/// its doc comment:
///
/// ```rust
/// ```no_run
/// /// # Panics
/// ///
/// /// Will panic if y is 0
@ -182,7 +182,7 @@
/// if the `fn main()` is left implicit.
///
/// ### Examples
/// ```rust
/// ```no_run
/// /// An example of a doctest with a `main()` function
/// ///
/// /// # Examples
@ -210,12 +210,12 @@
/// It is likely a typo when defining an intra-doc link
///
/// ### Example
/// ```rust
/// ```no_run
/// /// See also: ['foo']
/// fn bar() {}
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// /// See also: [`foo`]
/// fn bar() {}
/// ```
@ -235,7 +235,7 @@
/// need to describe safety preconditions that users are required to uphold.
///
/// ### Examples
/// ```rust
/// ```no_run
///# type Universe = ();
/// /// # Safety
/// ///
@ -248,7 +248,7 @@
/// The function is safe, so there shouldn't be any preconditions
/// that have to be explained for safety reasons.
///
/// ```rust
/// ```no_run
///# type Universe = ();
/// /// This function should really be documented
/// pub fn start_apocalypse(u: &mut Universe) {
@ -569,9 +569,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
if let End(Heading(_, _, _)) = event {
in_heading = false;
}
if ticks_unbalanced
&& let Some(span) = fragments.span(cx, paragraph_range.clone())
{
if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) {
span_lint_and_help(
cx,
DOC_MARKDOWN,
@ -617,8 +615,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
check_link_quotes(cx, trimmed_text, range.clone(), fragments);
}
if let Some(link) = in_link.as_ref()
&& let Ok(url) = Url::parse(link)
&& (url.scheme() == "https" || url.scheme() == "http") {
&& let Ok(url) = Url::parse(link)
&& (url.scheme() == "https" || url.scheme() == "http")
{
// Don't check the text associated with external URLs
continue;
}
@ -716,7 +715,9 @@ fn has_needless_main(code: String, edition: Edition) -> bool {
// Because of the global session, we need to create a new session in a different thread with
// the edition we need.
let text = text.to_owned();
if thread::spawn(move || has_needless_main(text, edition)).join().expect("thread::spawn failed")
if thread::spawn(move || has_needless_main(text, edition))
.join()
.expect("thread::spawn failed")
&& let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
{
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
@ -756,11 +757,12 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str
}
fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
/// Checks if a string is camel-case, i.e., contains at least two uppercase
/// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
/// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
/// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
/// letter (`NASA` is ok).
/// Plurals are also excluded (`IDs` is ok).
fn is_camel_case(s: &str) -> bool {
if s.starts_with(|c: char| c.is_ascii_digit()) {
if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) {
return false;
}

View File

@ -12,7 +12,7 @@
/// mistake.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn simple_double_parens() -> i32 {
/// ((0))
/// }
@ -22,7 +22,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// fn simple_no_parens() -> i32 {
/// 0
/// }

View File

@ -16,7 +16,7 @@
/// have been intended.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Foo;
/// let x = Foo;
/// std::mem::drop(x);
@ -36,7 +36,7 @@
/// have been intended.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Foo;
/// let x = Foo;
/// std::mem::forget(x);
@ -57,7 +57,7 @@
/// destructor, possibly causing leaks.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::mem;
/// # use std::rc::Rc;
/// mem::forget(Rc::new(55))
@ -90,7 +90,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let is_copy = is_copy(cx, arg_ty);
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
let (lint, msg, note_span) = match fn_name {
// early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types
// early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references,
// forgetting_copy_types
sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
sym::mem_forget if arg_ty.is_ref() => return,
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
@ -100,8 +101,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
|| is_must_use_func_call(cx, arg)
|| is_must_use_ty(cx, arg_ty)
|| drop_is_single_call_in_arm
) =>
|| drop_is_single_call_in_arm) =>
{
(DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span))
},
@ -122,7 +122,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
} else {
(FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span))
}
}
},
_ => return,
};
span_lint_and_note(

View File

@ -15,7 +15,7 @@
/// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
///
/// ### Example
/// ```rust
/// ```no_run
/// # fn a() {}
/// # fn b() {}
/// # let x: i32 = 1;
@ -28,7 +28,7 @@
///
/// Use instead:
///
/// ```rust
/// ```no_run
/// # fn a() {}
/// # fn b() {}
/// # let x: i32 = 1;

View File

@ -16,7 +16,7 @@
/// destructured, which might be the intention behind adding the implementation as a marker.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct S;
///
/// impl Drop for S {
@ -24,7 +24,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// struct S;
/// ```
#[clippy::version = "1.62.0"]

View File

@ -23,12 +23,12 @@
///
///
/// ### Example
/// ```rust
/// ```no_run
/// enum Test {}
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// #![feature(never_type)]
///
/// struct Test(!);

View File

@ -15,11 +15,11 @@
/// Empty brackets after a struct declaration can be omitted.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Cookie {}
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// struct Cookie;
/// ```
#[clippy::version = "1.62.0"]
@ -35,7 +35,8 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if let ItemKind::Struct(var_data, _) = &item.kind
&& has_brackets(var_data)
&& has_no_fields(cx, var_data, span_after_ident) {
&& has_no_fields(cx, var_data, span_after_ident)
{
span_lint_and_then(
cx,
EMPTY_STRUCTS_WITH_BRACKETS,
@ -46,8 +47,9 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
span_after_ident,
"remove the brackets",
";",
Applicability::Unspecified);
},
Applicability::Unspecified,
);
},
);
}
}

View File

@ -23,7 +23,7 @@
///
/// ### Known problems
/// The suggestion may have type inference errors in some cases. e.g.
/// ```rust
/// ```no_run
/// let mut map = std::collections::HashMap::new();
/// let _ = if !map.contains_key(&0) {
/// map.insert(0, 0)
@ -33,7 +33,7 @@
/// ```
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::collections::HashMap;
/// # let mut map = HashMap::new();
/// # let k = 1;
@ -43,7 +43,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::collections::HashMap;
/// # let mut map = HashMap::new();
/// # let k = 1;

View File

@ -19,7 +19,7 @@
/// architectures, but works fine on 64 bit.
///
/// ### Example
/// ```rust
/// ```no_run
/// # #[cfg(target_pointer_width = "64")]
/// #[repr(usize)]
/// enum NonPortable {

View File

@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if !in_external_macro(cx.sess(), expr.span)
&& let ExprKind::Let(let_expr) = expr.kind
&& unary_pattern(let_expr.pat) {
&& unary_pattern(let_expr.pat)
{
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
let mut applicability = Applicability::MachineApplicable;
@ -79,7 +80,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
"({})",
snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
),
_ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
_ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability)
.0
.to_string(),
};
span_lint_and_sugg(
cx,

View File

@ -41,10 +41,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
};
match item.kind {
ItemKind::TyAlias(..) if item.ident.name == sym::Error
&& is_visible_outside_module(cx, item.owner_id.def_id)
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& implements_trait(cx, ty, error_def_id, &[]) =>
ItemKind::TyAlias(..)
if item.ident.name == sym::Error
&& is_visible_outside_module(cx, item.owner_id.def_id)
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& implements_trait(cx, ty, error_def_id, &[]) =>
{
span_lint(
cx,
@ -53,13 +54,14 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
"exported type alias named `Error` that implements `Error`",
);
},
ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
&& error_def_id == trait_def_id
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
&& let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
&& let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
&& ident.name == sym::Error
&& is_visible_outside_module(cx, def_id) =>
ItemKind::Impl(imp)
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
&& error_def_id == trait_def_id
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
&& let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
&& let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
&& ident.name == sym::Error
&& is_visible_outside_module(cx, def_id) =>
{
span_lint_hir_and_then(
cx,
@ -69,9 +71,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
"exported type named `Error` that implements `Error`",
|diag| {
diag.span_note(item.span, "`Error` was implemented here");
}
},
);
}
},
_ => {},
}
}

View File

@ -28,12 +28,12 @@ pub struct BoxedLocal {
/// into something.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn foo(x: Box<u32>) {}
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// fn foo(x: u32) {}
/// ```
#[clippy::version = "pre 1.29.0"]

View File

@ -119,19 +119,21 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
match body.value.kind {
ExprKind::Call(callee, args)
if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) =>
if matches!(
callee.kind,
ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))
) =>
{
let callee_ty = typeck.expr_ty(callee).peel_refs();
if matches!(
type_diagnostic_name(cx, callee_ty),
Some(sym::Arc | sym::Rc)
) || !check_inputs(typeck, body.params, None, args) {
if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
|| !check_inputs(typeck, body.params, None, args)
{
return;
}
let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or(
callee_ty,
|a| a.target.peel_refs(),
);
let callee_ty_adjusted = typeck
.expr_adjustments(callee)
.last()
.map_or(callee_ty, |a| a.target.peel_refs());
let sig = match callee_ty_adjusted.kind() {
ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
@ -160,36 +162,26 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// For now ignore all callee types which reference a type parameter.
&& !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
{
span_lint_and_then(
cx,
REDUNDANT_CLOSURE,
expr.span,
"redundant closure",
|diag| {
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
if let Ok((ClosureKind::FnMut, _))
= cx.tcx.infer_ctxt().build().type_implements_fn_trait(
cx.param_env,
Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
ImplPolarity::Positive,
) && path_to_local(callee)
.map_or(
false,
|l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr),
)
{
// Mutable closure is used after current expr; we cannot consume it.
snippet = format!("&mut {snippet}");
}
diag.span_suggestion(
expr.span,
"replace the closure with the function itself",
snippet,
Applicability::MachineApplicable,
);
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
cx.param_env,
Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
ImplPolarity::Positive,
) && path_to_local(callee).map_or(false, |l| {
local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
}) {
// Mutable closure is used after current expr; we cannot consume it.
snippet = format!("&mut {snippet}");
}
diag.span_suggestion(
expr.span,
"replace the closure with the function itself",
snippet,
Applicability::MachineApplicable,
);
}
);
});
}
},
ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {

View File

@ -22,7 +22,7 @@
/// readability and API.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct S {
/// is_pending: bool,
/// is_processing: bool,
@ -31,7 +31,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// enum S {
/// Pending,
/// Processing,
@ -157,7 +157,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitIt
// functions with a body are already checked by `check_fn`
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
&& fn_sig.header.abi == Abi::Rust
{
{
self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
}
}
@ -174,11 +174,8 @@ fn check_fn(
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
if let Some(fn_header) = fn_kind.header()
&& fn_header.abi == Abi::Rust
&& get_parent_as_impl(cx.tcx, hir_id)
.map_or(true,
|impl_item| impl_item.of_trait.is_none()
)
{
&& get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none())
{
self.check_fn_sig(cx, fn_decl, span);
}
}

View File

@ -17,14 +17,14 @@
/// disable them by default.
///
/// ### Example
/// ```rust
/// ```no_run
/// enum Foo {
/// Bar,
/// Baz
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// #[non_exhaustive]
/// enum Foo {
/// Bar,
@ -47,14 +47,14 @@
/// disable them by default.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Foo {
/// bar: u8,
/// baz: String,
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// #[non_exhaustive]
/// struct Foo {
/// bar: u8,

View File

@ -17,7 +17,7 @@
/// the main function.
///
/// ### Example
/// ```
/// ```no_run
/// std::process::exit(0)
/// ```
///

View File

@ -19,7 +19,7 @@
/// Using `(e)println! is clearer and more concise
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::io::Write;
/// # let bar = "furchtbar";
/// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
@ -27,7 +27,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::io::Write;
/// # let bar = "furchtbar";
/// eprintln!("foo: {:?}", bar);
@ -58,7 +58,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
Some(sym::io_stderr) => ("stderr", "e"),
_ => return,
};
let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { return; };
let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else {
return;
};
// ordering is important here, since `writeln!` uses `write!` internally
let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() {
@ -78,18 +80,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
macro_name.replace("write", "print"),
)
} else {
(
format!("{dest_name}().write_fmt(...)"),
"print".into(),
)
(format!("{dest_name}().write_fmt(...)"), "print".into())
};
let mut applicability = Applicability::MachineApplicable;
let inputs_snippet = snippet_with_applicability(
cx,
format_args_inputs_span(&format_args),
"..",
&mut applicability,
);
let inputs_snippet =
snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability);
span_lint_and_sugg(
cx,
EXPLICIT_WRITE,

View File

@ -23,13 +23,13 @@
/// requires using a turbofish, which serves no purpose but to satisfy the compiler.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn unused_ty<T>(x: u8) {
/// // ..
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// fn no_unused_ty(x: u8) {
/// // ..
/// }
@ -177,20 +177,22 @@ fn emit_lint(&self) {
.iter()
.rev()
.map(|(idx, param)| {
if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) {
// Extend the current span forward, up until the next param in the list.
param.span.until(next.span)
} else {
// Extend the current span back to include the comma following the previous
// param. If the span of the next param in the list has already been
// extended, we continue the chain. This is why we're iterating in reverse.
end = Some(param.def_id);
if let Some(next) = explicit_params.get(idx + 1)
&& end != Some(next.def_id)
{
// Extend the current span forward, up until the next param in the list.
param.span.until(next.span)
} else {
// Extend the current span back to include the comma following the previous
// param. If the span of the next param in the list has already been
// extended, we continue the chain. This is why we're iterating in reverse.
end = Some(param.def_id);
// idx will never be 0, else we'd be removing the entire list of generics
let prev = explicit_params[idx - 1];
let prev_span = self.get_bound_span(prev);
self.get_bound_span(param).with_lo(prev_span.hi())
}
// idx will never be 0, else we'd be removing the entire list of generics
let prev = explicit_params[idx - 1];
let prev_span = self.get_bound_span(prev);
self.get_bound_span(param).with_lo(prev_span.hi())
}
})
.collect()
};

View File

@ -17,7 +17,7 @@
/// `TryFrom` should be used if there's a possibility of failure.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Foo(i32);
///
/// impl From<String> for Foo {
@ -28,7 +28,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// struct Foo(i32);
///
/// impl TryFrom<String> for Foo {

View File

@ -18,13 +18,13 @@
/// Rust will truncate the literal silently.
///
/// ### Example
/// ```rust
/// ```no_run
/// let v: f32 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let v: f64 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789_9
/// ```
@ -44,12 +44,12 @@
/// conversion to a float.
///
/// ### Example
/// ```rust
/// ```no_run
/// let _: f32 = 16_777_217.0; // 16_777_216.0
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let _: f32 = 16_777_216.0;
/// let _: f64 = 16_777_217.0;
/// ```

View File

@ -27,7 +27,7 @@
/// Negatively impacts accuracy.
///
/// ### Example
/// ```rust
/// ```no_run
/// let a = 3f32;
/// let _ = a.powf(1.0 / 3.0);
/// let _ = (1.0 + a).ln();
@ -35,7 +35,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let a = 3f32;
/// let _ = a.cbrt();
/// let _ = a.ln_1p();
@ -57,7 +57,7 @@
/// Negatively impacts accuracy and performance.
///
/// ### Example
/// ```rust
/// ```no_run
/// use std::f32::consts::E;
///
/// let a = 3f32;
@ -83,7 +83,7 @@
///
/// is better expressed as
///
/// ```rust
/// ```no_run
/// use std::f32::consts::E;
///
/// let a = 3f32;
@ -323,9 +323,9 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
let maybe_neg_sugg = |expr, hir_id| {
let sugg = Sugg::hir(cx, expr, "..");
if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
format!("-{}", sugg.maybe_par())
-sugg
} else {
sugg.to_string()
sugg
}
};
@ -470,25 +470,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
let maybe_neg_sugg = |expr| {
let sugg = Sugg::hir(cx, expr, "..");
if let BinOpKind::Sub = op {
format!("-{sugg}")
} else {
sugg.to_string()
}
if let BinOpKind::Sub = op { -sugg } else { sugg }
};
let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
(
inner_lhs,
Sugg::hir(cx, inner_rhs, "..").to_string(),
maybe_neg_sugg(rhs),
)
(inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs))
} else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
(
inner_lhs,
maybe_neg_sugg(inner_rhs),
Sugg::hir(cx, lhs, "..").to_string(),
)
(inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, ".."))
} else {
return;
};

View File

@ -23,13 +23,13 @@
/// if `foo: &str`.
///
/// ### Examples
/// ```rust
/// ```no_run
/// let foo = "foo";
/// format!("{}", foo);
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// let foo = "foo";
/// foo.to_owned();
/// ```
@ -54,7 +54,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
([], [_]) => {
// Simulate macro expansion, converting {{ and }} to { and }.
let Some(snippet) = snippet_opt(cx, format_args.span) else { return };
let Some(snippet) = snippet_opt(cx, format_args.span) else {
return;
};
let s_expand = snippet.replace("{{", "{").replace("}}", "}");
let sugg = format!("{s_expand}.to_string()");
span_useless_format(cx, call_site, sugg, applicability);
@ -76,13 +78,14 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
_ => false,
};
let sugg = if is_new_string {
snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned()
snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability)
.0
.into_owned()
} else {
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
format!("{}.to_string()", sugg.maybe_par())
};
span_useless_format(cx, call_site, sugg, applicability);
}
},
_ => {},

View File

@ -1,11 +1,11 @@
use arrayvec::ArrayVec;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_diag_trait_item;
use clippy_utils::macros::{
find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro,
is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage,
};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use if_chain::if_chain;
@ -35,12 +35,12 @@
/// The recommended code is both shorter and avoids a temporary allocation.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::panic::Location;
/// println!("error: {}", format!("something failed at {}", Location::caller()));
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller());
/// ```
@ -61,12 +61,12 @@
/// unnecessary.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller().to_string());
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller());
/// ```
@ -87,7 +87,7 @@
/// The inlined syntax, where allowed, is simpler.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let var = 42;
/// # let width = 1;
/// # let prec = 2;
@ -98,7 +98,7 @@
/// format!("{:.*}", prec, var);
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # let var = 42;
/// # let width = 1;
/// # let prec = 2;
@ -111,12 +111,12 @@
///
/// If allow-mixed-uninlined-format-args is set to false in clippy.toml,
/// the following code will also trigger the lint:
/// ```rust
/// ```no_run
/// # let var = 42;
/// format!("{} {}", var, 1+2);
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # let var = 42;
/// format!("{var} {}", 1+2);
/// ```
@ -141,13 +141,13 @@
/// an expected formatting operation such as adding padding isn't happening.
///
/// ### Example
/// ```rust
/// ```no_run
/// println!("{:.}", 1.0);
///
/// println!("not padded: {:5}", format_args!("..."));
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// println!("{}", 1.0);
///
/// println!("not padded: {}", format_args!("..."));
@ -370,7 +370,7 @@ fn check_one_arg(
};
fixes.push((pos_span, replacement));
fixes.push((arg_span, String::new()));
true // successful inlining, continue checking
true // successful inlining, continue checking
} else {
// Do not continue inlining (return false) in case
// * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)`

View File

@ -21,7 +21,7 @@
///
/// ### Example
///
/// ```rust
/// ```no_run
/// use std::fmt;
///
/// struct Structure(i32);
@ -33,7 +33,7 @@
///
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// use std::fmt;
///
/// struct Structure(i32);
@ -59,7 +59,7 @@
/// should write to the `Formatter`, not stdout/stderr.
///
/// ### Example
/// ```rust
/// ```no_run
/// use std::fmt::{Display, Error, Formatter};
///
/// struct S;
@ -72,7 +72,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// use std::fmt::{Display, Error, Formatter};
///
/// struct S;

View File

@ -21,13 +21,13 @@
/// While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer.
///
/// ### Example
/// ```rust
/// ```no_run
/// let mut s = String::new();
/// s += &format!("0x{:X}", 1024);
/// s.push_str(&format!("0x{:X}", 1024));
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// use std::fmt::Write as _; // import without risk of name clashing
///
/// let mut s = String::new();
@ -58,7 +58,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
arms.iter().any(|arm| is_format(cx, arm.body))
},
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e))
is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
},
_ => false,
}
@ -69,17 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let arg = match expr.kind {
ExprKind::MethodCall(_, _, [arg], _) => {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& match_def_path(cx, fn_def_id, &paths::PUSH_STR)
{
arg
} else {
return;
}
}
ExprKind::AssignOp(op, left, arg)
if op.node == BinOpKind::Add && is_string(cx, left) => {
arg
},
ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg,
_ => return,
};
if is_format(cx, arg) {

View File

@ -37,7 +37,7 @@
/// This is either a typo in the binary operator or confusing.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let foo = true;
/// # let bar = false;
/// // &&! looks like a different operator
@ -45,7 +45,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # let foo = true;
/// # let bar = false;
/// if foo && !bar {}

View File

@ -14,7 +14,7 @@
/// comment.
///
/// ### Example
/// ```rust
/// ```no_run
/// //// My amazing data structure
/// pub struct Foo {
/// // ...
@ -22,7 +22,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// /// My amazing data structure
/// pub struct Foo {
/// // ...

View File

@ -1,6 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::path_def_id;
use clippy_utils::source::snippet_opt;
use rustc_errors::Applicability;
@ -24,7 +24,7 @@
/// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct StringWrapper(String);
///
/// impl Into<StringWrapper> for String {
@ -34,7 +34,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// struct StringWrapper(String);
///
/// impl From<String> for StringWrapper {
@ -88,7 +88,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
cx.tcx.sess.source_map().guess_head_span(item.span),
"an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
|diag| {
// If the target type is likely foreign mention the orphan rules as it's a common source of confusion
// If the target type is likely foreign mention the orphan rules as it's a common source of
// confusion
if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
diag.help(
"`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
@ -96,7 +97,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
);
}
let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
let message = format!(
"replace the `Into` implementation with `From<{}>`",
middle_trait_ref.self_ty()
);
if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
} else {
@ -110,12 +114,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
extract_msrv_attr!(LateContext);
}
/// Finds the occurences of `Self` and `self`
/// Finds the occurrences of `Self` and `self`
struct SelfFinder<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
/// Occurences of `Self`
/// Occurrences of `Self`
upper: Vec<Span>,
/// Occurences of `self`
/// Occurrences of `self`
lower: Vec<Span>,
/// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
/// already named `val`

View File

@ -18,13 +18,13 @@
/// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::ffi::c_void;
/// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
/// let _ = unsafe { Box::from_raw(ptr) };
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::ffi::c_void;
/// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
@ -40,14 +40,22 @@
impl LateLintPass<'_> for FromRawWithVoidPtr {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
&& seg.ident.name == sym!(from_raw)
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
&& let RawPtr(TypeAndMut { ty, .. }) = arg_kind
&& is_c_void(cx, *ty) {
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
&& seg.ident.name == sym!(from_raw)
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
&& let RawPtr(TypeAndMut { ty, .. }) = arg_kind
&& is_c_void(cx, *ty)
{
let msg = format!("creating a `{type_str}` from a void raw pointer");
span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type");
span_lint_and_help(
cx,
FROM_RAW_WITH_VOID_PTR,
expr.span,
&msg,
Some(arg.span),
"cast this to a pointer of the appropriate type",
);
}
}
}

View File

@ -23,7 +23,7 @@
/// grouping some parameters into a new type.
///
/// ### Example
/// ```rust
/// ```no_run
/// # struct Color;
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
/// // ..
@ -46,7 +46,7 @@
/// multiple functions.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn im_too_long() {
/// println!("");
/// // ... 100 more LoC
@ -129,7 +129,7 @@
/// a remnant of a refactoring that removed the return type.
///
/// ### Examples
/// ```rust
/// ```no_run
/// #[must_use]
/// fn useless() { }
/// ```
@ -151,7 +151,7 @@
/// attribute to improve the lint message.
///
/// ### Examples
/// ```rust
/// ```no_run
/// #[must_use]
/// fn double_must_use() -> Result<(), ()> {
/// unimplemented!();
@ -183,7 +183,7 @@
/// `#[must_use]`.
///
/// ### Examples
/// ```rust
/// ```no_run
/// // this could be annotated with `#[must_use]`.
/// pub fn id<T>(t: T) -> T { t }
/// ```
@ -211,7 +211,7 @@
/// instead.
///
/// ### Examples
/// ```rust
/// ```no_run
/// pub fn read_u8() -> Result<u8, ()> { Err(()) }
/// ```
/// should become
@ -262,7 +262,7 @@
/// The size determined by Clippy is platform-dependent.
///
/// ### Examples
/// ```rust
/// ```no_run
/// pub enum ParseError {
/// UnparsedBytes([u8; 512]),
/// UnexpectedEof,
@ -274,7 +274,7 @@
/// }
/// ```
/// should be
/// ```
/// ```no_run
/// pub enum ParseError {
/// UnparsedBytes(Box<[u8; 512]>),
/// UnexpectedEof,
@ -301,7 +301,7 @@
///
/// ### Example
/// ```rust
/// ```no_run
/// struct A {
/// a: String,
/// b: String,
@ -315,7 +315,7 @@
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// struct A {
/// a: String,
/// b: String,
@ -340,14 +340,14 @@
/// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
///
/// ### Example
/// ```rust
/// ```no_run
/// trait MyTrait {}
/// fn foo(a: impl MyTrait) {
/// // [...]
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// trait MyTrait {}
/// fn foo<T: MyTrait>(a: T) {
/// // [...]

View File

@ -118,9 +118,10 @@ fn check_needless_must_use(
if sig.header.is_async() {
let infcx = cx.tcx.infer_ctxt().build();
if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id))
&& !is_must_use_ty(cx, future_ty) {
return;
}
&& !is_must_use_ty(cx, future_ty)
{
return;
}
}
span_lint_and_help(

View File

@ -21,7 +21,9 @@ fn result_err_ty<'tcx>(
) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
if !in_external_macro(cx.sess(), item_span)
&& let hir::FnRetTy::Return(hir_ty) = decl.output
&& let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
&& let ty = cx
.tcx
.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
&& let ty::Adt(_, args) = ty.kind()
{

View File

@ -34,11 +34,11 @@
/// produced.
///
/// ### Example
/// ```rust
/// ```no_run
/// async fn not_send(bytes: std::rc::Rc<[u8]>) {}
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// async fn is_send(bytes: std::sync::Arc<[u8]>) {}
/// ```
#[clippy::version = "1.44.0"]

View File

@ -1,6 +1,7 @@
//! lint on if branches that could be swapped so no `!` operation is necessary
//! on the condition
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_else_clause;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@ -16,7 +17,7 @@
/// Negations reduce the readability of statements.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let v: Vec<usize> = vec![];
/// # fn a() {}
/// # fn b() {}
@ -29,7 +30,7 @@
///
/// Could be written:
///
/// ```rust
/// ```no_run
/// # let v: Vec<usize> = vec![];
/// # fn a() {}
/// # fn b() {}
@ -47,6 +48,13 @@
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) {
return Constant::Int(0) == value;
}
false
}
impl LateLintPass<'_> for IfNotElse {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
// While loops will be desugared to ExprKind::If. This will cause the lint to fire.
@ -72,7 +80,9 @@ fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
"remove the `!` and swap the blocks of the `if`/`else`",
);
},
ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => {
// Disable firing the lint on `… != 0`, as these are likely to be bit tests.
// For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order.
span_lint_and_help(
cx,
IF_NOT_ELSE,

View File

@ -1,6 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
@ -21,7 +21,7 @@
/// in comparison to `bool::then`.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let v = vec![0];
/// let a = if v.is_empty() {
/// println!("true!");
@ -33,7 +33,7 @@
///
/// Could be written:
///
/// ```rust
/// ```no_run
/// # let v = vec![0];
/// let a = v.is_empty().then(|| {
/// println!("true!");
@ -76,7 +76,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
let ctxt = expr.span.ctxt();
if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
if let Some(higher::If {
cond,
then,
r#else: Some(els),
}) = higher::If::hir(expr)
&& let ExprKind::Block(then_block, _) = then.kind
&& let Some(then_expr) = then_block.expr
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
@ -86,7 +90,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
&& !contains_return(then_block.stmts)
{
let mut app = Applicability::Unspecified;
let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string();
let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
.maybe_par()
.to_string();
let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
let mut method_body = if then_block.stmts.is_empty() {
arg_snip.into_owned()
@ -100,9 +106,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
"then"
};
let help = format!(
"consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",
);
let help =
format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",);
span_lint_and_help(
cx,
IF_THEN_SOME_ELSE_NONE,

View File

@ -15,14 +15,14 @@
/// would detect a type change that `_` would ignore.
///
/// ### Example
/// ```rust
/// ```no_run
/// match std::fs::create_dir("tmp-work-dir") {
/// Ok(_) => println!("Working directory created"),
/// Err(s) => eprintln!("Could not create directory: {s}"),
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// match std::fs::create_dir("tmp-work-dir") {
/// Ok(()) => println!("Working directory created"),
/// Err(s) => eprintln!("Could not create directory: {s}"),
@ -52,7 +52,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
},
_ => {},
}
if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() {
span_lint_and_sugg(
cx,
IGNORED_UNIT_PATTERNS,

View File

@ -35,7 +35,7 @@
/// pieces of code, possibly including external crates.
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::collections::HashMap;
/// # use std::hash::{Hash, BuildHasher};
/// # trait Serialize {};
@ -44,7 +44,7 @@
/// pub fn foo(map: &mut HashMap<i32, i32>) { }
/// ```
/// could be rewritten as
/// ```rust
/// ```no_run
/// # use std::collections::HashMap;
/// # use std::hash::{Hash, BuildHasher};
/// # trait Serialize {};

View File

@ -24,13 +24,13 @@
/// corresponding statements.
///
/// ### Example
/// ```rust
/// ```no_run
/// fn foo(x: usize) -> usize {
/// x
/// }
/// ```
/// add return
/// ```rust
/// ```no_run
/// fn foo(x: usize) -> usize {
/// return x;
/// }

View File

@ -18,7 +18,7 @@
/// The built-in function is more readable and may be faster.
///
/// ### Example
/// ```rust
/// ```no_run
///let mut u:u32 = 7000;
///
/// if u != u32::MAX {
@ -26,7 +26,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
///let mut u:u32 = 7000;
///
/// u = u.saturating_add(1);
@ -82,18 +82,18 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
fn get_int_max(ty: Ty<'_>) -> Option<u128> {
match ty.peel_refs().kind() {
Int(IntTy::I8) => i8::max_value().try_into().ok(),
Int(IntTy::I16) => i16::max_value().try_into().ok(),
Int(IntTy::I32) => i32::max_value().try_into().ok(),
Int(IntTy::I64) => i64::max_value().try_into().ok(),
Int(IntTy::I128) => i128::max_value().try_into().ok(),
Int(IntTy::Isize) => isize::max_value().try_into().ok(),
Uint(UintTy::U8) => u8::max_value().try_into().ok(),
Uint(UintTy::U16) => u16::max_value().try_into().ok(),
Uint(UintTy::U32) => u32::max_value().try_into().ok(),
Uint(UintTy::U64) => u64::max_value().try_into().ok(),
Uint(UintTy::U128) => Some(u128::max_value()),
Uint(UintTy::Usize) => usize::max_value().try_into().ok(),
Int(IntTy::I8) => i8::MAX.try_into().ok(),
Int(IntTy::I16) => i16::MAX.try_into().ok(),
Int(IntTy::I32) => i32::MAX.try_into().ok(),
Int(IntTy::I64) => i64::MAX.try_into().ok(),
Int(IntTy::I128) => i128::MAX.try_into().ok(),
Int(IntTy::Isize) => isize::MAX.try_into().ok(),
Uint(UintTy::U8) => Some(u8::MAX.into()),
Uint(UintTy::U16) => Some(u16::MAX.into()),
Uint(UintTy::U32) => Some(u32::MAX.into()),
Uint(UintTy::U64) => Some(u64::MAX.into()),
Uint(UintTy::U128) => Some(u128::MAX),
Uint(UintTy::Usize) => usize::MAX.try_into().ok(),
_ => None,
}
}

View File

@ -15,7 +15,7 @@
/// Simplicity and readability. Instead we can easily use an builtin function.
///
/// ### Example
/// ```rust
/// ```no_run
/// # let end: u32 = 10;
/// # let start: u32 = 5;
/// let mut i: u32 = end - start;
@ -26,7 +26,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # let end: u32 = 10;
/// # let start: u32 = 5;
/// let mut i: u32 = end - start;

View File

@ -29,7 +29,7 @@
/// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`)
///
/// ### Example
/// ```rust
/// ```no_run
/// # use std::ops::{Deref,DerefMut};
/// fn f() -> impl Deref<Target = i32> + DerefMut<Target = i32> {
/// // ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound
@ -37,7 +37,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// # use std::ops::{Deref,DerefMut};
/// fn f() -> impl DerefMut<Target = i32> {
/// Box::new(123)
@ -230,19 +230,24 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
// Example:
// `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed.
// `DerefMut::Target` needs to match `Deref::Target`.
let implied_bounds: Vec<_> = opaque_ty.bounds.iter().filter_map(|bound| {
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
&& let [.., path] = poly_trait.trait_ref.path.segments
&& poly_trait.bound_generic_params.is_empty()
&& let Some(trait_def_id) = path.res.opt_def_id()
&& let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
&& !predicates.is_empty() // If the trait has no supertrait, there is nothing to add.
{
Some((bound.span(), path, predicates, trait_def_id))
} else {
None
}
}).collect();
let implied_bounds: Vec<_> = opaque_ty
.bounds
.iter()
.filter_map(|bound| {
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
&& let [.., path] = poly_trait.trait_ref.path.segments
&& poly_trait.bound_generic_params.is_empty()
&& let Some(trait_def_id) = path.res.opt_def_id()
&& let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
&& !predicates.is_empty()
// If the trait has no supertrait, there is nothing to add.
{
Some((bound.span(), path, predicates, trait_def_id))
} else {
None
}
})
.collect();
// Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec.
// This involves some extra logic when generic arguments are present, since
@ -253,30 +258,31 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
&& let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings)
&& let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id()
&& let Some((implied_by_span, implied_by_args, implied_by_bindings)) = implied_bounds
.iter()
.find_map(|&(span, implied_by_path, preds, implied_by_def_id)| {
let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args);
let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings);
&& let Some((implied_by_span, implied_by_args, implied_by_bindings)) =
implied_bounds
.iter()
.find_map(|&(span, implied_by_path, preds, implied_by_def_id)| {
let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args);
let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings);
preds.iter().find_map(|(clause, _)| {
if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
&& tr.def_id() == def_id
&& is_same_generics(
cx.tcx,
tr.trait_ref.args,
implied_by_args,
implied_args,
implied_by_def_id,
def_id,
)
{
Some((span, implied_by_args, implied_by_bindings))
} else {
None
}
preds.iter().find_map(|(clause, _)| {
if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
&& tr.def_id() == def_id
&& is_same_generics(
cx.tcx,
tr.trait_ref.args,
implied_by_args,
implied_args,
implied_by_def_id,
def_id,
)
{
Some((span, implied_by_args, implied_by_bindings))
} else {
None
}
})
})
})
{
emit_lint(
cx,
@ -286,7 +292,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
implied_bindings,
implied_by_bindings,
implied_by_args,
implied_by_span
implied_by_span,
);
}
}

View File

@ -19,7 +19,7 @@
/// Since the order of fields in a constructor doesn't affect the
/// resulted instance as the below example indicates,
///
/// ```rust
/// ```no_run
/// #[derive(Debug, PartialEq, Eq)]
/// struct Foo {
/// x: i32,
@ -35,7 +35,7 @@
/// inconsistent order can be confusing and decreases readability and consistency.
///
/// ### Example
/// ```rust
/// ```no_run
/// struct Foo {
/// x: i32,
/// y: i32,
@ -47,7 +47,7 @@
/// ```
///
/// Use instead:
/// ```rust
/// ```no_run
/// # struct Foo {
/// # x: i32,
/// # y: i32,

View File

@ -1,7 +1,7 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_copy;
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
use if_chain::if_chain;
@ -31,7 +31,7 @@
/// patterns.
///
/// ### Example
/// ```rust
/// ```no_run
/// let slice: Option<&[u32]> = Some(&[1, 2, 3]);
///
/// if let Some(slice) = slice {
@ -39,7 +39,7 @@
/// }
/// ```
/// Use instead:
/// ```rust
/// ```no_run
/// let slice: Option<&[u32]> = Some(&[1, 2, 3]);
///
/// if let Some(&[first, ..]) = slice {

Some files were not shown because too many files have changed in this diff Show More