mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
9f53fc32cf
298 changed files with 4937 additions and 5233 deletions
|
@ -4,7 +4,7 @@ uibless = "test --test compile-test -- -- --bless"
|
|||
bless = "test -- -- --bless"
|
||||
dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
|
||||
lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
|
||||
collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored"
|
||||
collect-metadata = "test --test dogfood --features internal -- collect_metadata"
|
||||
|
||||
[build]
|
||||
# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
|
||||
|
|
28
.github/workflows/lintcheck.yml
vendored
28
.github/workflows/lintcheck.yml
vendored
|
@ -53,18 +53,18 @@ jobs:
|
|||
id: cache-json
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: lintcheck-logs/lintcheck_crates_logs.json
|
||||
path: lintcheck-logs/ci_crates_logs.json
|
||||
key: ${{ steps.key.outputs.key }}
|
||||
|
||||
- name: Run lintcheck
|
||||
if: steps.cache-json.outputs.cache-hit != 'true'
|
||||
run: ./target/debug/lintcheck --format json --warn-all
|
||||
run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml
|
||||
|
||||
- name: Upload base JSON
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: base
|
||||
path: lintcheck-logs/lintcheck_crates_logs.json
|
||||
path: lintcheck-logs/ci_crates_logs.json
|
||||
|
||||
# Runs lintcheck on the PR and stores the results as an artifact
|
||||
head:
|
||||
|
@ -86,13 +86,13 @@ jobs:
|
|||
run: cargo build --manifest-path=lintcheck/Cargo.toml
|
||||
|
||||
- name: Run lintcheck
|
||||
run: ./target/debug/lintcheck --format json --warn-all
|
||||
run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml
|
||||
|
||||
- name: Upload head JSON
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: head
|
||||
path: lintcheck-logs/lintcheck_crates_logs.json
|
||||
path: lintcheck-logs/ci_crates_logs.json
|
||||
|
||||
# Retrieves the head and base JSON results and prints the diff to the GH actions step summary
|
||||
diff:
|
||||
|
@ -115,4 +115,20 @@ jobs:
|
|||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Diff results
|
||||
run: ./target/debug/lintcheck diff {base,head}/lintcheck_crates_logs.json >> $GITHUB_STEP_SUMMARY
|
||||
# GH's summery has a maximum size of 1024k:
|
||||
# https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary
|
||||
# That's why we first log to file and then to the summary and logs
|
||||
run: |
|
||||
./target/debug/lintcheck diff {base,head}/ci_crates_logs.json --truncate >> truncated_diff.md
|
||||
head -c 1024000 truncated_diff.md >> $GITHUB_STEP_SUMMARY
|
||||
cat truncated_diff.md
|
||||
./target/debug/lintcheck diff {base,head}/ci_crates_logs.json >> full_diff.md
|
||||
|
||||
- name: Upload full diff
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: diff
|
||||
if-no-files-found: ignore
|
||||
path: |
|
||||
full_diff.md
|
||||
truncated_diff.md
|
||||
|
|
47
CHANGELOG.md
47
CHANGELOG.md
|
@ -6,11 +6,53 @@ document.
|
|||
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[ca3b3937...master](https://github.com/rust-lang/rust-clippy/compare/ca3b3937...master)
|
||||
[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master)
|
||||
|
||||
## Rust 1.80
|
||||
|
||||
Current stable, released 2024-07-25
|
||||
|
||||
[View all 68 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-04-18T22%3A50%3A22Z..2024-05-30T08%3A26%3A18Z+base%3Amaster)
|
||||
|
||||
### New Lints
|
||||
|
||||
* Added [`while_float`] to `nursery`
|
||||
[#12765](https://github.com/rust-lang/rust-clippy/pull/12765)
|
||||
* Added [`macro_metavars_in_unsafe`] to `suspicious`
|
||||
[#12107](https://github.com/rust-lang/rust-clippy/pull/12107)
|
||||
* Added [`renamed_function_params`] to `restriction`
|
||||
[#11540](https://github.com/rust-lang/rust-clippy/pull/11540)
|
||||
* Added [`doc_lazy_continuation`] to `style`
|
||||
[#12770](https://github.com/rust-lang/rust-clippy/pull/12770)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Moved [`assigning_clones`] to `pedantic` (From `perf` now allow-by-default)
|
||||
[#12779](https://github.com/rust-lang/rust-clippy/pull/12779)
|
||||
* Moved [`single_char_pattern`] to `pedantic` (From `perf` now allow-by-default)
|
||||
[#11852](https://github.com/rust-lang/rust-clippy/pull/11852)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`panic`]: Added [`allow-panic-in-tests`] configuration to allow the lint in tests
|
||||
[#12803](https://github.com/rust-lang/rust-clippy/pull/12803)
|
||||
* [`missing_const_for_fn`]: Now respects the [`msrv`] configuration
|
||||
[#12713](https://github.com/rust-lang/rust-clippy/pull/12713)
|
||||
* [`missing_panics_doc`]: No longer lints on compile-time panics
|
||||
[#12790](https://github.com/rust-lang/rust-clippy/pull/12790)
|
||||
* [`collapsible_match`]: Now considers the [`msrv`] configuration for the suggestion
|
||||
[#12745](https://github.com/rust-lang/rust-clippy/pull/12745)
|
||||
* [`useless_vec`]: Added [`allow-useless-vec-in-tests`] configuration to allow the lint in tests
|
||||
[#12725](https://github.com/rust-lang/rust-clippy/pull/12725)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`single_match`], [`single_match_else`]: Suggestions are now machine-applicable
|
||||
[#12726](https://github.com/rust-lang/rust-clippy/pull/12726)
|
||||
|
||||
## Rust 1.79
|
||||
|
||||
Current stable, released 2024-06-13
|
||||
Released 2024-06-13
|
||||
|
||||
[View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-03-08T11%3A13%3A58Z..2024-04-18T15%3A50%3A50Z+base%3Amaster)
|
||||
|
||||
|
@ -5712,6 +5754,7 @@ Released 2018-09-13
|
|||
[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
|
||||
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
|
||||
[`path_ends_with_ext`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext
|
||||
[`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push
|
||||
[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
|
||||
[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
|
||||
[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
|
||||
|
|
|
@ -30,11 +30,10 @@ color-print = "0.3.4"
|
|||
anstream = "0.6.0"
|
||||
|
||||
[dev-dependencies]
|
||||
ui_test = "0.23"
|
||||
ui_test = "0.24"
|
||||
regex = "1.5.5"
|
||||
toml = "0.7.3"
|
||||
walkdir = "2.3"
|
||||
# This is used by the `collect-metadata` alias.
|
||||
filetime = "0.2.9"
|
||||
itertools = "0.12"
|
||||
|
||||
|
@ -63,3 +62,7 @@ rustc_private = true
|
|||
[[test]]
|
||||
name = "compile-test"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "dogfood"
|
||||
harness = false
|
||||
|
|
|
@ -458,9 +458,8 @@ pub struct ManualStrip {
|
|||
}
|
||||
|
||||
impl ManualStrip {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self { msrv: conf.msrv.clone() }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -689,7 +688,6 @@ for some users. Adding a configuration is done in the following steps:
|
|||
]);
|
||||
|
||||
// New manual definition struct
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StructName {}
|
||||
|
||||
impl_lint_pass!(StructName => [
|
||||
|
@ -700,7 +698,6 @@ for some users. Adding a configuration is done in the following steps:
|
|||
2. Next add the configuration value and a corresponding creation method like
|
||||
this:
|
||||
```rust
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StructName {
|
||||
configuration_ident: Type,
|
||||
}
|
||||
|
@ -708,9 +705,9 @@ for some users. Adding a configuration is done in the following steps:
|
|||
// ...
|
||||
|
||||
impl StructName {
|
||||
pub fn new(configuration_ident: Type) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
configuration_ident,
|
||||
configuration_ident: conf.configuration_ident,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -726,8 +723,7 @@ for some users. Adding a configuration is done in the following steps:
|
|||
store.register_*_pass(|| box module::StructName);
|
||||
|
||||
// New registration with configuration value
|
||||
let configuration_ident = conf.configuration_ident.clone();
|
||||
store.register_*_pass(move || box module::StructName::new(configuration_ident));
|
||||
store.register_*_pass(move || box module::StructName::new(conf));
|
||||
```
|
||||
|
||||
Congratulations the work is almost done. The configuration value can now be
|
||||
|
|
|
@ -455,7 +455,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 Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
|
||||
**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
|
@ -679,6 +679,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
|
|||
* [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned)
|
||||
* [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions)
|
||||
* [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied)
|
||||
* [`collapsible_match`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match)
|
||||
* [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace)
|
||||
* [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr)
|
||||
* [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls)
|
||||
|
|
|
@ -8,7 +8,6 @@ reason = "this function does not add a link to our documentation, please use the
|
|||
path = "rustc_lint::context::LintContext::span_lint"
|
||||
reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
|
||||
|
||||
|
||||
[[disallowed-methods]]
|
||||
path = "rustc_middle::ty::context::TyCtxt::node_span_lint"
|
||||
reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead"
|
||||
|
|
|
@ -18,23 +18,26 @@ use std::{cmp, env, fmt, fs, io};
|
|||
#[rustfmt::skip]
|
||||
const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
|
||||
"KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
|
||||
"AccessKit",
|
||||
"CoreFoundation", "CoreGraphics", "CoreText",
|
||||
"DevOps",
|
||||
"DirectX",
|
||||
"Direct2D", "Direct3D", "DirectWrite", "DirectX",
|
||||
"ECMAScript",
|
||||
"GPLv2", "GPLv3",
|
||||
"GitHub", "GitLab",
|
||||
"IPv4", "IPv6",
|
||||
"ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
|
||||
"ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript",
|
||||
"WebAssembly",
|
||||
"NaN", "NaNs",
|
||||
"OAuth", "GraphQL",
|
||||
"OCaml",
|
||||
"OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry",
|
||||
"WebGL", "WebGL2", "WebGPU",
|
||||
"OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry",
|
||||
"OpenType",
|
||||
"WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport",
|
||||
"WebP", "OpenExr", "YCbCr", "sRGB",
|
||||
"TensorFlow",
|
||||
"TrueType",
|
||||
"iOS", "macOS", "FreeBSD",
|
||||
"iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD",
|
||||
"TeX", "LaTeX", "BibTeX", "BibLaTeX",
|
||||
"MinGW",
|
||||
"CamelCase",
|
||||
|
@ -235,7 +238,7 @@ define_Conf! {
|
|||
///
|
||||
/// 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: FxHashSet<String> = <_>::default()),
|
||||
(arithmetic_side_effects_allowed: Vec<String> = <_>::default()),
|
||||
/// Lint: ARITHMETIC_SIDE_EFFECTS.
|
||||
///
|
||||
/// Suppress checking of the passed type pair names in binary operations like addition or
|
||||
|
@ -262,12 +265,12 @@ define_Conf! {
|
|||
/// ```toml
|
||||
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
|
||||
/// ```
|
||||
(arithmetic_side_effects_allowed_unary: FxHashSet<String> = <_>::default()),
|
||||
(arithmetic_side_effects_allowed_unary: Vec<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, NEEDLESS_PASS_BY_REF_MUT.
|
||||
///
|
||||
/// 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, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON.
|
||||
/// 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, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH.
|
||||
///
|
||||
/// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
|
||||
#[default_text = ""]
|
||||
|
@ -311,7 +314,7 @@ define_Conf! {
|
|||
/// 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.
|
||||
(doc_valid_idents: Vec<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
|
||||
(doc_valid_idents: FxHashSet<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
|
||||
|
@ -547,7 +550,7 @@ define_Conf! {
|
|||
/// Lint: PATH_ENDS_WITH_EXT.
|
||||
///
|
||||
/// Additional dotfiles (files or directories starting with a dot) to allow
|
||||
(allowed_dotfiles: FxHashSet<String> = FxHashSet::default()),
|
||||
(allowed_dotfiles: Vec<String> = Vec::default()),
|
||||
/// Lint: MULTIPLE_CRATE_VERSIONS.
|
||||
///
|
||||
/// A list of crate names to allow duplicates of
|
||||
|
@ -700,7 +703,6 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
|
|||
fn deserialize(file: &SourceFile) -> TryConf {
|
||||
match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) {
|
||||
Ok(mut conf) => {
|
||||
extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
|
||||
extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
|
||||
extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES);
|
||||
extend_vec_if_indicator_present(
|
||||
|
@ -713,6 +715,11 @@ fn deserialize(file: &SourceFile) -> TryConf {
|
|||
.allowed_idents_below_min_chars
|
||||
.extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string));
|
||||
}
|
||||
if conf.conf.doc_valid_idents.contains("..") {
|
||||
conf.conf
|
||||
.doc_valid_idents
|
||||
.extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string));
|
||||
}
|
||||
|
||||
conf
|
||||
},
|
||||
|
|
|
@ -2,13 +2,13 @@ use serde::de::{self, Deserializer, Visitor};
|
|||
use serde::{ser, Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Rename {
|
||||
pub path: String,
|
||||
pub rename: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DisallowedPath {
|
||||
Simple(String),
|
||||
|
@ -22,12 +22,10 @@ impl DisallowedPath {
|
|||
path
|
||||
}
|
||||
|
||||
pub fn reason(&self) -> Option<String> {
|
||||
match self {
|
||||
Self::WithReason {
|
||||
reason: Some(reason), ..
|
||||
} => Some(format!("{reason} (from clippy.toml)")),
|
||||
_ => None,
|
||||
pub fn reason(&self) -> Option<&str> {
|
||||
match &self {
|
||||
Self::WithReason { reason, .. } => reason.as_deref(),
|
||||
Self::Simple(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
|
|||
|
||||
let new_lint = if enable_msrv {
|
||||
format!(
|
||||
"store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ",
|
||||
"store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf)));\n ",
|
||||
lint_pass = lint.pass,
|
||||
ctor_arg = if lint.pass == "late" { "_" } else { "" },
|
||||
module_name = lint.name,
|
||||
|
@ -274,6 +274,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
formatdoc!(
|
||||
r#"
|
||||
use clippy_config::msrvs::{{self, Msrv}};
|
||||
use clippy_config::Conf;
|
||||
{pass_import}
|
||||
use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
@ -301,9 +302,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
|||
}}
|
||||
|
||||
impl {name_camel} {{
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {{
|
||||
Self {{ msrv }}
|
||||
pub fn new(conf: &'static Conf) -> Self {{
|
||||
Self {{ msrv: conf.msrv.clone() }}
|
||||
}}
|
||||
}}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
@ -47,7 +48,16 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
|
|||
|
||||
pub struct AbsolutePaths {
|
||||
pub absolute_paths_max_segments: u64,
|
||||
pub absolute_paths_allowed_crates: FxHashSet<String>,
|
||||
pub absolute_paths_allowed_crates: &'static FxHashSet<String>,
|
||||
}
|
||||
|
||||
impl AbsolutePaths {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
absolute_paths_max_segments: conf.absolute_paths_max_segments,
|
||||
absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for AbsolutePaths {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{trim_span, walk_span_to_context};
|
||||
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
|
||||
|
@ -34,8 +35,10 @@ pub struct AlmostCompleteRange {
|
|||
msrv: Msrv,
|
||||
}
|
||||
impl AlmostCompleteRange {
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl EarlyLintPass for AlmostCompleteRange {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
|
@ -67,9 +68,10 @@ pub struct ApproxConstant {
|
|||
}
|
||||
|
||||
impl ApproxConstant {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{is_from_proc_macro, last_path_segment};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
|
@ -42,12 +42,11 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if !expr.span.from_expansion()
|
||||
&& let ty = cx.typeck_results().expr_ty(expr)
|
||||
&& is_type_diagnostic_item(cx, ty, sym::Arc)
|
||||
&& let ExprKind::Call(func, [arg]) = expr.kind
|
||||
&& let ExprKind::Path(func_path) = func.kind
|
||||
&& last_path_segment(&func_path).ident.name == sym::new
|
||||
if let ExprKind::Call(func, [arg]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind
|
||||
&& func_name.ident.name == sym::new
|
||||
&& !expr.span.from_expansion()
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc)
|
||||
&& let arg_ty = cx.typeck_results().expr_ty(arg)
|
||||
// make sure that the type is not and does not contain any type parameters
|
||||
&& arg_ty.walk().all(|arg| {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
|
@ -57,9 +58,10 @@ pub struct AssigningClones {
|
|||
}
|
||||
|
||||
impl AssigningClones {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ mod useless_attribute;
|
|||
mod utils;
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
|
||||
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
|
@ -499,7 +500,6 @@ declare_clippy_lint! {
|
|||
"duplicated attribute"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Attributes {
|
||||
msrv: Msrv,
|
||||
}
|
||||
|
@ -517,9 +517,10 @@ impl_lint_pass!(Attributes => [
|
|||
]);
|
||||
|
||||
impl Attributes {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,7 +590,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
|
|||
}
|
||||
|
||||
pub struct EarlyAttributes {
|
||||
pub msrv: Msrv,
|
||||
msrv: Msrv,
|
||||
}
|
||||
|
||||
impl EarlyAttributes {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(EarlyAttributes => [
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use clippy_config::types::DisallowedPath;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use clippy_utils::{create_disallowed_map, match_def_path, paths};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{DefId, DefIdMap};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir::CoroutineLayout;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
|
@ -172,31 +172,19 @@ declare_clippy_lint! {
|
|||
|
||||
impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AwaitHolding {
|
||||
conf_invalid_types: Vec<DisallowedPath>,
|
||||
def_ids: FxHashMap<DefId, DisallowedPath>,
|
||||
def_ids: DefIdMap<(&'static str, Option<&'static str>)>,
|
||||
}
|
||||
|
||||
impl AwaitHolding {
|
||||
pub(crate) fn new(conf_invalid_types: Vec<DisallowedPath>) -> Self {
|
||||
pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
conf_invalid_types,
|
||||
def_ids: FxHashMap::default(),
|
||||
def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for AwaitHolding {
|
||||
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||
for conf in &self.conf_invalid_types {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.def_ids.insert(id, conf.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if let hir::ExprKind::Closure(hir::Closure {
|
||||
kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)),
|
||||
|
@ -258,25 +246,22 @@ impl AwaitHolding {
|
|||
);
|
||||
},
|
||||
);
|
||||
} else if let Some(disallowed) = self.def_ids.get(&adt.did()) {
|
||||
emit_invalid_type(cx, ty_cause.source_info.span, disallowed);
|
||||
} else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) {
|
||||
emit_invalid_type(cx, ty_cause.source_info.span, path, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) {
|
||||
fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
AWAIT_HOLDING_INVALID_TYPE,
|
||||
span,
|
||||
format!(
|
||||
"`{}` may not be held across an await point per `clippy.toml`",
|
||||
disallowed.path()
|
||||
),
|
||||
format!("holding a disallowed type across an await point `{path}`"),
|
||||
|diag| {
|
||||
if let Some(reason) = disallowed.reason() {
|
||||
if let Some(reason) = reason {
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -49,35 +49,31 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
|
||||
if !e.span.from_expansion()
|
||||
&& let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind
|
||||
&& !addrof_target.span.from_expansion()
|
||||
if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind
|
||||
&& let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
|
||||
&& !deref_target.span.from_expansion()
|
||||
&& !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
|
||||
&& !e.span.from_expansion()
|
||||
&& !deref_target.span.from_expansion()
|
||||
&& !addrof_target.span.from_expansion()
|
||||
&& let ref_ty = cx.typeck_results().expr_ty(deref_target)
|
||||
&& let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
|
||||
&& get_parent_expr(cx, e).map_or(true, |parent| {
|
||||
match parent.kind {
|
||||
// `*&*foo` should lint `deref_addrof` instead.
|
||||
ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id),
|
||||
// `&*foo` creates a distinct temporary from `foo`
|
||||
ExprKind::AddrOf(_, Mutability::Mut, _) => !matches!(
|
||||
deref_target.kind,
|
||||
ExprKind::Path(..)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::Unary(UnOp::Deref, ..)
|
||||
),
|
||||
_ => true,
|
||||
}
|
||||
})
|
||||
&& !is_from_proc_macro(cx, e)
|
||||
{
|
||||
if let Some(parent_expr) = get_parent_expr(cx, e) {
|
||||
if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..))
|
||||
&& !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// modification to `&mut &*x` is different from `&mut x`
|
||||
if matches!(
|
||||
deref_target.kind,
|
||||
ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..)
|
||||
) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if is_from_proc_macro(cx, e) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
BORROW_DEREF_REF,
|
||||
|
|
|
@ -5,6 +5,7 @@ mod multiple_crate_versions;
|
|||
mod wildcard_dependencies;
|
||||
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
@ -204,8 +205,8 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
pub struct Cargo {
|
||||
pub allowed_duplicate_crates: FxHashSet<String>,
|
||||
pub ignore_publish: bool,
|
||||
allowed_duplicate_crates: &'static FxHashSet<String>,
|
||||
ignore_publish: bool,
|
||||
}
|
||||
|
||||
impl_lint_pass!(Cargo => [
|
||||
|
@ -217,6 +218,15 @@ impl_lint_pass!(Cargo => [
|
|||
LINT_GROUPS_PRIORITY,
|
||||
]);
|
||||
|
||||
impl Cargo {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
allowed_duplicate_crates: &conf.allowed_duplicate_crates,
|
||||
ignore_publish: conf.cargo_ignore_publish,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for Cargo {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
static NO_DEPS_LINTS: &[&Lint] = &[
|
||||
|
@ -253,7 +263,7 @@ impl LateLintPass<'_> for Cargo {
|
|||
{
|
||||
match MetadataCommand::new().exec() {
|
||||
Ok(metadata) => {
|
||||
multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates);
|
||||
multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates);
|
||||
},
|
||||
Err(e) => {
|
||||
for lint in WITH_DEPS_LINTS {
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::in_constant;
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_isize_or_usize;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
|
||||
use rustc_hir::{Expr, QPath, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, FloatTy, Ty, UintTy};
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
use rustc_span::hygiene;
|
||||
|
||||
use super::{utils, CAST_LOSSLESS};
|
||||
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
cast_op: &Expr<'_>,
|
||||
cast_from_expr: &Expr<'_>,
|
||||
cast_from: Ty<'_>,
|
||||
cast_to: Ty<'_>,
|
||||
cast_to_hir: &rustc_hir::Ty<'_>,
|
||||
|
@ -23,64 +25,54 @@ pub(super) fn check(
|
|||
return;
|
||||
}
|
||||
|
||||
// The suggestion is to use a function call, so if the original expression
|
||||
// has parens on the outside, they are no longer needed.
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let opt = snippet_opt(cx, cast_op.span.source_callsite());
|
||||
let sugg = opt.as_ref().map_or_else(
|
||||
|| {
|
||||
app = Applicability::HasPlaceholders;
|
||||
".."
|
||||
},
|
||||
|snip| {
|
||||
if should_strip_parens(cast_op, snip) {
|
||||
&snip[1..snip.len() - 1]
|
||||
} else {
|
||||
snip.as_str()
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Display the type alias instead of the aliased type. Fixes #11285
|
||||
//
|
||||
// FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead,
|
||||
// this will allow us to display the right type with `cast_from` as well.
|
||||
let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
|
||||
// It's a bit annoying but the turbofish is optional for types. A type in an `as` cast
|
||||
// shouldn't have these if they're primitives, which are the only things we deal with.
|
||||
//
|
||||
// This could be removed for performance if this check is determined to have a pretty major
|
||||
// effect.
|
||||
&& path.segments.iter().all(|segment| segment.args.is_none())
|
||||
{
|
||||
snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
|
||||
} else {
|
||||
cast_to.to_string().into()
|
||||
};
|
||||
|
||||
let message = if cast_from.is_bool() {
|
||||
format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
|
||||
} else {
|
||||
format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CAST_LOSSLESS,
|
||||
expr.span,
|
||||
message,
|
||||
"try",
|
||||
format!("{cast_to_fmt}::from({sugg})"),
|
||||
app,
|
||||
format!("casts from `{cast_from}` to `{cast_to}` can be expressed infallibly using `From`"),
|
||||
|diag| {
|
||||
diag.help("an `as` cast can become silently lossy if the types change in the future");
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "<from>", &mut applicability);
|
||||
let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else {
|
||||
return;
|
||||
};
|
||||
match cast_to_hir.kind {
|
||||
TyKind::Infer => {
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"use `Into::into` instead",
|
||||
format!("{}.into()", from_sugg.maybe_par()),
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
// Don't suggest `A<_>::B::From(x)` or `macro!()::from(x)`
|
||||
kind if matches!(kind, TyKind::Path(QPath::Resolved(_, path)) if path.segments.iter().any(|s| s.args.is_some()))
|
||||
|| !cast_to_hir.span.eq_ctxt(expr.span) =>
|
||||
{
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
format!("use `<{ty}>::from` instead"),
|
||||
format!("<{ty}>::from({from_sugg})"),
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
_ => {
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
format!("use `{ty}::from` instead"),
|
||||
format!("{ty}::from({from_sugg})"),
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
|
||||
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
|
||||
//
|
||||
// If destination is u128, do not lint because source type cannot be larger
|
||||
// If source is bool, still lint due to the lint message differing (refers to style)
|
||||
if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) {
|
||||
if in_constant(cx, expr.hir_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -110,12 +102,3 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool {
|
||||
if let ExprKind::Binary(_, _, _) = cast_expr.kind {
|
||||
if snip.starts_with('(') && snip.ends_with(')') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ mod utils;
|
|||
mod zero_ptr;
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::is_hir_ty_cfg_dependant;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
@ -658,11 +659,11 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// ### Example
|
||||
/// ```rust,ignore
|
||||
/// let _: (0.0_f32 / 0.0) as u64;
|
||||
/// let _ = (0.0_f32 / 0.0) as u64;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,ignore
|
||||
/// let _: = 0_u64;
|
||||
/// let _ = 0_u64;
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub CAST_NAN_TO_INT,
|
||||
|
@ -722,9 +723,10 @@ pub struct Casts {
|
|||
}
|
||||
|
||||
impl Casts {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,45 +763,45 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
|
|||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
|
||||
if let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind {
|
||||
if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
|
||||
return;
|
||||
}
|
||||
let (cast_from, cast_to) = (
|
||||
cx.typeck_results().expr_ty(cast_expr),
|
||||
cx.typeck_results().expr_ty(cast_from_expr),
|
||||
cx.typeck_results().expr_ty(expr),
|
||||
);
|
||||
|
||||
if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
|
||||
if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) {
|
||||
return;
|
||||
}
|
||||
cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
|
||||
ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
|
||||
as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
|
||||
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
zero_ptr::check(cx, expr, cast_expr, cast_to_hir);
|
||||
cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, &self.msrv);
|
||||
ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv);
|
||||
as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
|
||||
fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
|
||||
fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
|
||||
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
|
||||
zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
|
||||
|
||||
if cast_to.is_numeric() {
|
||||
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
|
||||
cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span);
|
||||
if cast_from.is_numeric() {
|
||||
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
|
||||
cast_precision_loss::check(cx, expr, cast_from, cast_to);
|
||||
cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
|
||||
cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to);
|
||||
cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv);
|
||||
cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to);
|
||||
}
|
||||
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
|
||||
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
|
||||
cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
|
||||
cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from);
|
||||
}
|
||||
|
||||
as_underscore::check(cx, expr, cast_to_hir);
|
||||
|
||||
if self.msrv.meets(msrvs::PTR_FROM_REF) {
|
||||
ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
|
||||
ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
|
||||
} else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
|
||||
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
|
||||
borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use clippy_utils::sugg::Sugg;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
|
||||
use super::PTR_CAST_CONSTNESS;
|
||||
|
||||
|
@ -24,6 +24,7 @@ pub(super) fn check<'tcx>(
|
|||
(Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
|
||||
)
|
||||
&& from_ty == to_ty
|
||||
&& !from_ty.has_erased_regions()
|
||||
{
|
||||
let sugg = Sugg::hir(cx, cast_expr, "_");
|
||||
let constness = match *to_mutbl {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
//! lint on manually implemented checked conversions that could be transformed into `try_from`
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
@ -40,9 +41,10 @@ pub struct CheckedConversions {
|
|||
}
|
||||
|
||||
impl CheckedConversions {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,61 +52,54 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
|
||||
if !self.msrv.meets(msrvs::TRY_FROM) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = if !in_constant(cx, item.hir_id)
|
||||
if let ExprKind::Binary(op, lhs, rhs) = item.kind
|
||||
&& let (lt1, gt1, op2) = match op.node {
|
||||
BinOpKind::Le => (lhs, rhs, None),
|
||||
BinOpKind::Ge => (rhs, lhs, None),
|
||||
BinOpKind::And
|
||||
if let ExprKind::Binary(op1, lhs1, rhs1) = lhs.kind
|
||||
&& let ExprKind::Binary(op2, lhs2, rhs2) = rhs.kind
|
||||
&& let Some((lt1, gt1)) = read_le_ge(op1.node, lhs1, rhs1)
|
||||
&& let Some((lt2, gt2)) = read_le_ge(op2.node, lhs2, rhs2) =>
|
||||
{
|
||||
(lt1, gt1, Some((lt2, gt2)))
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
&& !in_external_macro(cx.sess(), item.span)
|
||||
&& let ExprKind::Binary(op, left, right) = &item.kind
|
||||
&& !in_constant(cx, item.hir_id)
|
||||
&& self.msrv.meets(msrvs::TRY_FROM)
|
||||
&& let Some(cv) = match op2 {
|
||||
// todo: check for case signed -> larger unsigned == only x >= 0
|
||||
None => check_upper_bound(lt1, gt1).filter(|cv| cv.cvt == ConversionType::FromUnsigned),
|
||||
Some((lt2, gt2)) => {
|
||||
let upper_lower = |lt1, gt1, lt2, gt2| {
|
||||
check_upper_bound(lt1, gt1)
|
||||
.zip(check_lower_bound(lt2, gt2))
|
||||
.and_then(|(l, r)| l.combine(r, cx))
|
||||
};
|
||||
upper_lower(lt1, gt1, lt2, gt2).or_else(|| upper_lower(lt2, gt2, lt1, gt1))
|
||||
},
|
||||
}
|
||||
&& let Some(to_type) = cv.to_type
|
||||
{
|
||||
match op.node {
|
||||
BinOpKind::Ge | BinOpKind::Le => single_check(item),
|
||||
BinOpKind::And => double_check(cx, left, right),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(cv) = result {
|
||||
if let Some(to_type) = cv.to_type {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
CHECKED_CONVERSIONS,
|
||||
item.span,
|
||||
"checked cast can be simplified",
|
||||
"try",
|
||||
format!("{to_type}::try_from({snippet}).is_ok()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
CHECKED_CONVERSIONS,
|
||||
item.span,
|
||||
"checked cast can be simplified",
|
||||
"try",
|
||||
format!("{to_type}::try_from({snippet}).is_ok()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
/// Searches for a single check from unsigned to _ is done
|
||||
/// todo: check for case signed -> larger unsigned == only x >= 0
|
||||
fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
|
||||
check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
|
||||
}
|
||||
|
||||
/// Searches for a combination of upper & lower bound checks
|
||||
fn double_check<'a>(cx: &LateContext<'_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option<Conversion<'a>> {
|
||||
let upper_lower = |l, r| {
|
||||
let upper = check_upper_bound(l);
|
||||
let lower = check_lower_bound(r);
|
||||
|
||||
upper.zip(lower).and_then(|(l, r)| l.combine(r, cx))
|
||||
};
|
||||
|
||||
upper_lower(left, right).or_else(|| upper_lower(right, left))
|
||||
}
|
||||
|
||||
/// Contains the result of a tried conversion check
|
||||
#[derive(Clone, Debug)]
|
||||
struct Conversion<'a> {
|
||||
|
@ -121,6 +116,19 @@ enum ConversionType {
|
|||
FromUnsigned,
|
||||
}
|
||||
|
||||
/// Attempts to read either `<=` or `>=` with a normalized operand order.
|
||||
fn read_le_ge<'tcx>(
|
||||
op: BinOpKind,
|
||||
lhs: &'tcx Expr<'tcx>,
|
||||
rhs: &'tcx Expr<'tcx>,
|
||||
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
|
||||
match op {
|
||||
BinOpKind::Le => Some((lhs, rhs)),
|
||||
BinOpKind::Ge => Some((rhs, lhs)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Conversion<'a> {
|
||||
/// Combine multiple conversions if the are compatible
|
||||
pub fn combine(self, other: Self, cx: &LateContext<'_>) -> Option<Conversion<'a>> {
|
||||
|
@ -188,29 +196,17 @@ impl ConversionType {
|
|||
}
|
||||
|
||||
/// Check for `expr <= (to_type::MAX as from_type)`
|
||||
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
|
||||
if let ExprKind::Binary(ref op, left, right) = &expr.kind
|
||||
&& let Some((candidate, check)) = normalize_le_ge(op, left, right)
|
||||
&& let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX")
|
||||
{
|
||||
Conversion::try_new(candidate, from, to)
|
||||
fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
|
||||
if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") {
|
||||
Conversion::try_new(lt, from, to)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for `expr >= 0|(to_type::MIN as from_type)`
|
||||
fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
|
||||
fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
|
||||
(check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
|
||||
}
|
||||
|
||||
// First of we need a binary containing the expression & the cast
|
||||
if let ExprKind::Binary(ref op, left, right) = &expr.kind {
|
||||
normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn check_lower_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
|
||||
check_lower_bound_zero(gt, lt).or_else(|| check_lower_bound_min(gt, lt))
|
||||
}
|
||||
|
||||
/// Check for `expr >= 0`
|
||||
|
@ -309,15 +305,6 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Will return the expressions as if they were expr1 <= expr2
|
||||
fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
|
||||
match op.node {
|
||||
BinOpKind::Le => Some((left, right)),
|
||||
BinOpKind::Ge => Some((right, left)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Constants
|
||||
const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
|
||||
const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! calculate cognitive complexity and warn about overly complex functions
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::{IntoSpan, SpanRangeExt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
|
@ -39,10 +40,9 @@ pub struct CognitiveComplexity {
|
|||
}
|
||||
|
||||
impl CognitiveComplexity {
|
||||
#[must_use]
|
||||
pub fn new(limit: u64) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
limit: LimitStack::new(limit),
|
||||
limit: LimitStack::new(conf.cognitive_complexity_threshold),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,20 +93,14 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
|
|||
|
||||
impl EarlyLintPass for CollapsibleIf {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
if !expr.span.from_expansion() {
|
||||
check_if(cx, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
if let ast::ExprKind::If(check, then, else_) = &expr.kind {
|
||||
if let Some(else_) = else_ {
|
||||
check_collapsible_maybe_if_let(cx, then.span, else_);
|
||||
} else if let ast::ExprKind::Let(..) = check.kind {
|
||||
// Prevent triggering on `if let a = b { if c { .. } }`.
|
||||
} else {
|
||||
check_collapsible_no_if_let(cx, expr, check, then);
|
||||
if let ast::ExprKind::If(cond, then, else_) = &expr.kind
|
||||
&& !expr.span.from_expansion()
|
||||
{
|
||||
if let Some(else_) = else_ {
|
||||
check_collapsible_maybe_if_let(cx, then.span, else_);
|
||||
} else if !matches!(cond.kind, ast::ExprKind::Let(..)) {
|
||||
check_collapsible_no_if_let(cx, expr, cond, then);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,13 +183,10 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
|
|||
|
||||
/// If the block contains only one expression, return it.
|
||||
fn expr_block(block: &ast::Block) -> Option<&ast::Expr> {
|
||||
let mut it = block.stmts.iter();
|
||||
|
||||
if let (Some(stmt), None) = (it.next(), it.next()) {
|
||||
match stmt.kind {
|
||||
ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr),
|
||||
_ => None,
|
||||
}
|
||||
if let [stmt] = &*block.stmts
|
||||
&& let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind
|
||||
{
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ static COLLECTIONS: [Symbol; 9] = [
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
|
||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
|
||||
// Look for local variables whose type is a container. Search surrounding bock for read access.
|
||||
if match_acceptable_type(cx, local, &COLLECTIONS)
|
||||
&& let PatKind::Binding(_, local_id, _, _) = local.pat.kind
|
||||
// Look for local variables whose type is a container. Search surrounding block for read access.
|
||||
if let PatKind::Binding(_, local_id, _, _) = local.pat.kind
|
||||
&& match_acceptable_type(cx, local, &COLLECTIONS)
|
||||
&& let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id)
|
||||
&& has_no_read_access(cx, local_id, enclosing_block)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
|
||||
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt};
|
||||
use clippy_utils::ty::{needs_ordered_drop, InteriorMut};
|
||||
|
@ -11,6 +12,7 @@ use core::ops::ControlFlow;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::hygiene::walk_chain;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
|
@ -159,15 +161,13 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
pub struct CopyAndPaste<'tcx> {
|
||||
ignore_interior_mutability: Vec<String>,
|
||||
interior_mut: InteriorMut<'tcx>,
|
||||
}
|
||||
|
||||
impl CopyAndPaste<'_> {
|
||||
pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
|
||||
impl<'tcx> CopyAndPaste<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
ignore_interior_mutability,
|
||||
interior_mut: InteriorMut::default(),
|
||||
interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,10 +180,6 @@ impl_lint_pass!(CopyAndPaste<'_> => [
|
|||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> {
|
||||
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||
self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability);
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) {
|
||||
let (conds, blocks) = if_sequence(expr);
|
||||
|
|
|
@ -53,10 +53,9 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]);
|
|||
|
||||
impl EarlyLintPass for CrateInMacroDef {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
if item.attrs.iter().any(is_macro_export)
|
||||
&& let ItemKind::MacroDef(macro_def) = &item.kind
|
||||
&& let tts = macro_def.body.tokens.clone()
|
||||
&& let Some(span) = contains_unhygienic_crate_reference(&tts)
|
||||
if let ItemKind::MacroDef(macro_def) = &item.kind
|
||||
&& item.attrs.iter().any(is_macro_export)
|
||||
&& let Some(span) = contains_unhygienic_crate_reference(¯o_def.body.tokens)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_in_test;
|
||||
use clippy_utils::macros::{macro_backtrace, MacroCall};
|
||||
|
@ -33,7 +34,6 @@ declare_clippy_lint! {
|
|||
"`dbg!` macro is intended as a debugging tool"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DbgMacro {
|
||||
allow_dbg_in_tests: bool,
|
||||
/// Tracks the `dbg!` macro callsites that are already checked.
|
||||
|
@ -45,9 +45,9 @@ pub struct DbgMacro {
|
|||
impl_lint_pass!(DbgMacro => [DBG_MACRO]);
|
||||
|
||||
impl DbgMacro {
|
||||
pub fn new(allow_dbg_in_tests: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
DbgMacro {
|
||||
allow_dbg_in_tests,
|
||||
allow_dbg_in_tests: conf.allow_dbg_in_tests,
|
||||
checked_dbg_call_site: FxHashSet::default(),
|
||||
prev_ctxt: SyntaxContext::root(),
|
||||
}
|
||||
|
|
|
@ -598,6 +598,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
|
||||
crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
|
||||
crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
|
||||
crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO,
|
||||
crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
|
||||
crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
|
||||
crate::precedence::PRECEDENCE_INFO,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::indent_of;
|
||||
use clippy_utils::{is_default_equivalent, peel_blocks};
|
||||
|
@ -60,9 +61,10 @@ pub struct DerivableImpls {
|
|||
}
|
||||
|
||||
impl DerivableImpls {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
DerivableImpls { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
DerivableImpls {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::types::DisallowedPath;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::create_disallowed_map;
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
use rustc_ast::Attribute;
|
||||
|
@ -9,6 +10,7 @@ use rustc_hir::{
|
|||
Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{ExpnId, MacroKind, Span};
|
||||
|
||||
|
@ -57,27 +59,24 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
pub struct DisallowedMacros {
|
||||
conf_disallowed: Vec<DisallowedPath>,
|
||||
disallowed: DefIdMap<usize>,
|
||||
disallowed: DefIdMap<(&'static str, Option<&'static str>)>,
|
||||
seen: FxHashSet<ExpnId>,
|
||||
|
||||
// Track the most recently seen node that can have a `derive` attribute.
|
||||
// Needed to use the correct lint level.
|
||||
derive_src: Option<OwnerId>,
|
||||
}
|
||||
|
||||
impl DisallowedMacros {
|
||||
pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
conf_disallowed,
|
||||
disallowed: DefIdMap::default(),
|
||||
disallowed: create_disallowed_map(tcx, &conf.disallowed_macros),
|
||||
seen: FxHashSet::default(),
|
||||
derive_src: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option<OwnerId>) {
|
||||
if self.conf_disallowed.is_empty() {
|
||||
if self.disallowed.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -86,11 +85,10 @@ impl DisallowedMacros {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(&index) = self.disallowed.get(&mac.def_id) {
|
||||
let conf = &self.conf_disallowed[index];
|
||||
let msg = format!("use of a disallowed macro `{}`", conf.path());
|
||||
if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) {
|
||||
let msg = format!("use of a disallowed macro `{path}`");
|
||||
let add_note = |diag: &mut Diag<'_, _>| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
if let Some(reason) = reason {
|
||||
diag.note(reason);
|
||||
}
|
||||
};
|
||||
|
@ -116,15 +114,6 @@ impl DisallowedMacros {
|
|||
impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
|
||||
|
||||
impl LateLintPass<'_> for DisallowedMacros {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
self.check(cx, expr.span, None);
|
||||
// `$t + $t` can have the context of $t, check also the span of the binary operator
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use clippy_config::types::DisallowedPath;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::create_disallowed_map;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -55,17 +57,14 @@ declare_clippy_lint! {
|
|||
"use of a disallowed method call"
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedMethods {
|
||||
conf_disallowed: Vec<DisallowedPath>,
|
||||
disallowed: DefIdMap<usize>,
|
||||
disallowed: DefIdMap<(&'static str, Option<&'static str>)>,
|
||||
}
|
||||
|
||||
impl DisallowedMethods {
|
||||
pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
conf_disallowed,
|
||||
disallowed: DefIdMap::default(),
|
||||
disallowed: create_disallowed_map(tcx, &conf.disallowed_methods),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,15 +72,6 @@ impl DisallowedMethods {
|
|||
impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (id, span) = match &expr.kind {
|
||||
ExprKind::Path(path)
|
||||
|
@ -95,14 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
|||
},
|
||||
_ => return,
|
||||
};
|
||||
if let Some(&index) = self.disallowed.get(&id) {
|
||||
let conf = &self.conf_disallowed[index];
|
||||
let msg = format!("use of a disallowed method `{}`", conf.path());
|
||||
span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(reason);
|
||||
}
|
||||
});
|
||||
if let Some(&(path, reason)) = self.disallowed.get(&id) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DISALLOWED_METHODS,
|
||||
span,
|
||||
format!("use of a disallowed method `{path}`"),
|
||||
|diag| {
|
||||
if let Some(reason) = reason {
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_in_test;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::{Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -24,15 +26,14 @@ declare_clippy_lint! {
|
|||
"usage of a disallowed/placeholder name"
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedNames {
|
||||
disallow: FxHashSet<String>,
|
||||
disallow: FxHashSet<Symbol>,
|
||||
}
|
||||
|
||||
impl DisallowedNames {
|
||||
pub fn new(disallowed_names: &[String]) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
disallow: disallowed_names.iter().cloned().collect(),
|
||||
disallow: conf.disallowed_names.iter().map(|x| Symbol::intern(x)).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +43,7 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
|
|||
impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
|
||||
if let PatKind::Binding(.., ident, _) = pat.kind
|
||||
&& self.disallow.contains(&ident.name.to_string())
|
||||
&& self.disallow.contains(&ident.name)
|
||||
&& !is_in_test(cx.tcx, pat.hir_id)
|
||||
{
|
||||
span_lint(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
@ -44,19 +45,20 @@ declare_clippy_lint! {
|
|||
"usage of non-allowed Unicode scripts"
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedScriptIdents {
|
||||
whitelist: FxHashSet<Script>,
|
||||
}
|
||||
|
||||
impl DisallowedScriptIdents {
|
||||
pub fn new(whitelist: &[String]) -> Self {
|
||||
let whitelist = whitelist
|
||||
.iter()
|
||||
.map(String::as_str)
|
||||
.filter_map(Script::from_full_name)
|
||||
.collect();
|
||||
Self { whitelist }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
whitelist: conf
|
||||
.allowed_scripts
|
||||
.iter()
|
||||
.map(String::as_str)
|
||||
.filter_map(Script::from_full_name)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use clippy_config::types::DisallowedPath;
|
||||
use clippy_config::Conf;
|
||||
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;
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
@ -49,60 +50,56 @@ declare_clippy_lint! {
|
|||
"use of disallowed types"
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedTypes {
|
||||
conf_disallowed: Vec<DisallowedPath>,
|
||||
def_ids: FxHashMap<DefId, usize>,
|
||||
prim_tys: FxHashMap<PrimTy, usize>,
|
||||
def_ids: DefIdMap<(&'static str, Option<&'static str>)>,
|
||||
prim_tys: FxHashMap<PrimTy, (&'static str, Option<&'static str>)>,
|
||||
}
|
||||
|
||||
impl DisallowedTypes {
|
||||
pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
|
||||
Self {
|
||||
conf_disallowed,
|
||||
def_ids: FxHashMap::default(),
|
||||
prim_tys: FxHashMap::default(),
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
let mut def_ids = DefIdMap::default();
|
||||
let mut prim_tys = FxHashMap::default();
|
||||
for x in &conf.disallowed_types {
|
||||
let path: Vec<_> = x.path().split("::").collect::<Vec<_>>();
|
||||
let reason = x.reason();
|
||||
for res in clippy_utils::def_path_res(tcx, &path) {
|
||||
match res {
|
||||
Res::Def(_, id) => {
|
||||
def_ids.insert(id, (x.path(), reason));
|
||||
},
|
||||
Res::PrimTy(ty) => {
|
||||
prim_tys.insert(ty, (x.path(), reason));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
Self { def_ids, prim_tys }
|
||||
}
|
||||
|
||||
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
|
||||
match res {
|
||||
Res::Def(_, did) => {
|
||||
if let Some(&index) = self.def_ids.get(did) {
|
||||
emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
|
||||
let (path, reason) = match res {
|
||||
Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x,
|
||||
Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x,
|
||||
_ => return,
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DISALLOWED_TYPES,
|
||||
span,
|
||||
format!("use of a disallowed type `{path}`"),
|
||||
|diag| {
|
||||
if let Some(reason) = reason {
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
Res::PrimTy(prim) => {
|
||||
if let Some(&index) = self.prim_tys.get(prim) {
|
||||
emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
|
||||
for res in clippy_utils::def_path_res(cx, &segs) {
|
||||
match res {
|
||||
Res::Def(_, id) => {
|
||||
self.def_ids.insert(id, index);
|
||||
},
|
||||
Res::PrimTy(ty) => {
|
||||
self.prim_tys.insert(ty, index);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
|
||||
for res in &path.res {
|
||||
|
@ -121,17 +118,3 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
|||
self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DISALLOWED_TYPES,
|
||||
span,
|
||||
format!("`{name}` is not allowed according to config"),
|
||||
|diag| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod lazy_continuation;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
|
@ -421,17 +422,16 @@ declare_clippy_lint! {
|
|||
"require every line of a paragraph to be indented and marked"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Documentation {
|
||||
valid_idents: FxHashSet<String>,
|
||||
valid_idents: &'static FxHashSet<String>,
|
||||
check_private_items: bool,
|
||||
}
|
||||
|
||||
impl Documentation {
|
||||
pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
valid_idents: valid_idents.iter().cloned().collect(),
|
||||
check_private_items,
|
||||
valid_idents: &conf.doc_valid_idents,
|
||||
check_private_items: conf.check_private_items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -452,7 +452,7 @@ impl_lint_pass!(Documentation => [
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for Documentation {
|
||||
fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
|
||||
let Some(headers) = check_attrs(cx, self.valid_idents, attrs) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -40,35 +40,29 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]);
|
|||
|
||||
impl EarlyLintPass for DoubleParens {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg: &str = "consider removing unnecessary double parentheses";
|
||||
|
||||
match expr.kind {
|
||||
ExprKind::Paren(ref in_paren) => match in_paren.kind {
|
||||
ExprKind::Paren(_) | ExprKind::Tup(_) => {
|
||||
span_lint(cx, DOUBLE_PARENS, expr.span, msg);
|
||||
},
|
||||
_ => {},
|
||||
let span = match &expr.kind {
|
||||
ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span,
|
||||
ExprKind::Call(_, params)
|
||||
if let [param] = &**params
|
||||
&& let ExprKind::Paren(_) = param.kind =>
|
||||
{
|
||||
param.span
|
||||
},
|
||||
ExprKind::Call(_, ref params) => {
|
||||
if params.len() == 1 {
|
||||
let param = ¶ms[0];
|
||||
if let ExprKind::Paren(_) = param.kind {
|
||||
span_lint(cx, DOUBLE_PARENS, param.span, msg);
|
||||
}
|
||||
}
|
||||
ExprKind::MethodCall(call)
|
||||
if let [arg] = &*call.args
|
||||
&& let ExprKind::Paren(_) = arg.kind =>
|
||||
{
|
||||
arg.span
|
||||
},
|
||||
ExprKind::MethodCall(ref call) => {
|
||||
if let [ref arg] = call.args[..] {
|
||||
if let ExprKind::Paren(_) = arg.kind {
|
||||
span_lint(cx, DOUBLE_PARENS, arg.span, msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
_ => return,
|
||||
};
|
||||
if !expr.span.from_expansion() {
|
||||
span_lint(
|
||||
cx,
|
||||
DOUBLE_PARENS,
|
||||
span,
|
||||
"consider removing unnecessary double parentheses",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,12 +50,9 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
|
|||
|
||||
impl EarlyLintPass for ElseIfWithoutElse {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::If(_, _, Some(ref els)) = item.kind
|
||||
&& let ExprKind::If(_, _, None) = els.kind
|
||||
&& !in_external_macro(cx.sess(), item.span)
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
|
|
@ -64,25 +64,21 @@ declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
// Only suggest the `never_type` if the feature is enabled
|
||||
if !cx.tcx.features().never_type {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ItemKind::Enum(..) = item.kind {
|
||||
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
|
||||
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
|
||||
if adt.variants().is_empty() {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
EMPTY_ENUM,
|
||||
item.span,
|
||||
"enum with no variants",
|
||||
None,
|
||||
"consider using the uninhabited type `!` (never type) or a wrapper \
|
||||
around it to introduce a type which can't be instantiated",
|
||||
);
|
||||
}
|
||||
if let ItemKind::Enum(..) = item.kind
|
||||
// Only suggest the `never_type` if the feature is enabled
|
||||
&& cx.tcx.features().never_type
|
||||
&& let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def()
|
||||
&& adt.variants().is_empty()
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
EMPTY_ENUM,
|
||||
item.span,
|
||||
"enum with no variants",
|
||||
None,
|
||||
"consider using the uninhabited type `!` (never type) or a wrapper \
|
||||
around it to introduce a type which can't be instantiated",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,32 +109,27 @@ impl LintKind {
|
|||
|
||||
impl LateLintPass<'_> for EndianBytes {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind
|
||||
&& args.is_empty()
|
||||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||
&& ty.is_primitive_ty()
|
||||
&& maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::Call(function, ..) = expr.kind
|
||||
&& let ExprKind::Path(qpath) = function.kind
|
||||
&& let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id()
|
||||
&& let Some(function_name) = cx.get_def_path(def_id).last()
|
||||
&& let ty = cx.typeck_results().expr_ty(expr)
|
||||
let (prefix, name, ty_expr) = match expr.kind {
|
||||
ExprKind::MethodCall(method_name, receiver, [], ..) => (Prefix::To, method_name.ident.name, receiver),
|
||||
ExprKind::Call(function, ..)
|
||||
if let ExprKind::Path(qpath) = function.kind
|
||||
&& let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id()
|
||||
&& let Some(function_name) = cx.get_def_path(def_id).last() =>
|
||||
{
|
||||
(Prefix::From, *function_name, expr)
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
if !in_external_macro(cx.sess(), expr.span)
|
||||
&& let ty = cx.typeck_results().expr_ty(ty_expr)
|
||||
&& ty.is_primitive_ty()
|
||||
{
|
||||
maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty);
|
||||
maybe_lint_endian_bytes(cx, expr, prefix, name, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool {
|
||||
fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) {
|
||||
let ne = LintKind::Host.as_name(prefix);
|
||||
let le = LintKind::Little.as_name(prefix);
|
||||
let be = LintKind::Big.as_name(prefix);
|
||||
|
@ -143,7 +138,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
|
|||
name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]),
|
||||
name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]),
|
||||
name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
|
||||
_ => return false,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let mut help = None;
|
||||
|
@ -208,6 +203,4 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
|
|||
|
||||
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
|
||||
if let ExprKind::Let(let_expr) = expr.kind
|
||||
&& unary_pattern(let_expr.pat)
|
||||
&& !in_external_macro(cx.sess(), expr.span)
|
||||
{
|
||||
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
|
||||
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
|
||||
|
|
|
@ -36,15 +36,12 @@ declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else {
|
||||
return;
|
||||
};
|
||||
|
||||
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()
|
||||
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
|
||||
&& implements_trait(cx, ty, error_def_id, &[]) =>
|
||||
{
|
||||
span_lint(
|
||||
|
@ -56,9 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
|
|||
},
|
||||
ItemKind::Impl(imp)
|
||||
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
|
||||
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
|
||||
&& 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.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) =>
|
||||
|
@ -66,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
|
|||
span_lint_hir_and_then(
|
||||
cx,
|
||||
ERROR_IMPL_ERROR,
|
||||
hir_id,
|
||||
cx.tcx.local_def_id_to_hir_id(def_id),
|
||||
ident.span,
|
||||
"exported type named `Error` that implements `Error`",
|
||||
|diag| {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir;
|
||||
use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
|
||||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
|
@ -11,9 +12,16 @@ use rustc_span::symbol::kw;
|
|||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct BoxedLocal {
|
||||
pub too_large_for_stack: u64,
|
||||
too_large_for_stack: u64,
|
||||
}
|
||||
|
||||
impl BoxedLocal {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
too_large_for_stack: conf.too_large_for_stack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
|
@ -87,69 +88,57 @@ pub struct ExcessiveBools {
|
|||
max_fn_params_bools: u64,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
enum Kind {
|
||||
Struct,
|
||||
Fn,
|
||||
}
|
||||
|
||||
impl ExcessiveBools {
|
||||
#[must_use]
|
||||
pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
max_struct_bools,
|
||||
max_fn_params_bools,
|
||||
}
|
||||
}
|
||||
|
||||
fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, kind: Kind) -> bool {
|
||||
if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() {
|
||||
(if Kind::Fn == kind {
|
||||
self.max_fn_params_bools
|
||||
} else {
|
||||
self.max_struct_bools
|
||||
}) < bools
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
|
||||
if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
FN_PARAMS_EXCESSIVE_BOOLS,
|
||||
span,
|
||||
format!("more than {} bools in function parameters", self.max_fn_params_bools),
|
||||
None,
|
||||
"consider refactoring bools into two-variant enums",
|
||||
);
|
||||
max_struct_bools: conf.max_struct_bools,
|
||||
max_fn_params_bools: conf.max_fn_params_bools,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
|
||||
|
||||
fn has_n_bools<'tcx>(iter: impl Iterator<Item = &'tcx Ty<'tcx>>, mut count: u64) -> bool {
|
||||
iter.filter(|ty| is_bool(ty)).any(|_| {
|
||||
let (x, overflow) = count.overflowing_sub(1);
|
||||
count = x;
|
||||
overflow
|
||||
})
|
||||
}
|
||||
|
||||
fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) {
|
||||
if has_n_bools(decl.inputs.iter(), max) && !sp.from_expansion() {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
FN_PARAMS_EXCESSIVE_BOOLS,
|
||||
sp,
|
||||
format!("more than {max} bools in function parameters"),
|
||||
None,
|
||||
"consider refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if item.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let ItemKind::Struct(variant_data, _) = &item.kind {
|
||||
if has_repr_attr(cx, item.hir_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
STRUCT_EXCESSIVE_BOOLS,
|
||||
item.span,
|
||||
format!("more than {} bools in a struct", self.max_struct_bools),
|
||||
None,
|
||||
"consider using a state machine or refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
if let ItemKind::Struct(variant_data, _) = &item.kind
|
||||
&& variant_data.fields().len() as u64 > self.max_struct_bools
|
||||
&& has_n_bools(
|
||||
variant_data.fields().iter().map(|field| field.ty),
|
||||
self.max_struct_bools,
|
||||
)
|
||||
&& !has_repr_attr(cx, item.hir_id())
|
||||
&& !item.span.from_expansion()
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
STRUCT_EXCESSIVE_BOOLS,
|
||||
item.span,
|
||||
format!("more than {} bools in a struct", self.max_struct_bools),
|
||||
None,
|
||||
"consider using a state machine or refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,8 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
|||
// 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
|
||||
&& fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools
|
||||
{
|
||||
self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
|
||||
check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,12 +161,13 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
|||
span: Span,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let hir_id = cx.tcx.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())
|
||||
&& fn_decl.inputs.len() as u64 > self.max_fn_params_bools
|
||||
&& get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id))
|
||||
.map_or(true, |impl_item| impl_item.of_trait.is_none())
|
||||
{
|
||||
self.check_fn_sig(cx, fn_decl, span);
|
||||
check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_ast::node_id::NodeSet;
|
||||
|
@ -63,13 +64,19 @@ declare_clippy_lint! {
|
|||
}
|
||||
impl_lint_pass!(ExcessiveNesting => [EXCESSIVE_NESTING]);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExcessiveNesting {
|
||||
pub excessive_nesting_threshold: u64,
|
||||
pub nodes: NodeSet,
|
||||
}
|
||||
|
||||
impl ExcessiveNesting {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
excessive_nesting_threshold: conf.excessive_nesting_threshold,
|
||||
nodes: NodeSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_node_id(&self, cx: &EarlyContext<'_>, span: Span, node_id: NodeId) {
|
||||
if self.nodes.contains(&node_id) {
|
||||
span_lint_and_help(
|
||||
|
|
|
@ -70,20 +70,24 @@ declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
|
|||
|
||||
impl LateLintPass<'_> for ExhaustiveItems {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind
|
||||
&& cx.effective_visibilities.is_exported(item.owner_id.def_id)
|
||||
let (lint, msg, fields) = match item.kind {
|
||||
ItemKind::Enum(..) => (
|
||||
EXHAUSTIVE_ENUMS,
|
||||
"exported enums should not be exhaustive",
|
||||
[].as_slice(),
|
||||
),
|
||||
ItemKind::Struct(v, ..) => (
|
||||
EXHAUSTIVE_STRUCTS,
|
||||
"exported structs should not be exhaustive",
|
||||
v.fields(),
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
if cx.effective_visibilities.is_exported(item.owner_id.def_id)
|
||||
&& let attrs = cx.tcx.hir().attrs(item.hir_id())
|
||||
&& !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
|
||||
&& fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
|
||||
{
|
||||
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
|
||||
if v.fields().iter().any(|f| !cx.tcx.visibility(f.def_id).is_public()) {
|
||||
// skip structs with private fields
|
||||
return;
|
||||
}
|
||||
(EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
|
||||
} else {
|
||||
(EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
|
||||
};
|
||||
let suggestion_span = item.span.shrink_to_lo();
|
||||
let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
|
||||
span_lint_and_then(cx, lint, item.span, msg, |diag| {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_entrypoint_fn;
|
||||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
|
||||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, OwnerNode};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::sym;
|
||||
|
@ -47,8 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
|
|||
&& let ExprKind::Path(ref path) = path_expr.kind
|
||||
&& let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id()
|
||||
&& cx.tcx.is_diagnostic_item(sym::process_exit, def_id)
|
||||
&& let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id
|
||||
&& let Node::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_node_by_def_id(parent)
|
||||
&& let parent = cx.tcx.hir().get_parent_item(e.hir_id)
|
||||
&& let OwnerNode::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_owner_node(parent)
|
||||
// If the next item up is a function we check if it is an entry point
|
||||
// and only then emit a linter warning
|
||||
&& !is_entrypoint_fn(cx, parent.to_def_id())
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::{is_from_proc_macro, trait_ref_of_method};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
@ -45,26 +46,11 @@ pub struct ExtraUnusedTypeParameters {
|
|||
}
|
||||
|
||||
impl ExtraUnusedTypeParameters {
|
||||
pub fn new(avoid_breaking_exported_api: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
avoid_breaking_exported_api,
|
||||
avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
|
||||
}
|
||||
}
|
||||
|
||||
/// Don't lint external macros or functions with empty bodies. Also, don't lint exported items
|
||||
/// if the `avoid_breaking_exported_api` config option is set.
|
||||
fn is_empty_exported_or_macro(
|
||||
&self,
|
||||
cx: &LateContext<'_>,
|
||||
span: Span,
|
||||
def_id: LocalDefId,
|
||||
body_id: BodyId,
|
||||
) -> bool {
|
||||
let body = cx.tcx.hir().body(body_id).value;
|
||||
let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
|
||||
let is_exported = cx.effective_visibilities.is_exported(def_id);
|
||||
in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api)
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
|
||||
|
@ -266,10 +252,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool {
|
||||
matches!(cx.tcx.hir().body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none())
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Fn(_, generics, body_id) = item.kind
|
||||
&& !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
|
||||
&& !generics.params.is_empty()
|
||||
&& !is_empty_body(cx, body_id)
|
||||
&& (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
|
||||
&& !in_external_macro(cx.sess(), item.span)
|
||||
&& !is_from_proc_macro(cx, item)
|
||||
{
|
||||
let mut walker = TypeWalker::new(cx, generics);
|
||||
|
@ -281,8 +274,12 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
|||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
|
||||
// Only lint on inherent methods, not trait methods.
|
||||
if let ImplItemKind::Fn(.., body_id) = item.kind
|
||||
&& !item.generics.params.is_empty()
|
||||
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||
&& !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
|
||||
&& !is_empty_body(cx, body_id)
|
||||
&& (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
|
||||
&& !in_external_macro(cx.sess(), item.span)
|
||||
&& !is_from_proc_macro(cx, item)
|
||||
{
|
||||
let mut walker = TypeWalker::new(cx, item.generics);
|
||||
walk_impl_item(&mut walker, item);
|
||||
|
|
|
@ -62,10 +62,9 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if let ty::Float(fty) = *ty.kind()
|
||||
&& let hir::ExprKind::Lit(lit) = expr.kind
|
||||
if let hir::ExprKind::Lit(lit) = expr.kind
|
||||
&& let LitKind::Float(sym, lit_float_ty) = lit.node
|
||||
&& let ty::Float(fty) = *cx.typeck_results().expr_ty(expr).kind()
|
||||
{
|
||||
let sym_str = sym.as_str();
|
||||
let formatter = FloatFormat::new(sym_str);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use arrayvec::ArrayVec;
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::is_diag_trait_item;
|
||||
use clippy_utils::macros::{
|
||||
|
@ -175,12 +176,11 @@ pub struct FormatArgs {
|
|||
}
|
||||
|
||||
impl FormatArgs {
|
||||
#[must_use]
|
||||
pub fn new(format_args: FormatArgsStorage, msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
|
||||
Self {
|
||||
format_args,
|
||||
msrv,
|
||||
ignore_mixed: allow_mixed_uninlined_format_args,
|
||||
msrv: conf.msrv.clone(),
|
||||
ignore_mixed: conf.allow_mixed_uninlined_format_args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,6 @@ struct FormatTraitNames {
|
|||
formatter_name: Option<Symbol>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatImpl {
|
||||
format_args: FormatArgsStorage,
|
||||
// Whether we are inside Display or Debug trait impl - None for neither
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::span_is_local;
|
||||
use clippy_utils::path_def_id;
|
||||
|
@ -54,9 +55,10 @@ pub struct FromOverInto {
|
|||
}
|
||||
|
||||
impl FromOverInto {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
FromOverInto { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
FromOverInto {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,10 +66,6 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(hir_trait_ref),
|
||||
self_ty,
|
||||
|
@ -77,6 +75,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
|||
&& let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
|
||||
// `impl Into<target_ty> for self_ty`
|
||||
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
|
||||
&& self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE)
|
||||
&& span_is_local(item.span)
|
||||
&& let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
|
||||
.map(ty::EarlyBinder::instantiate_identity)
|
||||
&& cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
|
||||
|
@ -181,6 +181,9 @@ fn convert_to_from(
|
|||
let from = snippet_opt(cx, self_ty.span)?;
|
||||
let into = snippet_opt(cx, target_ty.span)?;
|
||||
|
||||
let return_type = matches!(sig.decl.output, FnRetTy::Return(_))
|
||||
.then_some(String::from("Self"))
|
||||
.unwrap_or_default();
|
||||
let mut suggestions = vec![
|
||||
// impl Into<T> for U -> impl From<T> for U
|
||||
// ~~~~ ~~~~
|
||||
|
@ -197,13 +200,10 @@ fn convert_to_from(
|
|||
// fn into([mut] self) -> T -> fn into([mut] v: T) -> T
|
||||
// ~~~~ ~~~~
|
||||
(self_ident.span, format!("val: {from}")),
|
||||
];
|
||||
|
||||
if let FnRetTy::Return(_) = sig.decl.output {
|
||||
// fn into(self) -> T -> fn into(self) -> Self
|
||||
// ~ ~~~~
|
||||
suggestions.push((sig.decl.output.span(), String::from("Self")));
|
||||
}
|
||||
(sig.decl.output.span(), return_type),
|
||||
];
|
||||
|
||||
let mut finder = SelfFinder {
|
||||
cx,
|
||||
|
|
|
@ -47,9 +47,13 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
|||
fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
|
||||
if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind
|
||||
// do not lint in constant context, because the suggestion won't work.
|
||||
// NB: keep this check until a new `const_trait_impl` is available and stablized.
|
||||
&& !in_constant(cx, exp.hir_id)
|
||||
|
||||
// check if the second argument is a primitive `10`
|
||||
&& is_integer_literal(radix, 10)
|
||||
|
||||
// check if the second part of the path indeed calls the associated
|
||||
// function `from_str_radix`
|
||||
&& pathseg.ident.name.as_str() == "from_str_radix"
|
||||
|
||||
// check if the first part of the path is some integer primitive
|
||||
&& let TyKind::Path(ty_qpath) = &ty.kind
|
||||
|
@ -57,12 +61,9 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
|||
&& let def::Res::PrimTy(prim_ty) = ty_res
|
||||
&& matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_))
|
||||
|
||||
// check if the second part of the path indeed calls the associated
|
||||
// function `from_str_radix`
|
||||
&& pathseg.ident.name.as_str() == "from_str_radix"
|
||||
|
||||
// check if the second argument is a primitive `10`
|
||||
&& is_integer_literal(radix, 10)
|
||||
// do not lint in constant context, because the suggestion won't work.
|
||||
// NB: keep this check until a new `const_trait_impl` is available and stablized.
|
||||
&& !in_constant(cx, exp.hir_id)
|
||||
{
|
||||
let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
|
|
|
@ -7,10 +7,12 @@ mod result;
|
|||
mod too_many_arguments;
|
||||
mod too_many_lines;
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::def_path_def_ids;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::def_id::{DefIdSet, LocalDefId};
|
||||
use rustc_span::Span;
|
||||
|
@ -391,39 +393,34 @@ declare_clippy_lint! {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.74.0"]
|
||||
#[clippy::version = "1.80.0"]
|
||||
pub RENAMED_FUNCTION_PARAMS,
|
||||
restriction,
|
||||
"renamed function parameters in trait implementation"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Functions {
|
||||
too_many_arguments_threshold: u64,
|
||||
too_many_lines_threshold: u64,
|
||||
large_error_threshold: u64,
|
||||
avoid_breaking_exported_api: bool,
|
||||
allow_renamed_params_for: Vec<String>,
|
||||
/// A set of resolved `def_id` of traits that are configured to allow
|
||||
/// function params renaming.
|
||||
trait_ids: DefIdSet,
|
||||
}
|
||||
|
||||
impl Functions {
|
||||
pub fn new(
|
||||
too_many_arguments_threshold: u64,
|
||||
too_many_lines_threshold: u64,
|
||||
large_error_threshold: u64,
|
||||
avoid_breaking_exported_api: bool,
|
||||
allow_renamed_params_for: Vec<String>,
|
||||
) -> Self {
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
too_many_arguments_threshold,
|
||||
too_many_lines_threshold,
|
||||
large_error_threshold,
|
||||
avoid_breaking_exported_api,
|
||||
allow_renamed_params_for,
|
||||
trait_ids: DefIdSet::default(),
|
||||
too_many_arguments_threshold: conf.too_many_arguments_threshold,
|
||||
too_many_lines_threshold: conf.too_many_lines_threshold,
|
||||
large_error_threshold: conf.large_error_threshold,
|
||||
avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
|
||||
trait_ids: conf
|
||||
.allow_renamed_params_for
|
||||
.iter()
|
||||
.flat_map(|p| def_path_def_ids(tcx, &p.split("::").collect::<Vec<_>>()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -479,12 +476,4 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
|||
result::check_trait_item(cx, item, self.large_error_threshold);
|
||||
impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
|
||||
}
|
||||
|
||||
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||
for path in &self.allow_renamed_params_for {
|
||||
let path_segments: Vec<&str> = path.split("::").collect();
|
||||
let ids = def_path_def_ids(cx, &path_segments);
|
||||
self.trait_ids.extend(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,15 +66,11 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
|||
let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
|
||||
if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
|
||||
let preds = cx.tcx.explicit_item_super_predicates(def_id);
|
||||
let mut is_future = false;
|
||||
for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
|
||||
if let Some(trait_pred) = p.as_trait_clause() {
|
||||
if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
|
||||
is_future = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
|
||||
p.as_trait_clause().is_some_and(|trait_pred| {
|
||||
Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait()
|
||||
})
|
||||
});
|
||||
if is_future {
|
||||
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
||||
let span = decl.output.span();
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{higher, SpanlessEq};
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir::intravisit::{self as visit, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
@ -44,8 +45,6 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
let mut arm_visit = ArmVisitor { found_mutex: None, cx };
|
||||
let mut op_visit = OppVisitor { found_mutex: None, cx };
|
||||
if let Some(higher::IfLet {
|
||||
let_expr,
|
||||
if_then,
|
||||
|
@ -53,12 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
|||
..
|
||||
}) = higher::IfLet::hir(cx, expr)
|
||||
{
|
||||
op_visit.visit_expr(let_expr);
|
||||
if let Some(op_mutex) = op_visit.found_mutex {
|
||||
arm_visit.visit_expr(if_then);
|
||||
arm_visit.visit_expr(if_else);
|
||||
let is_mutex_lock = |e: &'tcx Expr<'tcx>| {
|
||||
if let Some(mutex) = is_mutex_lock_call(cx, e) {
|
||||
ControlFlow::Break(mutex)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) {
|
||||
let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock);
|
||||
if let Some(op_mutex) = op_mutex {
|
||||
let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock);
|
||||
if let Some(arm_mutex) = arm_mutex
|
||||
&& SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)
|
||||
{
|
||||
let diag = |diag: &mut Diag<'_, ()>| {
|
||||
diag.span_label(
|
||||
op_mutex.span,
|
||||
|
@ -83,48 +90,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if `Mutex::lock` is called in the `if let` expr.
|
||||
pub struct OppVisitor<'a, 'tcx> {
|
||||
found_mutex: Option<&'tcx Expr<'tcx>>,
|
||||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
|
||||
self.found_mutex = Some(mutex);
|
||||
return;
|
||||
}
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `Mutex::lock` is called in any of the branches.
|
||||
pub struct ArmVisitor<'a, 'tcx> {
|
||||
found_mutex: Option<&'tcx Expr<'tcx>>,
|
||||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
|
||||
self.found_mutex = Some(mutex);
|
||||
return;
|
||||
}
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
|
||||
fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> {
|
||||
self.found_mutex.and_then(|arm_mutex| {
|
||||
SpanlessEq::new(self.cx)
|
||||
.eq_expr(op_mutex, arm_mutex)
|
||||
.then_some(arm_mutex)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
|
||||
&& path.ident.as_str() == "lock"
|
||||
|
|
|
@ -56,44 +56,33 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
|
|||
}
|
||||
|
||||
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.
|
||||
// To fix this, return early if this span comes from a macro or desugaring.
|
||||
if item.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::If(cond, _, Some(els)) = item.kind {
|
||||
if let ExprKind::Block(..) = els.kind {
|
||||
// Disable firing the lint in "else if" expressions.
|
||||
if is_else_clause(cx.tcx, item) {
|
||||
return;
|
||||
}
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
|
||||
if let ExprKind::If(cond, _, Some(els)) = e.kind
|
||||
&& let ExprKind::DropTemps(cond) = cond.kind
|
||||
&& let ExprKind::Block(..) = els.kind
|
||||
{
|
||||
let (msg, help) = match cond.kind {
|
||||
ExprKind::Unary(UnOp::Not, _) => (
|
||||
"unnecessary boolean `not` operation",
|
||||
"remove the `!` and swap the blocks of the `if`/`else`",
|
||||
),
|
||||
// Don't lint on `… != 0`, as these are likely to be bit tests.
|
||||
// For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order.
|
||||
ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => (
|
||||
"unnecessary `!=` operation",
|
||||
"change to `==` and swap the blocks of the `if`/`else`",
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
match cond.peel_drop_temps().kind {
|
||||
ExprKind::Unary(UnOp::Not, _) => {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
IF_NOT_ELSE,
|
||||
item.span,
|
||||
"unnecessary boolean `not` operation",
|
||||
None,
|
||||
"remove the `!` and swap the blocks of the `if`/`else`",
|
||||
);
|
||||
},
|
||||
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,
|
||||
item.span,
|
||||
"unnecessary `!=` operation",
|
||||
None,
|
||||
"change to `==` and swap the blocks of the `if`/`else`",
|
||||
);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
// `from_expansion` will also catch `while` loops which appear in the HIR as:
|
||||
// ```rust
|
||||
// loop {
|
||||
// if cond { ... } else { break; }
|
||||
// }
|
||||
// ```
|
||||
if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) {
|
||||
span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
|
@ -51,9 +52,10 @@ pub struct IfThenSomeElseNone {
|
|||
}
|
||||
|
||||
impl IfThenSomeElseNone {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,26 +63,6 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if !self.msrv.meets(msrvs::BOOL_THEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only care about the top-most `if` in the chain
|
||||
if is_else_clause(cx.tcx, expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// `bool::then()` and `bool::then_some()` are not const
|
||||
if in_constant(cx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ctxt = expr.span.ctxt();
|
||||
|
||||
if let Some(higher::If {
|
||||
cond,
|
||||
then,
|
||||
|
@ -89,9 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
|||
&& let ExprKind::Block(then_block, _) = then.kind
|
||||
&& let Some(then_expr) = then_block.expr
|
||||
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
|
||||
&& let ctxt = expr.span.ctxt()
|
||||
&& then_expr.span.ctxt() == ctxt
|
||||
&& is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
|
||||
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
|
||||
&& !is_else_clause(cx.tcx, expr)
|
||||
&& !in_constant(cx, expr.hir_id)
|
||||
&& !in_external_macro(cx.sess(), expr.span)
|
||||
&& self.msrv.meets(msrvs::BOOL_THEN)
|
||||
&& !contains_return(then_block.stmts)
|
||||
{
|
||||
let mut app = Applicability::Unspecified;
|
||||
|
|
|
@ -37,22 +37,21 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
|
||||
if pat.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
match cx.tcx.parent_hir_node(pat.hir_id) {
|
||||
Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
|
||||
// Ignore function parameters
|
||||
return;
|
||||
},
|
||||
Node::LetStmt(local) if local.ty.is_some() => {
|
||||
// Ignore let bindings with explicit type
|
||||
return;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() {
|
||||
if matches!(pat.kind, PatKind::Wild)
|
||||
&& !pat.span.from_expansion()
|
||||
&& cx.typeck_results().pat_ty(pat).peel_refs().is_unit()
|
||||
{
|
||||
match cx.tcx.parent_hir_node(pat.hir_id) {
|
||||
Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
|
||||
// Ignore function parameters
|
||||
return;
|
||||
},
|
||||
Node::LetStmt(local) if local.ty.is_some() => {
|
||||
// Ignore let bindings with explicit type
|
||||
return;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IGNORED_UNIT_PATTERNS,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::Msrv;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_in_test;
|
||||
use rustc_attr::{StabilityLevel, StableSince};
|
||||
|
@ -47,9 +48,9 @@ pub struct IncompatibleMsrv {
|
|||
impl_lint_pass!(IncompatibleMsrv => [INCOMPATIBLE_MSRV]);
|
||||
|
||||
impl IncompatibleMsrv {
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv,
|
||||
msrv: conf.msrv.clone(),
|
||||
is_above_msrv: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,13 +65,13 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
if !expr.span.from_expansion()
|
||||
&& let ExprKind::Struct(qpath, fields, base) = expr.kind
|
||||
if let ExprKind::Struct(qpath, fields, base) = expr.kind
|
||||
&& fields.iter().all(|f| f.is_shorthand)
|
||||
&& !expr.span.from_expansion()
|
||||
&& let ty = cx.typeck_results().expr_ty(expr)
|
||||
&& let Some(adt_def) = ty.ty_adt_def()
|
||||
&& adt_def.is_struct()
|
||||
&& let Some(variant) = adt_def.variants().iter().next()
|
||||
&& fields.iter().all(|f| f.is_shorthand)
|
||||
{
|
||||
let mut def_order_map = FxHashMap::default();
|
||||
for (idx, field) in variant.fields.iter().enumerate() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLet;
|
||||
|
@ -58,10 +59,10 @@ pub struct IndexRefutableSlice {
|
|||
}
|
||||
|
||||
impl IndexRefutableSlice {
|
||||
pub fn new(max_suggested_slice_pattern_length: u64, msrv: Msrv) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
max_suggested_slice: max_suggested_slice_pattern_length,
|
||||
msrv,
|
||||
max_suggested_slice: conf.max_suggested_slice_pattern_length,
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,8 +71,8 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
|
||||
&& let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
|
||||
if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
|
||||
&& (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
|
||||
&& !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
|
||||
&& self.msrv.meets(msrvs::SLICE_PATTERNS)
|
||||
&& let found_slices = find_slice_values(cx, let_pat)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! lint on indexing and slicing operations
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
|
||||
|
@ -87,28 +88,22 @@ declare_clippy_lint! {
|
|||
|
||||
impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct IndexingSlicing {
|
||||
suppress_restriction_lint_in_const: bool,
|
||||
}
|
||||
|
||||
impl IndexingSlicing {
|
||||
pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
suppress_restriction_lint_in_const,
|
||||
suppress_restriction_lint_in_const: conf.suppress_restriction_lint_in_const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if (self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id))
|
||||
|| is_from_proc_macro(cx, expr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::Index(array, index, _) = &expr.kind
|
||||
&& (!self.suppress_restriction_lint_in_const || !cx.tcx.hir().is_inside_const_context(expr.hir_id))
|
||||
&& let expr_ty = cx.typeck_results().expr_ty(array)
|
||||
&& let mut deref = deref_chain(cx, expr_ty)
|
||||
&& deref.any(|l| {
|
||||
|
@ -116,6 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
|||
|| l.peel_refs().is_array()
|
||||
|| ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr)
|
||||
})
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
{
|
||||
let note = "the suggestion might not be applicable in constant blocks";
|
||||
let ty = cx.typeck_results().expr_ty(array).peel_refs();
|
||||
|
|
|
@ -226,13 +226,14 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
|
|||
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||
match expr.kind {
|
||||
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||
let method_str = method.ident.name.as_str();
|
||||
for &(name, len) in &COMPLETING_METHODS {
|
||||
if method.ident.name.as_str() == name && args.len() == len {
|
||||
if method_str == name && args.len() == len {
|
||||
return is_infinite(cx, receiver);
|
||||
}
|
||||
}
|
||||
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
|
||||
if method.ident.name.as_str() == name && args.len() == len {
|
||||
if method_str == name && args.len() == len {
|
||||
return MaybeInfinite.and(is_infinite(cx, receiver));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
|
@ -68,9 +69,10 @@ pub struct InstantSubtraction {
|
|||
}
|
||||
|
||||
impl InstantSubtraction {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! lint on enum variants that are prefixed or suffixed by the same characters
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
|
||||
use clippy_utils::is_bool;
|
||||
use clippy_utils::macros::span_is_local;
|
||||
|
@ -152,21 +153,14 @@ pub struct ItemNameRepetitions {
|
|||
}
|
||||
|
||||
impl ItemNameRepetitions {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
enum_threshold: u64,
|
||||
struct_threshold: u64,
|
||||
avoid_breaking_exported_api: bool,
|
||||
allow_private_module_inception: bool,
|
||||
allowed_prefixes: &[String],
|
||||
) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
modules: Vec::new(),
|
||||
enum_threshold,
|
||||
struct_threshold,
|
||||
avoid_breaking_exported_api,
|
||||
allow_private_module_inception,
|
||||
allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
|
||||
enum_threshold: conf.enum_variant_name_threshold,
|
||||
struct_threshold: conf.struct_field_name_threshold,
|
||||
avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
|
||||
allow_private_module_inception: conf.allow_private_module_inception,
|
||||
allowed_prefixes: conf.allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
|
@ -32,13 +33,14 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
pub struct LargeConstArrays {
|
||||
maximum_allowed_size: u128,
|
||||
maximum_allowed_size: u64,
|
||||
}
|
||||
|
||||
impl LargeConstArrays {
|
||||
#[must_use]
|
||||
pub fn new(maximum_allowed_size: u128) -> Self {
|
||||
Self { maximum_allowed_size }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
maximum_allowed_size: conf.array_size_threshold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
|||
&& let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
|
||||
&& let element_count = element_count.to_target_usize(cx.tcx)
|
||||
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
|
||||
&& self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
|
||||
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
|
||||
{
|
||||
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
|
||||
let sugg_span = Span::new(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! lint when there is a large size difference between variants on an enum
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo};
|
||||
|
@ -59,16 +60,14 @@ declare_clippy_lint! {
|
|||
"large size difference between variants on an enum"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LargeEnumVariant {
|
||||
maximum_size_difference_allowed: u64,
|
||||
}
|
||||
|
||||
impl LargeEnumVariant {
|
||||
#[must_use]
|
||||
pub fn new(maximum_size_difference_allowed: u64) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
maximum_size_difference_allowed,
|
||||
maximum_size_difference_allowed: conf.enum_variant_size_threshold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
|
@ -39,14 +40,15 @@ declare_clippy_lint! {
|
|||
"large future may lead to unexpected stack overflows"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LargeFuture {
|
||||
future_size_threshold: u64,
|
||||
}
|
||||
|
||||
impl LargeFuture {
|
||||
pub fn new(future_size_threshold: u64) -> Self {
|
||||
Self { future_size_threshold }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
future_size_threshold: conf.future_size_threshold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::macros::root_macro_call_first_node;
|
||||
use rustc_ast::LitKind;
|
||||
|
@ -41,9 +42,10 @@ pub struct LargeIncludeFile {
|
|||
}
|
||||
|
||||
impl LargeIncludeFile {
|
||||
#[must_use]
|
||||
pub fn new(max_file_size: u64) -> Self {
|
||||
Self { max_file_size }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
max_file_size: conf.max_include_file_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
|
@ -27,15 +28,14 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
pub struct LargeStackArrays {
|
||||
maximum_allowed_size: u128,
|
||||
maximum_allowed_size: u64,
|
||||
prev_vec_macro_callsite: Option<Span>,
|
||||
}
|
||||
|
||||
impl LargeStackArrays {
|
||||
#[must_use]
|
||||
pub fn new(maximum_allowed_size: u128) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
maximum_allowed_size,
|
||||
maximum_allowed_size: conf.array_size_threshold,
|
||||
prev_vec_macro_callsite: None,
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
|
|||
})
|
||||
)
|
||||
})
|
||||
&& self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
|
||||
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
@ -106,7 +106,7 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
|
|||
///
|
||||
/// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the
|
||||
/// correct result.
|
||||
fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool {
|
||||
fn repeat_expr_might_be_expanded(expr: &Expr<'_>) -> bool {
|
||||
let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else {
|
||||
return false;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::{fmt, ops};
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::fn_has_unsatisfiable_preds;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
@ -85,10 +86,9 @@ pub struct LargeStackFrames {
|
|||
}
|
||||
|
||||
impl LargeStackFrames {
|
||||
#[must_use]
|
||||
pub fn new(size: u64) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
maximum_allowed_size: size,
|
||||
maximum_allowed_size: conf.stack_size_threshold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::{get_parent_expr, is_from_proc_macro};
|
||||
use hir::def_id::DefId;
|
||||
|
@ -38,9 +39,10 @@ pub struct LegacyNumericConstants {
|
|||
}
|
||||
|
||||
impl LegacyNumericConstants {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(binary_heap_into_iter_sorted)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(f128)]
|
||||
#![feature(f16)]
|
||||
#![feature(if_let_guard)]
|
||||
|
@ -8,7 +9,6 @@
|
|||
#![feature(iter_intersperse)]
|
||||
#![feature(iter_partition_in_place)]
|
||||
#![feature(let_chains)]
|
||||
#![cfg_attr(bootstrap, feature(lint_reasons))]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
@ -288,6 +288,7 @@ mod partial_pub_fields;
|
|||
mod partialeq_ne_impl;
|
||||
mod partialeq_to_none;
|
||||
mod pass_by_ref_or_value;
|
||||
mod pathbuf_init_then_push;
|
||||
mod pattern_type_mismatch;
|
||||
mod permissions_set_readonly_false;
|
||||
mod precedence;
|
||||
|
@ -394,7 +395,6 @@ use clippy_config::{get_configuration_metadata, Conf};
|
|||
use clippy_utils::macros::FormatArgsStorage;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_lint::{Lint, LintId};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Register all pre expansion lints
|
||||
///
|
||||
|
@ -406,9 +406,7 @@ use std::collections::BTreeMap;
|
|||
/// Used in `./src/driver.rs`.
|
||||
pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
||||
// NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
|
||||
let msrv = || conf.msrv.clone();
|
||||
|
||||
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
|
||||
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf)));
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -534,88 +532,6 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
|
|||
/// Used in `./src/driver.rs`.
|
||||
#[expect(clippy::too_many_lines)]
|
||||
pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
||||
let Conf {
|
||||
ref absolute_paths_allowed_crates,
|
||||
absolute_paths_max_segments,
|
||||
accept_comment_above_attributes,
|
||||
accept_comment_above_statement,
|
||||
allow_dbg_in_tests,
|
||||
allow_expect_in_tests,
|
||||
allow_mixed_uninlined_format_args,
|
||||
allow_one_hash_in_raw_strings,
|
||||
allow_panic_in_tests,
|
||||
allow_print_in_tests,
|
||||
allow_private_module_inception,
|
||||
allow_unwrap_in_tests,
|
||||
allow_useless_vec_in_tests,
|
||||
ref allowed_dotfiles,
|
||||
ref allowed_idents_below_min_chars,
|
||||
ref allowed_scripts,
|
||||
ref allowed_wildcard_imports,
|
||||
ref arithmetic_side_effects_allowed_binary,
|
||||
ref arithmetic_side_effects_allowed_unary,
|
||||
ref arithmetic_side_effects_allowed,
|
||||
array_size_threshold,
|
||||
avoid_breaking_exported_api,
|
||||
ref await_holding_invalid_types,
|
||||
cargo_ignore_publish,
|
||||
cognitive_complexity_threshold,
|
||||
ref disallowed_macros,
|
||||
ref disallowed_methods,
|
||||
ref disallowed_names,
|
||||
ref disallowed_types,
|
||||
ref doc_valid_idents,
|
||||
enable_raw_pointer_heuristic_for_send,
|
||||
enforce_iter_loop_reborrow,
|
||||
ref enforced_import_renames,
|
||||
enum_variant_name_threshold,
|
||||
enum_variant_size_threshold,
|
||||
excessive_nesting_threshold,
|
||||
future_size_threshold,
|
||||
ref ignore_interior_mutability,
|
||||
large_error_threshold,
|
||||
literal_representation_threshold,
|
||||
matches_for_let_else,
|
||||
max_fn_params_bools,
|
||||
max_include_file_size,
|
||||
max_struct_bools,
|
||||
max_suggested_slice_pattern_length,
|
||||
max_trait_bounds,
|
||||
min_ident_chars_threshold,
|
||||
missing_docs_in_crate_items,
|
||||
ref msrv,
|
||||
pass_by_value_size_limit,
|
||||
semicolon_inside_block_ignore_singleline,
|
||||
semicolon_outside_block_ignore_multiline,
|
||||
single_char_binding_names_threshold,
|
||||
stack_size_threshold,
|
||||
ref standard_macro_braces,
|
||||
struct_field_name_threshold,
|
||||
suppress_restriction_lint_in_const,
|
||||
too_large_for_stack,
|
||||
too_many_arguments_threshold,
|
||||
too_many_lines_threshold,
|
||||
trivial_copy_size_limit,
|
||||
type_complexity_threshold,
|
||||
unnecessary_box_size,
|
||||
unreadable_literal_lint_fractions,
|
||||
upper_case_acronyms_aggressive,
|
||||
vec_box_size_threshold,
|
||||
verbose_bit_mask_threshold,
|
||||
warn_on_all_wildcard_imports,
|
||||
check_private_items,
|
||||
pub_underscore_fields_behavior,
|
||||
ref allowed_duplicate_crates,
|
||||
allow_comparison_to_zero,
|
||||
ref allowed_prefixes,
|
||||
ref allow_renamed_params_for,
|
||||
|
||||
blacklisted_names: _,
|
||||
cyclomatic_complexity_threshold: _,
|
||||
warn_unsafe_macro_metavars_in_private_macros,
|
||||
} = *conf;
|
||||
let msrv = || msrv.clone();
|
||||
|
||||
register_removed_non_tool_lints(store);
|
||||
register_categories(store);
|
||||
|
||||
|
@ -660,35 +576,12 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
});
|
||||
}
|
||||
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
|
||||
arithmetic_side_effects_allowed
|
||||
.iter()
|
||||
.flat_map(|el| [[el.clone(), "*".to_string()], ["*".to_string(), el.clone()]])
|
||||
.chain(arithmetic_side_effects_allowed_binary.clone())
|
||||
.collect(),
|
||||
arithmetic_side_effects_allowed
|
||||
.iter()
|
||||
.chain(arithmetic_side_effects_allowed_unary.iter())
|
||||
.cloned()
|
||||
.collect(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
|
||||
store.register_late_pass(|_| Box::new(utils::author::Author));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(await_holding_invalid::AwaitHolding::new(
|
||||
await_holding_invalid_types.clone(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |tcx| Box::new(await_holding_invalid::AwaitHolding::new(tcx, conf)));
|
||||
store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(types::Types::new(
|
||||
vec_box_size_threshold,
|
||||
type_complexity_threshold,
|
||||
avoid_breaking_exported_api,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(types::Types::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
|
||||
store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
|
||||
store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
|
||||
|
@ -702,7 +595,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
|
||||
store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
|
||||
store.register_late_pass(|_| Box::new(len_zero::LenZero));
|
||||
store.register_late_pass(move |_| Box::new(attrs::Attributes::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(attrs::Attributes::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions));
|
||||
store.register_late_pass(|_| Box::new(unicode::Unicode));
|
||||
store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
|
||||
|
@ -714,44 +607,30 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
|
||||
store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
|
||||
store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
|
||||
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(conf)));
|
||||
let format_args = format_args_storage.clone();
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(methods::Methods::new(
|
||||
avoid_breaking_exported_api,
|
||||
msrv(),
|
||||
allow_expect_in_tests,
|
||||
allow_unwrap_in_tests,
|
||||
allowed_dotfiles.clone(),
|
||||
format_args.clone(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
|
||||
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
|
||||
store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv())));
|
||||
store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone())));
|
||||
store.register_late_pass(move |_| Box::new(matches::Matches::new(conf)));
|
||||
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf)));
|
||||
store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf)));
|
||||
store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(ranges::Ranges::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
|
||||
store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv())));
|
||||
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(casts::Casts::new(conf)));
|
||||
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
|
||||
store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(index_refutable_slice::IndexRefutableSlice::new(
|
||||
max_suggested_slice_pattern_length,
|
||||
msrv(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(index_refutable_slice::IndexRefutableSlice::new(conf)));
|
||||
store.register_late_pass(|_| Box::<shadow::Shadow>::default());
|
||||
store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
|
||||
store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv(), enforce_iter_loop_reborrow)));
|
||||
store.register_late_pass(move |_| Box::new(loops::Loops::new(conf)));
|
||||
store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
|
||||
store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
|
||||
store.register_late_pass(|_| Box::new(entry::HashMapPass));
|
||||
|
@ -763,75 +642,49 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
|
||||
store.register_late_pass(|_| Box::<no_effect::NoEffect>::default());
|
||||
store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
|
||||
store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(cognitive_complexity::CognitiveComplexity::new(
|
||||
cognitive_complexity_threshold,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(vec::UselessVec {
|
||||
too_large_for_stack,
|
||||
msrv: msrv(),
|
||||
span_to_lint_map: BTreeMap::new(),
|
||||
allow_in_test: allow_useless_vec_in_tests,
|
||||
})
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented { allow_panic_in_tests }));
|
||||
store.register_late_pass(move |_| Box::new(transmute::Transmute::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(cognitive_complexity::CognitiveComplexity::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(escape::BoxedLocal::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(vec::UselessVec::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
|
||||
store.register_late_pass(|_| Box::new(derive::Derive));
|
||||
store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
|
||||
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
|
||||
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
|
||||
store.register_late_pass(|_| Box::<regex::Regex>::default());
|
||||
store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
|
||||
store.register_late_pass(move |tcx| Box::new(copies::CopyAndPaste::new(tcx, conf)));
|
||||
store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
|
||||
let format_args = format_args_storage.clone();
|
||||
store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
|
||||
store.register_late_pass(|_| Box::new(swap::Swap));
|
||||
store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
|
||||
store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
|
||||
store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names)));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(functions::Functions::new(
|
||||
too_many_arguments_threshold,
|
||||
too_many_lines_threshold,
|
||||
large_error_threshold,
|
||||
avoid_breaking_exported_api,
|
||||
allow_renamed_params_for.clone(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items)));
|
||||
store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf)));
|
||||
store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf)));
|
||||
store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
|
||||
store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
|
||||
store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
|
||||
store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items)));
|
||||
store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
|
||||
store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
|
||||
store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
|
||||
store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
|
||||
store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
|
||||
store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
|
||||
store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(conf)));
|
||||
let format_args = format_args_storage.clone();
|
||||
store.register_late_pass(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone())));
|
||||
store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
|
||||
store.register_late_pass(move |tcx| {
|
||||
Box::new(pass_by_ref_or_value::PassByRefOrValue::new(
|
||||
trivial_copy_size_limit,
|
||||
pass_by_value_size_limit,
|
||||
avoid_breaking_exported_api,
|
||||
tcx.sess.target.pointer_width,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |tcx| Box::new(pass_by_ref_or_value::PassByRefOrValue::new(tcx, conf)));
|
||||
store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
|
||||
store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
|
||||
store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
|
||||
store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
|
||||
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
|
||||
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
|
||||
store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(msrv(), matches_for_let_else)));
|
||||
store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
|
||||
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
|
||||
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
|
||||
|
@ -839,22 +692,18 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
|
||||
store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
|
||||
store.register_late_pass(|_| Box::new(unwrap::Unwrap));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(indexing_slicing::IndexingSlicing::new(
|
||||
suppress_restriction_lint_in_const,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone())));
|
||||
store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
|
||||
store.register_late_pass(move |tcx| Box::new(non_copy_const::NonCopyConst::new(tcx, conf)));
|
||||
store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
|
||||
store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
|
||||
store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
|
||||
store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
|
||||
store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants));
|
||||
store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
|
||||
store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
|
||||
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv())));
|
||||
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
|
||||
store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
|
||||
store.register_late_pass(move |tcx| Box::new(mut_key::MutableKeyType::new(tcx, conf)));
|
||||
store.register_early_pass(|| Box::new(reference::DerefAddrOf));
|
||||
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
|
||||
let format_args = format_args_storage.clone();
|
||||
|
@ -875,80 +724,45 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
|
||||
store.register_late_pass(|_| Box::new(create_dir::CreateDir));
|
||||
store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
|
||||
store.register_early_pass(move || {
|
||||
Box::new(literal_representation::LiteralDigitGrouping::new(
|
||||
unreadable_literal_lint_fractions,
|
||||
))
|
||||
});
|
||||
store.register_early_pass(move || {
|
||||
Box::new(literal_representation::DecimalLiteralRepresentation::new(
|
||||
literal_representation_threshold,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(item_name_repetitions::ItemNameRepetitions::new(
|
||||
enum_variant_name_threshold,
|
||||
struct_field_name_threshold,
|
||||
avoid_breaking_exported_api,
|
||||
allow_private_module_inception,
|
||||
allowed_prefixes,
|
||||
))
|
||||
});
|
||||
store.register_early_pass(move || Box::new(literal_representation::LiteralDigitGrouping::new(conf)));
|
||||
store.register_early_pass(move || Box::new(literal_representation::DecimalLiteralRepresentation::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(item_name_repetitions::ItemNameRepetitions::new(conf)));
|
||||
store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
|
||||
avoid_breaking_exported_api,
|
||||
upper_case_acronyms_aggressive,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(upper_case_acronyms::UpperCaseAcronyms::new(conf)));
|
||||
store.register_late_pass(|_| Box::<default::Default>::default());
|
||||
store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
|
||||
store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
|
||||
store.register_late_pass(|_| Box::new(exit::Exit));
|
||||
store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
|
||||
store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold.into())));
|
||||
store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold.into())));
|
||||
store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
|
||||
store.register_late_pass(|_| Box::new(as_conversions::AsConversions));
|
||||
store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
|
||||
store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(excessive_bools::ExcessiveBools::new(
|
||||
max_struct_bools,
|
||||
max_fn_params_bools,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(excessive_bools::ExcessiveBools::new(conf)));
|
||||
store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(wildcard_imports::WildcardImports::new(
|
||||
warn_on_all_wildcard_imports,
|
||||
allowed_wildcard_imports.clone(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(conf)));
|
||||
store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
|
||||
store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
|
||||
store.register_late_pass(|_| Box::<dereference::Dereferencing<'_>>::default());
|
||||
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
|
||||
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
|
||||
store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold)));
|
||||
store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
|
||||
store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
|
||||
store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
|
||||
store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn));
|
||||
store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn));
|
||||
store.register_early_pass(move || {
|
||||
Box::new(non_expressive_names::NonExpressiveNames {
|
||||
single_char_binding_names_threshold,
|
||||
})
|
||||
});
|
||||
store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(standard_macro_braces)));
|
||||
store.register_early_pass(move || Box::new(non_expressive_names::NonExpressiveNames::new(conf)));
|
||||
store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(conf)));
|
||||
store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
|
||||
store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
|
||||
store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
|
||||
store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
|
||||
store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
|
||||
store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
|
||||
store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
|
||||
store.register_late_pass(move |tcx| Box::new(disallowed_macros::DisallowedMacros::new(tcx, conf)));
|
||||
store.register_late_pass(move |tcx| Box::new(disallowed_methods::DisallowedMethods::new(tcx, conf)));
|
||||
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
|
||||
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
|
||||
store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
|
||||
|
@ -958,86 +772,57 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
|
||||
store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
|
||||
store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
|
||||
store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
|
||||
store.register_early_pass(move || Box::new(module_style::ModStyle));
|
||||
store.register_late_pass(|_| Box::<unused_async::UnusedAsync>::default());
|
||||
store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(missing_enforced_import_rename::ImportRename::new(
|
||||
enforced_import_renames.clone(),
|
||||
))
|
||||
});
|
||||
store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(allowed_scripts)));
|
||||
store.register_late_pass(move |tcx| Box::new(disallowed_types::DisallowedTypes::new(tcx, conf)));
|
||||
store.register_late_pass(move |tcx| Box::new(missing_enforced_import_rename::ImportRename::new(tcx, conf)));
|
||||
store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
|
||||
store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
|
||||
store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
|
||||
store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
|
||||
enable_raw_pointer_heuristic_for_send,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
|
||||
accept_comment_above_statement,
|
||||
accept_comment_above_attributes,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf)));
|
||||
let format_args = format_args_storage.clone();
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(format_args::FormatArgs::new(
|
||||
format_args.clone(),
|
||||
msrv(),
|
||||
allow_mixed_uninlined_format_args,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(conf, format_args.clone())));
|
||||
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
|
||||
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
|
||||
store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
|
||||
store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
|
||||
store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
|
||||
store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
|
||||
store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
|
||||
store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
|
||||
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
|
||||
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(conf)));
|
||||
let format_args = format_args_storage.clone();
|
||||
store.register_late_pass(move |_| Box::new(write::Write::new(format_args.clone(), allow_print_in_tests)));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(cargo::Cargo {
|
||||
ignore_publish: cargo_ignore_publish,
|
||||
allowed_duplicate_crates: allowed_duplicate_crates.clone(),
|
||||
})
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(write::Write::new(conf, format_args.clone())));
|
||||
store.register_late_pass(move |_| Box::new(cargo::Cargo::new(conf)));
|
||||
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
|
||||
store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets));
|
||||
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
|
||||
store.register_early_pass(|| Box::new(pub_use::PubUse));
|
||||
store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
|
||||
store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
|
||||
store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
|
||||
store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
|
||||
store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
|
||||
store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
|
||||
store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(msrv())));
|
||||
store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
|
||||
store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
|
||||
store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
|
||||
store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
|
||||
store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(operators::Operators::new(
|
||||
verbose_bit_mask_threshold,
|
||||
allow_comparison_to_zero,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(operators::Operators::new(conf)));
|
||||
store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
|
||||
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
|
||||
store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
|
||||
store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
|
||||
store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
|
||||
|
@ -1048,44 +833,25 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
|
||||
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
|
||||
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
|
||||
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(semicolon_block::SemicolonBlock::new(
|
||||
semicolon_inside_block_ignore_singleline,
|
||||
semicolon_outside_block_ignore_multiline,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(semicolon_block::SemicolonBlock::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
|
||||
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
|
||||
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(
|
||||
avoid_breaking_exported_api,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
|
||||
store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead));
|
||||
store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
|
||||
store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized));
|
||||
store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock));
|
||||
store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
|
||||
store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(
|
||||
avoid_breaking_exported_api,
|
||||
unnecessary_box_size,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk));
|
||||
store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
|
||||
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
|
||||
store.register_early_pass(move || {
|
||||
Box::new(excessive_nesting::ExcessiveNesting {
|
||||
excessive_nesting_threshold,
|
||||
nodes: rustc_ast::node_id::NodeSet::new(),
|
||||
})
|
||||
});
|
||||
store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
|
||||
store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
|
||||
store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
|
||||
|
@ -1095,44 +861,21 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
|
||||
store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
|
||||
store.register_late_pass(|_| Box::new(needless_if::NeedlessIf));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(min_ident_chars::MinIdentChars {
|
||||
allowed_idents_below_min_chars: allowed_idents_below_min_chars.clone(),
|
||||
min_ident_chars_threshold,
|
||||
})
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold)));
|
||||
store.register_late_pass(move |_| Box::new(min_ident_chars::MinIdentChars::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(
|
||||
avoid_breaking_exported_api,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(non_canonical_impls::NonCanonicalImpls));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(single_call_fn::SingleCallFn {
|
||||
avoid_breaking_exported_api,
|
||||
def_id_to_usage: rustc_data_structures::fx::FxIndexMap::default(),
|
||||
})
|
||||
});
|
||||
store.register_early_pass(move || {
|
||||
Box::new(raw_strings::RawStrings {
|
||||
allow_one_hash_in_raw_strings,
|
||||
})
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(single_call_fn::SingleCallFn::new(conf)));
|
||||
store.register_early_pass(move || Box::new(raw_strings::RawStrings::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
|
||||
store.register_early_pass(|| Box::new(visibility::Visibility));
|
||||
store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
|
||||
store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
|
||||
store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
|
||||
store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(absolute_paths::AbsolutePaths {
|
||||
absolute_paths_max_segments,
|
||||
absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
|
||||
})
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(absolute_paths::AbsolutePaths::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
|
||||
store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
|
||||
store.register_late_pass(|_| Box::<reserve_after_initialization::ReserveAfterInitialization>::default());
|
||||
|
@ -1141,38 +884,29 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(unnecessary_map_on_constructor::UnnecessaryMapOnConstructor));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(needless_borrows_for_generic_args::NeedlessBorrowsForGenericArgs::new(
|
||||
msrv(),
|
||||
conf,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
|
||||
store.register_late_pass(|_| Box::<pathbuf_init_then_push::PathbufThenPush<'_>>::default());
|
||||
store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
|
||||
store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
|
||||
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
|
||||
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
|
||||
store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
|
||||
store.register_late_pass(|_| Box::<unconditional_recursion::UnconditionalRecursion>::default());
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(pub_underscore_fields::PubUnderscoreFields {
|
||||
behavior: pub_underscore_fields_behavior,
|
||||
})
|
||||
});
|
||||
store
|
||||
.register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(pub_underscore_fields::PubUnderscoreFields::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
|
||||
store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
|
||||
store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
|
||||
store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
|
||||
store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe {
|
||||
warn_unsafe_macro_metavars_in_private_macros,
|
||||
..Default::default()
|
||||
})
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
|
||||
store.register_late_pass(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(conf)));
|
||||
store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
|
||||
store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
|
||||
store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
|
||||
|
|
|
@ -22,6 +22,7 @@ use rustc_session::declare_lint_pass;
|
|||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -380,11 +381,8 @@ fn could_use_elision<'tcx>(
|
|||
return None;
|
||||
}
|
||||
|
||||
let mut checker = BodyLifetimeChecker {
|
||||
lifetimes_used_in_body: false,
|
||||
};
|
||||
checker.visit_expr(body.value);
|
||||
if checker.lifetimes_used_in_body {
|
||||
let mut checker = BodyLifetimeChecker;
|
||||
if checker.visit_expr(body.value).is_break() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -694,15 +692,15 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
|
|||
}
|
||||
}
|
||||
|
||||
struct BodyLifetimeChecker {
|
||||
lifetimes_used_in_body: bool,
|
||||
}
|
||||
struct BodyLifetimeChecker;
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
|
||||
type Result = ControlFlow<()>;
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> {
|
||||
if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {
|
||||
self.lifetimes_used_in_body = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Lints concerned with the grouping of digits with underscores in integral or
|
||||
//! floating-point literal expressions.
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
@ -218,7 +219,6 @@ impl WarningType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LiteralDigitGrouping {
|
||||
lint_fraction_readability: bool,
|
||||
}
|
||||
|
@ -245,13 +245,13 @@ impl EarlyLintPass for LiteralDigitGrouping {
|
|||
const UUID_GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12];
|
||||
|
||||
impl LiteralDigitGrouping {
|
||||
pub fn new(lint_fraction_readability: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
lint_fraction_readability,
|
||||
lint_fraction_readability: conf.unreadable_literal_lint_fractions,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
|
||||
fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
|
||||
if let Some(src) = snippet_opt(cx, span)
|
||||
&& let Ok(lit_kind) = LitKind::from_token_lit(lit)
|
||||
&& let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
|
||||
|
@ -437,7 +437,6 @@ impl LiteralDigitGrouping {
|
|||
}
|
||||
|
||||
#[expect(clippy::module_name_repetitions)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DecimalLiteralRepresentation {
|
||||
threshold: u64,
|
||||
}
|
||||
|
@ -455,11 +454,12 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
|
|||
}
|
||||
|
||||
impl DecimalLiteralRepresentation {
|
||||
#[must_use]
|
||||
pub fn new(threshold: u64) -> Self {
|
||||
Self { threshold }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
threshold: conf.literal_representation_threshold,
|
||||
}
|
||||
}
|
||||
fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
|
||||
fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
|
||||
// Lint integral literals.
|
||||
if let Ok(lit_kind) = LitKind::from_token_lit(lit)
|
||||
&& let LitKind::Int(val, _) = lit_kind
|
||||
|
|
|
@ -23,6 +23,7 @@ mod while_let_loop;
|
|||
mod while_let_on_iterator;
|
||||
|
||||
use clippy_config::msrvs::Msrv;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::higher;
|
||||
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -717,10 +718,10 @@ pub struct Loops {
|
|||
enforce_iter_loop_reborrow: bool,
|
||||
}
|
||||
impl Loops {
|
||||
pub fn new(msrv: Msrv, enforce_iter_loop_reborrow: bool) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv,
|
||||
enforce_iter_loop_reborrow,
|
||||
msrv: conf.msrv.clone(),
|
||||
enforce_iter_loop_reborrow: conf.enforce_iter_loop_reborrow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use rustc_lint::LateContext;
|
|||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::Span;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
|
||||
if let Some(higher::Range {
|
||||
|
@ -114,7 +115,6 @@ impl MutatePairDelegate<'_, '_> {
|
|||
struct BreakAfterExprVisitor {
|
||||
hir_id: HirId,
|
||||
past_expr: bool,
|
||||
past_candidate: bool,
|
||||
break_after_expr: bool,
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,6 @@ impl BreakAfterExprVisitor {
|
|||
let mut visitor = BreakAfterExprVisitor {
|
||||
hir_id,
|
||||
past_expr: false,
|
||||
past_candidate: false,
|
||||
break_after_expr: false,
|
||||
};
|
||||
|
||||
|
@ -135,21 +134,19 @@ impl BreakAfterExprVisitor {
|
|||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for BreakAfterExprVisitor {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
if self.past_candidate {
|
||||
return;
|
||||
}
|
||||
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
|
||||
if expr.hir_id == self.hir_id {
|
||||
self.past_expr = true;
|
||||
ControlFlow::Continue(())
|
||||
} else if self.past_expr {
|
||||
if matches!(&expr.kind, ExprKind::Break(..)) {
|
||||
self.break_after_expr = true;
|
||||
}
|
||||
|
||||
self.past_candidate = true;
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
intravisit::walk_expr(self, expr);
|
||||
intravisit::walk_expr(self, expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use clippy_utils::visitors::contains_break_or_continue;
|
|||
use rustc_ast::util::parser::PREC_PREFIX;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
|
||||
use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::sym;
|
||||
|
@ -70,7 +70,10 @@ pub(super) fn check<'tcx>(
|
|||
&& !contains_break_or_continue(body)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
|
||||
let mut pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
|
||||
if matches!(pat.kind, PatKind::Or(..)) {
|
||||
pat_snip = format!("({pat_snip})").into();
|
||||
}
|
||||
let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
|
||||
let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
|
||||
block_str.remove(0);
|
||||
|
|
|
@ -7,6 +7,7 @@ use rustc_hir::def_id::DefIdMap;
|
|||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind, HirIdSet, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
|
||||
if constant(cx, cx.typeck_results(), cond).is_some() {
|
||||
|
@ -35,11 +36,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
|
|||
};
|
||||
let mutable_static_in_cond = var_visitor.def_ids.items().any(|(_, v)| *v);
|
||||
|
||||
let mut has_break_or_return_visitor = HasBreakOrReturnVisitor {
|
||||
has_break_or_return: false,
|
||||
};
|
||||
has_break_or_return_visitor.visit_expr(expr);
|
||||
let has_break_or_return = has_break_or_return_visitor.has_break_or_return;
|
||||
let mut has_break_or_return_visitor = HasBreakOrReturnVisitor;
|
||||
let has_break_or_return = has_break_or_return_visitor.visit_expr(expr).is_break();
|
||||
|
||||
if no_cond_variable_mutated && !mutable_static_in_cond {
|
||||
span_lint_and_then(
|
||||
|
@ -59,25 +57,19 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
|
|||
}
|
||||
}
|
||||
|
||||
struct HasBreakOrReturnVisitor {
|
||||
has_break_or_return: bool,
|
||||
}
|
||||
struct HasBreakOrReturnVisitor;
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if self.has_break_or_return {
|
||||
return;
|
||||
}
|
||||
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow<()> {
|
||||
match expr.kind {
|
||||
ExprKind::Ret(_) | ExprKind::Break(_, _) => {
|
||||
self.has_break_or_return = true;
|
||||
return;
|
||||
return ControlFlow::Break(());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
walk_expr(self, expr);
|
||||
walk_expr(self, expr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use std::collections::btree_map::Entry;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use itertools::Itertools;
|
||||
|
@ -10,6 +8,8 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
|
|||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{sym, Span, SyntaxContext};
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -90,9 +90,8 @@ pub enum MetavarState {
|
|||
ReferencedInSafe,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExprMetavarsInUnsafe {
|
||||
pub warn_unsafe_macro_metavars_in_private_macros: bool,
|
||||
warn_unsafe_macro_metavars_in_private_macros: bool,
|
||||
/// A metavariable can be expanded more than once, potentially across multiple bodies, so it
|
||||
/// requires some state kept across HIR nodes to make it possible to delay a warning
|
||||
/// and later undo:
|
||||
|
@ -106,7 +105,16 @@ pub struct ExprMetavarsInUnsafe {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub metavar_expns: BTreeMap<Span, MetavarState>,
|
||||
metavar_expns: BTreeMap<Span, MetavarState>,
|
||||
}
|
||||
|
||||
impl ExprMetavarsInUnsafe {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
warn_unsafe_macro_metavars_in_private_macros: conf.warn_unsafe_macro_metavars_in_private_macros,
|
||||
metavar_expns: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BodyVisitor<'a, 'tcx> {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
|
@ -34,15 +35,15 @@ declare_clippy_lint! {
|
|||
"manual implementation of `size_of::<T>() * 8` can be simplified with `T::BITS`"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ManualBits {
|
||||
msrv: Msrv,
|
||||
}
|
||||
|
||||
impl ManualBits {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::higher::If;
|
||||
|
@ -97,8 +98,10 @@ pub struct ManualClamp {
|
|||
}
|
||||
|
||||
impl ManualClamp {
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::visitors::{is_local_used, local_used_once};
|
||||
|
@ -51,9 +52,10 @@ pub struct ManualHashOne {
|
|||
}
|
||||
|
||||
impl ManualHashOne {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::matching_root_macro_call;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
|
@ -62,9 +63,10 @@ pub struct ManualIsAsciiCheck {
|
|||
}
|
||||
|
||||
impl ManualIsAsciiCheck {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs};
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -37,9 +38,10 @@ pub struct ManualMainSeparatorStr {
|
|||
}
|
||||
|
||||
impl ManualMainSeparatorStr {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::is_doc_hidden;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
@ -67,9 +68,10 @@ pub struct ManualNonExhaustiveStruct {
|
|||
}
|
||||
|
||||
impl ManualNonExhaustiveStruct {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,10 +85,9 @@ pub struct ManualNonExhaustiveEnum {
|
|||
}
|
||||
|
||||
impl ManualNonExhaustiveEnum {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv,
|
||||
msrv: conf.msrv.clone(),
|
||||
constructed_enum_variants: FxHashSet::default(),
|
||||
potential_enums: Vec::new(),
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant_full_int, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
|
@ -38,9 +39,10 @@ pub struct ManualRemEuclid {
|
|||
}
|
||||
|
||||
impl ManualRemEuclid {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
|
@ -59,9 +60,10 @@ pub struct ManualRetain {
|
|||
}
|
||||
|
||||
impl ManualRetain {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet;
|
||||
|
@ -50,9 +51,10 @@ pub struct ManualStrip {
|
|||
}
|
||||
|
||||
impl ManualStrip {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,17 @@ pub(super) fn check_if_let<'tcx>(
|
|||
else_expr: &'tcx Expr<'_>,
|
||||
) {
|
||||
let ty = cx.typeck_results().expr_ty(let_expr);
|
||||
let then_ty = cx.typeck_results().expr_ty(then_expr);
|
||||
// The signature is `fn unwrap_or<T>(self: Option<T>, default: T) -> T`.
|
||||
// When `expr_adjustments(then_expr).is_empty()`, `T` should equate to `default`'s type.
|
||||
// Otherwise, type error will occur.
|
||||
if cx.typeck_results().expr_adjustments(then_expr).is_empty()
|
||||
&& let rustc_middle::ty::Adt(_did, args) = ty.kind()
|
||||
&& let Some(some_ty) = args.first().and_then(|arg| arg.as_type())
|
||||
&& some_ty != then_ty
|
||||
{
|
||||
return;
|
||||
}
|
||||
check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ mod try_err;
|
|||
mod wild_in_or_pats;
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::source::walk_span_to_context;
|
||||
use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
|
||||
|
@ -980,10 +981,9 @@ pub struct Matches {
|
|||
}
|
||||
|
||||
impl Matches {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv,
|
||||
msrv: conf.msrv.clone(),
|
||||
infallible_destructuring_match_linted: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
|
|||
enum SigDropHolder {
|
||||
/// No values with significant drop present in this expression.
|
||||
///
|
||||
/// Expressions that we've emited lints do not count.
|
||||
/// Expressions that we've emitted lints do not count.
|
||||
None,
|
||||
/// Some field in this expression references to values with significant drop.
|
||||
///
|
||||
|
@ -426,7 +426,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
|
|||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
// We've emited a lint on some neighborhood expression. That lint will suggest to move out the
|
||||
// We've emitted a lint on some neighborhood expression. That lint will suggest to move out the
|
||||
// _parent_ expression (not the expression itself). Since we decide to move out the parent
|
||||
// expression, it is pointless to continue to process the current expression.
|
||||
if self.sig_drop_holder == SigDropHolder::Moved {
|
||||
|
@ -450,7 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
|
|||
ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _)
|
||||
if lhs.hir_id == ex.hir_id && self.sig_drop_holder == SigDropHolder::Moved =>
|
||||
{
|
||||
// Never move out only the assignee. Instead, we should always move out the whole assigment.
|
||||
// Never move out only the assignee. Instead, we should always move out the whole assignment.
|
||||
self.replace_current_sig_drop(parent_ex.span, true, 0);
|
||||
},
|
||||
_ => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
|
@ -217,9 +218,10 @@ pub struct MemReplace {
|
|||
}
|
||||
|
||||
impl MemReplace {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,59 +10,80 @@ use rustc_hir::{LangItem, QPath};
|
|||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
|
||||
pub(crate) struct OptionAndThenSome;
|
||||
|
||||
impl BindInsteadOfMap for OptionAndThenSome {
|
||||
const VARIANT_LANG_ITEM: LangItem = LangItem::OptionSome;
|
||||
const BAD_METHOD_NAME: &'static str = "and_then";
|
||||
const GOOD_METHOD_NAME: &'static str = "map";
|
||||
pub(super) fn check_and_then_some(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
arg: &hir::Expr<'_>,
|
||||
) -> bool {
|
||||
BindInsteadOfMap {
|
||||
variant_lang_item: LangItem::OptionSome,
|
||||
bad_method_name: "and_then",
|
||||
good_method_name: "map",
|
||||
}
|
||||
.check(cx, expr, recv, arg)
|
||||
}
|
||||
|
||||
pub(crate) struct ResultAndThenOk;
|
||||
|
||||
impl BindInsteadOfMap for ResultAndThenOk {
|
||||
const VARIANT_LANG_ITEM: LangItem = LangItem::ResultOk;
|
||||
const BAD_METHOD_NAME: &'static str = "and_then";
|
||||
const GOOD_METHOD_NAME: &'static str = "map";
|
||||
pub(super) fn check_and_then_ok(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
arg: &hir::Expr<'_>,
|
||||
) -> bool {
|
||||
BindInsteadOfMap {
|
||||
variant_lang_item: LangItem::ResultOk,
|
||||
bad_method_name: "and_then",
|
||||
good_method_name: "map",
|
||||
}
|
||||
.check(cx, expr, recv, arg)
|
||||
}
|
||||
|
||||
pub(crate) struct ResultOrElseErrInfo;
|
||||
|
||||
impl BindInsteadOfMap for ResultOrElseErrInfo {
|
||||
const VARIANT_LANG_ITEM: LangItem = LangItem::ResultErr;
|
||||
const BAD_METHOD_NAME: &'static str = "or_else";
|
||||
const GOOD_METHOD_NAME: &'static str = "map_err";
|
||||
pub(super) fn check_or_else_err(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
arg: &hir::Expr<'_>,
|
||||
) -> bool {
|
||||
BindInsteadOfMap {
|
||||
variant_lang_item: LangItem::ResultErr,
|
||||
bad_method_name: "or_else",
|
||||
good_method_name: "map_err",
|
||||
}
|
||||
.check(cx, expr, recv, arg)
|
||||
}
|
||||
|
||||
pub(crate) trait BindInsteadOfMap {
|
||||
const VARIANT_LANG_ITEM: LangItem;
|
||||
const BAD_METHOD_NAME: &'static str;
|
||||
const GOOD_METHOD_NAME: &'static str;
|
||||
struct BindInsteadOfMap {
|
||||
variant_lang_item: LangItem,
|
||||
bad_method_name: &'static str,
|
||||
good_method_name: &'static str,
|
||||
}
|
||||
|
||||
fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
|
||||
let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
|
||||
impl BindInsteadOfMap {
|
||||
fn no_op_msg(&self, cx: &LateContext<'_>) -> Option<String> {
|
||||
let variant_id = cx.tcx.lang_items().get(self.variant_lang_item)?;
|
||||
let item_id = cx.tcx.parent(variant_id);
|
||||
Some(format!(
|
||||
"using `{}.{}({})`, which is a no-op",
|
||||
cx.tcx.item_name(item_id),
|
||||
Self::BAD_METHOD_NAME,
|
||||
self.bad_method_name,
|
||||
cx.tcx.item_name(variant_id),
|
||||
))
|
||||
}
|
||||
|
||||
fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
|
||||
let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
|
||||
fn lint_msg(&self, cx: &LateContext<'_>) -> Option<String> {
|
||||
let variant_id = cx.tcx.lang_items().get(self.variant_lang_item)?;
|
||||
let item_id = cx.tcx.parent(variant_id);
|
||||
Some(format!(
|
||||
"using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
|
||||
cx.tcx.item_name(item_id),
|
||||
Self::BAD_METHOD_NAME,
|
||||
self.bad_method_name,
|
||||
cx.tcx.item_name(variant_id),
|
||||
Self::GOOD_METHOD_NAME
|
||||
self.good_method_name,
|
||||
))
|
||||
}
|
||||
|
||||
fn lint_closure_autofixable(
|
||||
&self,
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
|
@ -71,9 +92,9 @@ pub(crate) trait BindInsteadOfMap {
|
|||
) -> bool {
|
||||
if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind
|
||||
&& let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind
|
||||
&& Self::is_variant(cx, path.res)
|
||||
&& self.is_variant(cx, path.res)
|
||||
&& !contains_return(inner_expr)
|
||||
&& let Some(msg) = Self::lint_msg(cx)
|
||||
&& let Some(msg) = self.lint_msg(cx)
|
||||
{
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0;
|
||||
|
@ -82,7 +103,7 @@ pub(crate) trait BindInsteadOfMap {
|
|||
let option_snip = snippet(cx, recv.span, "..");
|
||||
let note = format!(
|
||||
"{option_snip}.{}({closure_args_snip} {some_inner_snip})",
|
||||
Self::GOOD_METHOD_NAME
|
||||
self.good_method_name
|
||||
);
|
||||
span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, "try", note, app);
|
||||
true
|
||||
|
@ -91,13 +112,13 @@ pub(crate) trait BindInsteadOfMap {
|
|||
}
|
||||
}
|
||||
|
||||
fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
|
||||
fn lint_closure(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
|
||||
let mut suggs = Vec::new();
|
||||
let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
|
||||
if !ret_expr.span.from_expansion()
|
||||
&& let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind
|
||||
&& let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind
|
||||
&& Self::is_variant(cx, path.res)
|
||||
&& self.is_variant(cx, path.res)
|
||||
&& !contains_return(arg)
|
||||
{
|
||||
suggs.push((ret_expr.span, arg.span.source_callsite()));
|
||||
|
@ -108,7 +129,7 @@ pub(crate) trait BindInsteadOfMap {
|
|||
});
|
||||
let (span, msg) = if can_sugg
|
||||
&& let hir::ExprKind::MethodCall(segment, ..) = expr.kind
|
||||
&& let Some(msg) = Self::lint_msg(cx)
|
||||
&& let Some(msg) = self.lint_msg(cx)
|
||||
{
|
||||
(segment.ident.span, msg)
|
||||
} else {
|
||||
|
@ -119,7 +140,7 @@ pub(crate) trait BindInsteadOfMap {
|
|||
diag,
|
||||
"try",
|
||||
Applicability::MachineApplicable,
|
||||
std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
|
||||
std::iter::once((span, self.good_method_name.into())).chain(
|
||||
suggs
|
||||
.into_iter()
|
||||
.map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
|
||||
|
@ -130,9 +151,9 @@ pub(crate) trait BindInsteadOfMap {
|
|||
}
|
||||
|
||||
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
|
||||
fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
|
||||
fn check(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
|
||||
if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
|
||||
&& let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)
|
||||
&& let Some(vid) = cx.tcx.lang_items().get(self.variant_lang_item)
|
||||
&& adt.did() == cx.tcx.parent(vid)
|
||||
{
|
||||
} else {
|
||||
|
@ -144,15 +165,15 @@ pub(crate) trait BindInsteadOfMap {
|
|||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_expr = peel_blocks(closure_body.value);
|
||||
|
||||
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
|
||||
if self.lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
|
||||
true
|
||||
} else {
|
||||
Self::lint_closure(cx, expr, closure_expr)
|
||||
self.lint_closure(cx, expr, closure_expr)
|
||||
}
|
||||
},
|
||||
// `_.and_then(Some)` case, which is no-op.
|
||||
hir::ExprKind::Path(QPath::Resolved(_, path)) if Self::is_variant(cx, path.res) => {
|
||||
if let Some(msg) = Self::no_op_msg(cx) {
|
||||
hir::ExprKind::Path(QPath::Resolved(_, path)) if self.is_variant(cx, path.res) => {
|
||||
if let Some(msg) = self.no_op_msg(cx) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
BIND_INSTEAD_OF_MAP,
|
||||
|
@ -169,9 +190,9 @@ pub(crate) trait BindInsteadOfMap {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
|
||||
fn is_variant(&self, cx: &LateContext<'_>, res: Res) -> bool {
|
||||
if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
|
||||
if let Some(variant_id) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM) {
|
||||
if let Some(variant_id) = cx.tcx.lang_items().get(self.variant_lang_item) {
|
||||
return cx.tcx.parent(id) == variant_id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,8 +131,8 @@ mod waker_clone_wake;
|
|||
mod wrong_self_convention;
|
||||
mod zst_offset;
|
||||
|
||||
use bind_instead_of_map::BindInsteadOfMap;
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::macros::FormatArgsStorage;
|
||||
|
@ -4131,27 +4131,20 @@ pub struct Methods {
|
|||
msrv: Msrv,
|
||||
allow_expect_in_tests: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
allowed_dotfiles: FxHashSet<String>,
|
||||
allowed_dotfiles: FxHashSet<&'static str>,
|
||||
format_args: FormatArgsStorage,
|
||||
}
|
||||
|
||||
impl Methods {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Msrv,
|
||||
allow_expect_in_tests: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
mut allowed_dotfiles: FxHashSet<String>,
|
||||
format_args: FormatArgsStorage,
|
||||
) -> Self {
|
||||
allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
|
||||
pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
|
||||
let mut allowed_dotfiles: FxHashSet<_> = conf.allowed_dotfiles.iter().map(|s| &**s).collect();
|
||||
allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES);
|
||||
|
||||
Self {
|
||||
avoid_breaking_exported_api,
|
||||
msrv,
|
||||
allow_expect_in_tests,
|
||||
allow_unwrap_in_tests,
|
||||
avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
|
||||
msrv: conf.msrv.clone(),
|
||||
allow_expect_in_tests: conf.allow_expect_in_tests,
|
||||
allow_unwrap_in_tests: conf.allow_unwrap_in_tests,
|
||||
allowed_dotfiles,
|
||||
format_args,
|
||||
}
|
||||
|
@ -4512,8 +4505,8 @@ impl Methods {
|
|||
}
|
||||
},
|
||||
("and_then", [arg]) => {
|
||||
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
|
||||
let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
|
||||
let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
|
||||
let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
|
||||
if !biom_option_linted && !biom_result_linted {
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
||||
}
|
||||
|
@ -4853,7 +4846,7 @@ impl Methods {
|
|||
open_options::check(cx, expr, recv);
|
||||
},
|
||||
("or_else", [arg]) => {
|
||||
if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
|
||||
if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) {
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@ use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath};
|
|||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_span::{sym, Span};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use super::MAP_UNWRAP_OR;
|
||||
|
||||
|
@ -54,15 +55,14 @@ pub(super) fn check<'tcx>(
|
|||
let mut reference_visitor = ReferenceVisitor {
|
||||
cx,
|
||||
identifiers: unwrap_visitor.identifiers,
|
||||
found_reference: false,
|
||||
unwrap_or_span: unwrap_arg.span,
|
||||
};
|
||||
|
||||
let map = cx.tcx.hir();
|
||||
let body = map.body_owned_by(map.enclosing_body_owner(expr.hir_id));
|
||||
reference_visitor.visit_body(body);
|
||||
|
||||
if reference_visitor.found_reference {
|
||||
// Visit the body, and return if we've found a reference
|
||||
if reference_visitor.visit_body(body).is_break() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -151,29 +151,27 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
|
|||
struct ReferenceVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
identifiers: FxHashSet<HirId>,
|
||||
found_reference: bool,
|
||||
unwrap_or_span: Span,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> {
|
||||
// If we haven't found a reference yet, check if this references
|
||||
// one of the locals that was moved in the `unwrap_or` argument.
|
||||
// We are only interested in exprs that appear before the `unwrap_or` call.
|
||||
if !self.found_reference {
|
||||
if expr.span < self.unwrap_or_span
|
||||
&& let ExprKind::Path(ref path) = expr.kind
|
||||
&& let QPath::Resolved(_, path) = path
|
||||
&& let Res::Local(local_id) = path.res
|
||||
&& let Node::Pat(pat) = self.cx.tcx.hir_node(local_id)
|
||||
&& let PatKind::Binding(_, local_id, ..) = pat.kind
|
||||
&& self.identifiers.contains(&local_id)
|
||||
{
|
||||
self.found_reference = true;
|
||||
}
|
||||
rustc_hir::intravisit::walk_expr(self, expr);
|
||||
if expr.span < self.unwrap_or_span
|
||||
&& let ExprKind::Path(ref path) = expr.kind
|
||||
&& let QPath::Resolved(_, path) = path
|
||||
&& let Res::Local(local_id) = path.res
|
||||
&& let Node::Pat(pat) = self.cx.tcx.hir_node(local_id)
|
||||
&& let PatKind::Binding(_, local_id, ..) = pat.kind
|
||||
&& self.identifiers.contains(&local_id)
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
rustc_hir::intravisit::walk_expr(self, expr)
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment};
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use clippy_utils::{
|
||||
contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
|
@ -13,7 +18,7 @@ use {rustc_ast as ast, rustc_hir as hir};
|
|||
use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
|
||||
|
||||
/// Checks for the `OR_FUN_CALL` lint.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[expect(clippy::too_many_lines)]
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &hir::Expr<'_>,
|
||||
|
@ -26,7 +31,6 @@ pub(super) fn check<'tcx>(
|
|||
/// `or_insert(T::new())` or `or_insert(T::default())`.
|
||||
/// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`,
|
||||
/// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn check_unwrap_or_default(
|
||||
cx: &LateContext<'_>,
|
||||
name: &str,
|
||||
|
@ -70,18 +74,31 @@ pub(super) fn check<'tcx>(
|
|||
};
|
||||
|
||||
let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
|
||||
let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| {
|
||||
let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| {
|
||||
cx.tcx
|
||||
.inherent_impls(adt_def.did())
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
|
||||
.any(|assoc| {
|
||||
assoc.fn_has_self_parameter
|
||||
.find_map(|assoc| {
|
||||
if assoc.fn_has_self_parameter
|
||||
&& cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
|
||||
{
|
||||
Some(assoc.def_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
if !has_suggested_method {
|
||||
}) else {
|
||||
return false;
|
||||
};
|
||||
let in_sugg_method_implementation = {
|
||||
matches!(
|
||||
suggested_method_def_id.as_local(),
|
||||
Some(local_def_id) if local_def_id == cx.tcx.hir().get_parent_item(receiver.hir_id).def_id
|
||||
)
|
||||
};
|
||||
if in_sugg_method_implementation {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -110,8 +127,8 @@ pub(super) fn check<'tcx>(
|
|||
}
|
||||
|
||||
/// Checks for `*or(foo())`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn check_general_case<'tcx>(
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_or_fn_call<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
name: &str,
|
||||
method_span: Span,
|
||||
|
@ -122,7 +139,7 @@ pub(super) fn check<'tcx>(
|
|||
span: Span,
|
||||
// None if lambda is required
|
||||
fun_span: Option<Span>,
|
||||
) {
|
||||
) -> bool {
|
||||
// (path, fn_has_argument, methods, suffix)
|
||||
const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [
|
||||
(sym::BTreeEntry, false, &["or_insert"], "with"),
|
||||
|
@ -172,54 +189,68 @@ pub(super) fn check<'tcx>(
|
|||
format!("{name}_{suffix}({sugg})"),
|
||||
app,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| {
|
||||
if let hir::ExprKind::Block(
|
||||
hir::Block {
|
||||
stmts: [],
|
||||
expr: Some(expr),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) = arg.kind
|
||||
{
|
||||
expr
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
};
|
||||
|
||||
if let [arg] = args {
|
||||
let inner_arg = extract_inner_arg(arg);
|
||||
match inner_arg.kind {
|
||||
hir::ExprKind::Call(fun, or_args) => {
|
||||
let or_has_args = !or_args.is_empty();
|
||||
if or_has_args
|
||||
|| !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span)
|
||||
{
|
||||
let fun_span = if or_has_args { None } else { Some(fun.span) };
|
||||
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
|
||||
}
|
||||
},
|
||||
hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => {
|
||||
check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span);
|
||||
},
|
||||
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
||||
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
let inner_arg = peel_blocks(arg);
|
||||
for_each_expr(cx, inner_arg, |ex| {
|
||||
// `or_fun_call` lint needs to take nested expr into account,
|
||||
// but `unwrap_or_default` lint doesn't, we don't want something like:
|
||||
// `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by
|
||||
// `opt.unwrap_or_default()`.
|
||||
let is_nested_expr = ex.hir_id != inner_arg.hir_id;
|
||||
|
||||
let is_triggered = match ex.kind {
|
||||
hir::ExprKind::Call(fun, fun_args) => {
|
||||
let inner_fun_has_args = !fun_args.is_empty();
|
||||
let fun_span = if inner_fun_has_args || is_nested_expr {
|
||||
None
|
||||
} else {
|
||||
Some(fun.span)
|
||||
};
|
||||
(!inner_fun_has_args
|
||||
&& !is_nested_expr
|
||||
&& check_unwrap_or_default(cx, name, receiver, fun, Some(ex), expr.span, method_span))
|
||||
|| check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, fun_span)
|
||||
},
|
||||
hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) if !is_nested_expr => {
|
||||
check_unwrap_or_default(cx, name, receiver, ex, None, expr.span, method_span)
|
||||
},
|
||||
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
||||
check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, None)
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if is_triggered {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// `map_or` takes two arguments
|
||||
if let [arg, lambda] = args {
|
||||
let inner_arg = extract_inner_arg(arg);
|
||||
if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind {
|
||||
let fun_span = if or_args.is_empty() { Some(fun.span) } else { None };
|
||||
check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span);
|
||||
}
|
||||
let inner_arg = peel_blocks(arg);
|
||||
for_each_expr(cx, inner_arg, |ex| {
|
||||
let is_top_most_expr = ex.hir_id == inner_arg.hir_id;
|
||||
if let hir::ExprKind::Call(fun, fun_args) = ex.kind {
|
||||
let fun_span = if fun_args.is_empty() && is_top_most_expr {
|
||||
Some(fun.span)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ pub(super) fn check(
|
|||
path: &Expr<'_>,
|
||||
expr: &Expr<'_>,
|
||||
msrv: &Msrv,
|
||||
allowed_dotfiles: &FxHashSet<String>,
|
||||
allowed_dotfiles: &FxHashSet<&'static str>,
|
||||
) {
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::Path)
|
||||
&& !path.span.from_expansion()
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue