Auto merge of #133588 - flip1995:clippy-subtree-update, r=Manishearth
Clippy subtree update r? `@Manishearth`
This commit is contained in:
commit
d10a6823f4
196 changed files with 1965 additions and 652 deletions
12
Cargo.lock
12
Cargo.lock
|
@ -536,7 +536,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy"
|
name = "clippy"
|
||||||
version = "0.1.84"
|
version = "0.1.85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
|
@ -567,8 +567,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_config"
|
name = "clippy_config"
|
||||||
version = "0.1.84"
|
version = "0.1.85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clippy_utils",
|
||||||
"itertools",
|
"itertools",
|
||||||
"serde",
|
"serde",
|
||||||
"toml 0.7.8",
|
"toml 0.7.8",
|
||||||
|
@ -580,6 +581,7 @@ name = "clippy_dev"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"indoc",
|
"indoc",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
@ -590,7 +592,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_lints"
|
name = "clippy_lints"
|
||||||
version = "0.1.84"
|
version = "0.1.85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
|
@ -613,12 +615,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy_utils"
|
name = "clippy_utils"
|
||||||
version = "0.1.84"
|
version = "0.1.85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"clippy_config",
|
|
||||||
"itertools",
|
"itertools",
|
||||||
"rustc_apfloat",
|
"rustc_apfloat",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -6,11 +6,56 @@ document.
|
||||||
|
|
||||||
## Unreleased / Beta / In Rust Nightly
|
## Unreleased / Beta / In Rust Nightly
|
||||||
|
|
||||||
[0f8eabd6...master](https://github.com/rust-lang/rust-clippy/compare/0f8eabd6...master)
|
[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master)
|
||||||
|
|
||||||
|
## Rust 1.83
|
||||||
|
|
||||||
|
Current stable, released 2024-11-28
|
||||||
|
|
||||||
|
[View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster)
|
||||||
|
|
||||||
|
### Important Change
|
||||||
|
|
||||||
|
* Removed the implicit `cargo-clippy` feature set by Clippy as announced here:
|
||||||
|
<https://blog.rust-lang.org/2024/02/28/Clippy-deprecating-feature-cargo-clippy.html>
|
||||||
|
[#13246](https://github.com/rust-lang/rust-clippy/pull/13246)
|
||||||
|
|
||||||
|
### New Lints
|
||||||
|
|
||||||
|
* Added [`unused_trait_names`] to `restriction`
|
||||||
|
[#13322](https://github.com/rust-lang/rust-clippy/pull/13322)
|
||||||
|
* Added [`unnecessary_first_then_check`] to `complexity`
|
||||||
|
[#13421](https://github.com/rust-lang/rust-clippy/pull/13421)
|
||||||
|
* Added [`non_zero_suggestions`] to `restriction`
|
||||||
|
[#13167](https://github.com/rust-lang/rust-clippy/pull/13167)
|
||||||
|
* Added [`manual_is_power_of_two`] to `pedantic`
|
||||||
|
[#13327](https://github.com/rust-lang/rust-clippy/pull/13327)
|
||||||
|
* Added [`manual_div_ceil`] to `complexity`
|
||||||
|
[#12987](https://github.com/rust-lang/rust-clippy/pull/12987)
|
||||||
|
* Added [`zombie_processes`] to `suspicious`
|
||||||
|
[#11476](https://github.com/rust-lang/rust-clippy/pull/11476)
|
||||||
|
* Added [`used_underscore_items`] to `pedantic`
|
||||||
|
[#13294](https://github.com/rust-lang/rust-clippy/pull/13294)
|
||||||
|
|
||||||
|
### Moves and Deprecations
|
||||||
|
|
||||||
|
* Moved [`ref_option`] to `pedantic` (From `nursery`)
|
||||||
|
[#13469](https://github.com/rust-lang/rust-clippy/pull/13469)
|
||||||
|
* Moved [`manual_c_str_literals`] to `complexity` (From `pedantic`, now warn-by-default)
|
||||||
|
[#13263](https://github.com/rust-lang/rust-clippy/pull/13263)
|
||||||
|
* Moved [`empty_line_after_doc_comments`] to `suspicious` (From `nursery`, now warn-by-default)
|
||||||
|
[#13091](https://github.com/rust-lang/rust-clippy/pull/13091)
|
||||||
|
* Moved [`empty_line_after_outer_attr`] to `suspicious` (From `nursery`, now warn-by-default)
|
||||||
|
[#13091](https://github.com/rust-lang/rust-clippy/pull/13091)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [`missing_panics_doc`]: No longer lints in const environments
|
||||||
|
[#13382](https://github.com/rust-lang/rust-clippy/pull/13382)
|
||||||
|
|
||||||
## Rust 1.82
|
## Rust 1.82
|
||||||
|
|
||||||
Current stable, released 2024-10-17
|
Released 2024-10-17
|
||||||
|
|
||||||
[View all 108 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-07-11T20%3A12%3A07Z..2024-08-24T20%3A55%3A35Z+base%3Amaster)
|
[View all 108 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-07-11T20%3A12%3A07Z..2024-08-24T20%3A55%3A35Z+base%3Amaster)
|
||||||
|
|
||||||
|
@ -5441,6 +5486,7 @@ Released 2018-09-13
|
||||||
[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
|
[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
|
||||||
[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
|
[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
|
||||||
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
|
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
|
||||||
|
[`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg
|
||||||
[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
|
[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
|
||||||
[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
|
[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
|
||||||
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "clippy"
|
name = "clippy"
|
||||||
version = "0.1.84"
|
# begin autogenerated version
|
||||||
|
version = "0.1.85"
|
||||||
|
# end autogenerated version
|
||||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||||
repository = "https://github.com/rust-lang/rust-clippy"
|
repository = "https://github.com/rust-lang/rust-clippy"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -27,7 +29,7 @@ rustc_tools_util = "0.4.0"
|
||||||
tempfile = { version = "3.3", optional = true }
|
tempfile = { version = "3.3", optional = true }
|
||||||
termize = "0.1"
|
termize = "0.1"
|
||||||
color-print = "0.3.4"
|
color-print = "0.3.4"
|
||||||
anstream = "0.6.0"
|
anstream = "0.6.18"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cargo_metadata = "0.18.1"
|
cargo_metadata = "0.18.1"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
- [Configuration](configuration.md)
|
- [Configuration](configuration.md)
|
||||||
- [Lint Configuration](lint_configuration.md)
|
- [Lint Configuration](lint_configuration.md)
|
||||||
- [Clippy's Lints](lints.md)
|
- [Clippy's Lints](lints.md)
|
||||||
|
- [Attributes for Crate Authors](attribs.md)
|
||||||
- [Continuous Integration](continuous_integration/README.md)
|
- [Continuous Integration](continuous_integration/README.md)
|
||||||
- [GitHub Actions](continuous_integration/github_actions.md)
|
- [GitHub Actions](continuous_integration/github_actions.md)
|
||||||
- [GitLab CI](continuous_integration/gitlab.md)
|
- [GitLab CI](continuous_integration/gitlab.md)
|
||||||
|
|
53
src/tools/clippy/book/src/attribs.md
Normal file
53
src/tools/clippy/book/src/attribs.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Attributes for Crate Authors
|
||||||
|
|
||||||
|
In some cases it is possible to extend Clippy coverage to 3rd party libraries.
|
||||||
|
To do this, Clippy provides attributes that can be applied to items in the 3rd party crate.
|
||||||
|
|
||||||
|
## `#[clippy::format_args]`
|
||||||
|
|
||||||
|
_Available since Clippy v1.84_
|
||||||
|
|
||||||
|
This attribute can be added to a macro that supports `format!`, `println!`, or similar syntax.
|
||||||
|
It tells Clippy that the macro is a formatting macro, and that the arguments to the macro
|
||||||
|
should be linted as if they were arguments to `format!`. Any lint that would apply to a
|
||||||
|
`format!` call will also apply to the macro call. The macro may have additional arguments
|
||||||
|
before the format string, and these will be ignored.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// A macro that prints a message if a condition is true.
|
||||||
|
#[macro_export]
|
||||||
|
#[clippy::format_args]
|
||||||
|
macro_rules! print_if {
|
||||||
|
($condition:expr, $($args:tt)+) => {{
|
||||||
|
if $condition {
|
||||||
|
println!($($args)+)
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `#[clippy::has_significant_drop]`
|
||||||
|
|
||||||
|
_Available since Clippy v1.60_
|
||||||
|
|
||||||
|
The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have an important side effect,
|
||||||
|
such as unlocking a mutex, making it important for users to be able to accurately understand their lifetimes.
|
||||||
|
When a temporary is returned in a function call in a match scrutinee, its lifetime lasts until the end of the match
|
||||||
|
block, which may be surprising.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[clippy::has_significant_drop]
|
||||||
|
struct CounterWrapper<'a> {
|
||||||
|
counter: &'a Counter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for CounterWrapper<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.counter.i.fetch_sub(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
|
@ -438,7 +438,7 @@ need to ensure that the MSRV configured for the project is >= the MSRV of the
|
||||||
required Rust feature. If multiple features are required, just use the one with
|
required Rust feature. If multiple features are required, just use the one with
|
||||||
a lower MSRV.
|
a lower MSRV.
|
||||||
|
|
||||||
First, add an MSRV alias for the required feature in [`clippy_config::msrvs`].
|
First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`].
|
||||||
This can be accessed later as `msrvs::STR_STRIP_PREFIX`, for example.
|
This can be accessed later as `msrvs::STR_STRIP_PREFIX`, for example.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -517,7 +517,7 @@ define_Conf! {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`clippy_config::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_config/msrvs/index.html
|
[`clippy_utils::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_config/msrvs/index.html
|
||||||
|
|
||||||
Afterwards update the documentation for the book as described in [Adding configuration to a lint](#adding-configuration-to-a-lint).
|
Afterwards update the documentation for the book as described in [Adding configuration to a lint](#adding-configuration-to-a-lint).
|
||||||
|
|
||||||
|
|
|
@ -895,7 +895,7 @@ The order of associated items in traits.
|
||||||
|
|
||||||
## `trivial-copy-size-limit`
|
## `trivial-copy-size-limit`
|
||||||
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
|
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
|
||||||
reference. By default there is no limit
|
reference.
|
||||||
|
|
||||||
**Default Value:** `target_pointer_width * 2`
|
**Default Value:** `target_pointer_width * 2`
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
[package]
|
[package]
|
||||||
name = "clippy_config"
|
name = "clippy_config"
|
||||||
version = "0.1.84"
|
# begin autogenerated version
|
||||||
|
version = "0.1.85"
|
||||||
|
# end autogenerated version
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
clippy_utils = { path = "../clippy_utils" }
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
toml = "0.7.3"
|
toml = "0.7.3"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::ClippyConfiguration;
|
use crate::ClippyConfiguration;
|
||||||
use crate::msrvs::Msrv;
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering,
|
DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering,
|
||||||
SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
|
SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
|
||||||
SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
|
SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
|
||||||
};
|
};
|
||||||
|
use clippy_utils::msrvs::Msrv;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::edit_distance::edit_distance;
|
use rustc_span::edit_distance::edit_distance;
|
||||||
|
@ -181,7 +181,7 @@ macro_rules! define_Conf {
|
||||||
)*) => {
|
)*) => {
|
||||||
/// Clippy lint configuration
|
/// Clippy lint configuration
|
||||||
pub struct Conf {
|
pub struct Conf {
|
||||||
$($(#[doc = $doc])+ pub $name: $ty,)*
|
$($(#[cfg_attr(doc, doc = $doc)])+ pub $name: $ty,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
mod defaults {
|
mod defaults {
|
||||||
|
@ -678,7 +678,7 @@ define_Conf! {
|
||||||
#[lints(arbitrary_source_item_ordering)]
|
#[lints(arbitrary_source_item_ordering)]
|
||||||
trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(),
|
trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(),
|
||||||
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
|
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
|
||||||
/// reference. By default there is no limit
|
/// reference.
|
||||||
#[default_text = "target_pointer_width * 2"]
|
#[default_text = "target_pointer_width * 2"]
|
||||||
#[lints(trivially_copy_pass_by_ref)]
|
#[lints(trivially_copy_pass_by_ref)]
|
||||||
trivial_copy_size_limit: Option<u64> = None,
|
trivial_copy_size_limit: Option<u64> = None,
|
||||||
|
|
|
@ -13,18 +13,14 @@
|
||||||
rustc::untranslatable_diagnostic
|
rustc::untranslatable_diagnostic
|
||||||
)]
|
)]
|
||||||
|
|
||||||
extern crate rustc_ast;
|
|
||||||
extern crate rustc_attr;
|
|
||||||
#[allow(unused_extern_crates)]
|
|
||||||
extern crate rustc_driver;
|
|
||||||
extern crate rustc_errors;
|
extern crate rustc_errors;
|
||||||
|
extern crate rustc_hir;
|
||||||
|
extern crate rustc_middle;
|
||||||
extern crate rustc_session;
|
extern crate rustc_session;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
extern crate smallvec;
|
|
||||||
|
|
||||||
mod conf;
|
mod conf;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
pub mod msrvs;
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub use conf::{Conf, get_configuration_metadata, lookup_conf_file, sanitize_explanation};
|
pub use conf::{Conf, get_configuration_metadata, lookup_conf_file, sanitize_explanation};
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use clippy_utils::def_path_def_ids;
|
||||||
|
use rustc_hir::def_id::DefIdMap;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use serde::de::{self, Deserializer, Visitor};
|
use serde::de::{self, Deserializer, Visitor};
|
||||||
use serde::{Deserialize, Serialize, ser};
|
use serde::{Deserialize, Serialize, ser};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -31,6 +34,18 @@ impl DisallowedPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a map of disallowed items to the reason they were disallowed.
|
||||||
|
pub fn create_disallowed_map(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
disallowed: &'static [DisallowedPath],
|
||||||
|
) -> DefIdMap<(&'static str, Option<&'static str>)> {
|
||||||
|
disallowed
|
||||||
|
.iter()
|
||||||
|
.map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x.reason()))
|
||||||
|
.flat_map(|(name, path, reason)| def_path_def_ids(tcx, &path).map(move |id| (id, (name, reason))))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub enum MatchLintBehaviour {
|
pub enum MatchLintBehaviour {
|
||||||
AllTypes,
|
AllTypes,
|
||||||
|
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aho-corasick = "1.0"
|
aho-corasick = "1.0"
|
||||||
|
chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
|
||||||
clap = { version = "4.4", features = ["derive"] }
|
clap = { version = "4.4", features = ["derive"] }
|
||||||
indoc = "1.0"
|
indoc = "1.0"
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{clippy_project_root, exit_if_err};
|
use crate::utils::{clippy_project_root, exit_if_err};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::clippy_project_root;
|
use crate::utils::clippy_project_root;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_lexer::{TokenKind, tokenize};
|
use rustc_lexer::{TokenKind, tokenize};
|
||||||
use shell_escape::escape;
|
use shell_escape::escape;
|
||||||
|
|
|
@ -14,69 +14,13 @@
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_lexer;
|
extern crate rustc_lexer;
|
||||||
|
|
||||||
use std::io;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::{self, ExitStatus};
|
|
||||||
|
|
||||||
pub mod dogfood;
|
pub mod dogfood;
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod lint;
|
pub mod lint;
|
||||||
pub mod new_lint;
|
pub mod new_lint;
|
||||||
|
pub mod release;
|
||||||
pub mod serve;
|
pub mod serve;
|
||||||
pub mod setup;
|
pub mod setup;
|
||||||
|
pub mod sync;
|
||||||
pub mod update_lints;
|
pub mod update_lints;
|
||||||
|
pub mod utils;
|
||||||
#[cfg(not(windows))]
|
|
||||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
|
||||||
#[cfg(windows)]
|
|
||||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
|
|
||||||
|
|
||||||
/// Returns the path to the `cargo-clippy` binary
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the path of current executable could not be retrieved.
|
|
||||||
#[must_use]
|
|
||||||
pub fn cargo_clippy_path() -> PathBuf {
|
|
||||||
let mut path = std::env::current_exe().expect("failed to get current executable name");
|
|
||||||
path.set_file_name(CARGO_CLIPPY_EXE);
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the path to the Clippy project directory
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the current directory could not be retrieved, there was an error reading any of the
|
|
||||||
/// Cargo.toml files or ancestor directory is the clippy root directory
|
|
||||||
#[must_use]
|
|
||||||
pub fn clippy_project_root() -> PathBuf {
|
|
||||||
let current_dir = std::env::current_dir().unwrap();
|
|
||||||
for path in current_dir.ancestors() {
|
|
||||||
let result = std::fs::read_to_string(path.join("Cargo.toml"));
|
|
||||||
if let Err(err) = &result {
|
|
||||||
if err.kind() == io::ErrorKind::NotFound {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = result.unwrap();
|
|
||||||
if content.contains("[package]\nname = \"clippy\"") {
|
|
||||||
return path.to_path_buf();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Panics
|
|
||||||
/// Panics if given command result was failed.
|
|
||||||
pub fn exit_if_err(status: io::Result<ExitStatus>) {
|
|
||||||
match status.expect("failed to run command").code() {
|
|
||||||
Some(0) => {},
|
|
||||||
Some(n) => process::exit(n),
|
|
||||||
None => {
|
|
||||||
eprintln!("Killed by signal");
|
|
||||||
process::exit(1);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{cargo_clippy_path, exit_if_err};
|
use crate::utils::{cargo_clippy_path, exit_if_err};
|
||||||
use std::process::{self, Command};
|
use std::process::{self, Command};
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
|
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints};
|
use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -23,9 +23,9 @@ fn main() {
|
||||||
if print_only {
|
if print_only {
|
||||||
update_lints::print_lints();
|
update_lints::print_lints();
|
||||||
} else if check {
|
} else if check {
|
||||||
update_lints::update(update_lints::UpdateMode::Check);
|
update_lints::update(utils::UpdateMode::Check);
|
||||||
} else {
|
} else {
|
||||||
update_lints::update(update_lints::UpdateMode::Change);
|
update_lints::update(utils::UpdateMode::Change);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DevCommand::NewLint {
|
DevCommand::NewLint {
|
||||||
|
@ -35,7 +35,7 @@ fn main() {
|
||||||
r#type,
|
r#type,
|
||||||
msrv,
|
msrv,
|
||||||
} => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) {
|
} => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) {
|
||||||
Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
|
Ok(()) => update_lints::update(utils::UpdateMode::Change),
|
||||||
Err(e) => eprintln!("Unable to create lint: {e}"),
|
Err(e) => eprintln!("Unable to create lint: {e}"),
|
||||||
},
|
},
|
||||||
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
|
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
|
||||||
|
@ -75,6 +75,12 @@ fn main() {
|
||||||
uplift,
|
uplift,
|
||||||
} => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
|
} => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
|
||||||
DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason),
|
DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason),
|
||||||
|
DevCommand::Sync(SyncCommand { subcommand }) => match subcommand {
|
||||||
|
SyncSubcommand::UpdateNightly => sync::update_nightly(),
|
||||||
|
},
|
||||||
|
DevCommand::Release(ReleaseCommand { subcommand }) => match subcommand {
|
||||||
|
ReleaseSubcommand::BumpVersion => release::bump_version(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +231,10 @@ enum DevCommand {
|
||||||
/// The reason for deprecation
|
/// The reason for deprecation
|
||||||
reason: String,
|
reason: String,
|
||||||
},
|
},
|
||||||
|
/// Sync between the rust repo and the Clippy repo
|
||||||
|
Sync(SyncCommand),
|
||||||
|
/// Manage Clippy releases
|
||||||
|
Release(ReleaseCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
@ -291,3 +301,29 @@ enum RemoveSubcommand {
|
||||||
/// Remove the tasks added with 'cargo dev setup vscode-tasks'
|
/// Remove the tasks added with 'cargo dev setup vscode-tasks'
|
||||||
VscodeTasks,
|
VscodeTasks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
struct SyncCommand {
|
||||||
|
#[command(subcommand)]
|
||||||
|
subcommand: SyncSubcommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum SyncSubcommand {
|
||||||
|
#[command(name = "update_nightly")]
|
||||||
|
/// Update nightly version in rust-toolchain and `clippy_utils`
|
||||||
|
UpdateNightly,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
struct ReleaseCommand {
|
||||||
|
#[command(subcommand)]
|
||||||
|
subcommand: ReleaseSubcommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum ReleaseSubcommand {
|
||||||
|
#[command(name = "bump_version")]
|
||||||
|
/// Bump the version in the Cargo.toml files
|
||||||
|
BumpVersion,
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::clippy_project_root;
|
use crate::utils::{clippy_project_root, clippy_version};
|
||||||
use indoc::{formatdoc, writedoc};
|
use indoc::{formatdoc, writedoc};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
|
@ -186,23 +186,8 @@ fn to_camel_case(name: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_stabilization_version() -> String {
|
pub(crate) fn get_stabilization_version() -> String {
|
||||||
fn parse_manifest(contents: &str) -> Option<String> {
|
let (minor, patch) = clippy_version();
|
||||||
let version = contents
|
format!("{minor}.{patch}.0")
|
||||||
.lines()
|
|
||||||
.filter_map(|l| l.split_once('='))
|
|
||||||
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
|
|
||||||
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let (minor, patch) = version.split_once('.')?;
|
|
||||||
Some(format!(
|
|
||||||
"{}.{}.0",
|
|
||||||
minor.parse::<u32>().ok()?,
|
|
||||||
patch.parse::<u32>().ok()?
|
|
||||||
))
|
|
||||||
}
|
|
||||||
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
|
|
||||||
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
|
fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
|
||||||
|
@ -273,7 +258,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
||||||
result.push_str(&if enable_msrv {
|
result.push_str(&if enable_msrv {
|
||||||
formatdoc!(
|
formatdoc!(
|
||||||
r"
|
r"
|
||||||
use clippy_config::msrvs::{{self, Msrv}};
|
use clippy_utils::msrvs::{{self, Msrv}};
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
{pass_import}
|
{pass_import}
|
||||||
use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
|
use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
|
||||||
|
@ -399,7 +384,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
|
||||||
let _: fmt::Result = writedoc!(
|
let _: fmt::Result = writedoc!(
|
||||||
lint_file_contents,
|
lint_file_contents,
|
||||||
r#"
|
r#"
|
||||||
use clippy_config::msrvs::{{self, Msrv}};
|
use clippy_utils::msrvs::{{self, Msrv}};
|
||||||
use rustc_lint::{{{context_import}, LintContext}};
|
use rustc_lint::{{{context_import}, LintContext}};
|
||||||
|
|
||||||
use super::{name_upper};
|
use super::{name_upper};
|
||||||
|
|
27
src/tools/clippy/clippy_dev/src/release.rs
Normal file
27
src/tools/clippy/clippy_dev/src/release.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::utils::{UpdateMode, clippy_version, replace_region_in_file};
|
||||||
|
|
||||||
|
const CARGO_TOML_FILES: [&str; 4] = [
|
||||||
|
"clippy_config/Cargo.toml",
|
||||||
|
"clippy_lints/Cargo.toml",
|
||||||
|
"clippy_utils/Cargo.toml",
|
||||||
|
"Cargo.toml",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn bump_version() {
|
||||||
|
let (minor, mut patch) = clippy_version();
|
||||||
|
patch += 1;
|
||||||
|
for file in &CARGO_TOML_FILES {
|
||||||
|
replace_region_in_file(
|
||||||
|
UpdateMode::Change,
|
||||||
|
Path::new(file),
|
||||||
|
"# begin autogenerated version\n",
|
||||||
|
"# end autogenerated version",
|
||||||
|
|res| {
|
||||||
|
writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
33
src/tools/clippy/clippy_dev/src/sync.rs
Normal file
33
src/tools/clippy/clippy_dev/src/sync.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use chrono::offset::Utc;
|
||||||
|
|
||||||
|
use crate::utils::{UpdateMode, replace_region_in_file};
|
||||||
|
|
||||||
|
pub fn update_nightly() {
|
||||||
|
// Update rust-toolchain nightly version
|
||||||
|
let date = Utc::now().format("%Y-%m-%d").to_string();
|
||||||
|
replace_region_in_file(
|
||||||
|
UpdateMode::Change,
|
||||||
|
Path::new("rust-toolchain"),
|
||||||
|
"# begin autogenerated nightly\n",
|
||||||
|
"# end autogenerated nightly",
|
||||||
|
|res| {
|
||||||
|
writeln!(res, "channel = \"nightly-{date}\"").unwrap();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update clippy_utils nightly version
|
||||||
|
replace_region_in_file(
|
||||||
|
UpdateMode::Change,
|
||||||
|
Path::new("clippy_utils/README.md"),
|
||||||
|
"<!-- begin autogenerated nightly -->\n",
|
||||||
|
"<!-- end autogenerated nightly -->",
|
||||||
|
|res| {
|
||||||
|
writeln!(res, "```").unwrap();
|
||||||
|
writeln!(res, "nightly-{date}").unwrap();
|
||||||
|
writeln!(res, "```").unwrap();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::clippy_project_root;
|
use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file};
|
||||||
use aho_corasick::AhoCorasickBuilder;
|
use aho_corasick::AhoCorasickBuilder;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape};
|
use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape};
|
||||||
|
@ -17,12 +17,6 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u
|
||||||
|
|
||||||
const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
|
const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum UpdateMode {
|
|
||||||
Check,
|
|
||||||
Change,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs the `update_lints` command.
|
/// Runs the `update_lints` command.
|
||||||
///
|
///
|
||||||
/// This updates various generated values from the lint source code.
|
/// This updates various generated values from the lint source code.
|
||||||
|
@ -511,14 +505,6 @@ fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit_with_failure() {
|
|
||||||
println!(
|
|
||||||
"Not all lints defined properly. \
|
|
||||||
Please run `cargo dev update_lints` to make sure all lints are defined properly."
|
|
||||||
);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lint data parsed from the Clippy source code.
|
/// Lint data parsed from the Clippy source code.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
struct Lint {
|
struct Lint {
|
||||||
|
@ -851,61 +837,6 @@ fn remove_line_splices(s: &str) -> String {
|
||||||
});
|
});
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces a region in a file delimited by two lines matching regexes.
|
|
||||||
///
|
|
||||||
/// `path` is the relative path to the file on which you want to perform the replacement.
|
|
||||||
///
|
|
||||||
/// See `replace_region_in_text` for documentation of the other options.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the path could not read or then written
|
|
||||||
fn replace_region_in_file(
|
|
||||||
update_mode: UpdateMode,
|
|
||||||
path: &Path,
|
|
||||||
start: &str,
|
|
||||||
end: &str,
|
|
||||||
write_replacement: impl FnMut(&mut String),
|
|
||||||
) {
|
|
||||||
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
|
|
||||||
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
|
|
||||||
};
|
|
||||||
|
|
||||||
match update_mode {
|
|
||||||
UpdateMode::Check if contents != new_contents => exit_with_failure(),
|
|
||||||
UpdateMode::Check => (),
|
|
||||||
UpdateMode::Change => {
|
|
||||||
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
|
|
||||||
panic!("Cannot write to `{}`: {e}", path.display());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
|
|
||||||
/// were found, or the missing delimiter if not.
|
|
||||||
fn replace_region_in_text<'a>(
|
|
||||||
text: &str,
|
|
||||||
start: &'a str,
|
|
||||||
end: &'a str,
|
|
||||||
mut write_replacement: impl FnMut(&mut String),
|
|
||||||
) -> Result<String, &'a str> {
|
|
||||||
let (text_start, rest) = text.split_once(start).ok_or(start)?;
|
|
||||||
let (_, text_end) = rest.split_once(end).ok_or(end)?;
|
|
||||||
|
|
||||||
let mut res = String::with_capacity(text.len() + 4096);
|
|
||||||
res.push_str(text_start);
|
|
||||||
res.push_str(start);
|
|
||||||
write_replacement(&mut res);
|
|
||||||
res.push_str(end);
|
|
||||||
res.push_str(text_end);
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
|
fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
|
||||||
match OpenOptions::new().create_new(true).write(true).open(new_name) {
|
match OpenOptions::new().create_new(true).write(true).open(new_name) {
|
||||||
Ok(file) => drop(file),
|
Ok(file) => drop(file),
|
||||||
|
|
142
src/tools/clippy/clippy_dev/src/utils.rs
Normal file
142
src/tools/clippy/clippy_dev/src/utils.rs
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::{self, ExitStatus};
|
||||||
|
use std::{fs, io};
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
||||||
|
#[cfg(windows)]
|
||||||
|
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
|
||||||
|
|
||||||
|
/// Returns the path to the `cargo-clippy` binary
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the path of current executable could not be retrieved.
|
||||||
|
#[must_use]
|
||||||
|
pub fn cargo_clippy_path() -> PathBuf {
|
||||||
|
let mut path = std::env::current_exe().expect("failed to get current executable name");
|
||||||
|
path.set_file_name(CARGO_CLIPPY_EXE);
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the path to the Clippy project directory
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the current directory could not be retrieved, there was an error reading any of the
|
||||||
|
/// Cargo.toml files or ancestor directory is the clippy root directory
|
||||||
|
#[must_use]
|
||||||
|
pub fn clippy_project_root() -> PathBuf {
|
||||||
|
let current_dir = std::env::current_dir().unwrap();
|
||||||
|
for path in current_dir.ancestors() {
|
||||||
|
let result = fs::read_to_string(path.join("Cargo.toml"));
|
||||||
|
if let Err(err) = &result {
|
||||||
|
if err.kind() == io::ErrorKind::NotFound {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = result.unwrap();
|
||||||
|
if content.contains("[package]\nname = \"clippy\"") {
|
||||||
|
return path.to_path_buf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if given command result was failed.
|
||||||
|
pub fn exit_if_err(status: io::Result<ExitStatus>) {
|
||||||
|
match status.expect("failed to run command").code() {
|
||||||
|
Some(0) => {},
|
||||||
|
Some(n) => process::exit(n),
|
||||||
|
None => {
|
||||||
|
eprintln!("Killed by signal");
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn clippy_version() -> (u32, u32) {
|
||||||
|
fn parse_manifest(contents: &str) -> Option<(u32, u32)> {
|
||||||
|
let version = contents
|
||||||
|
.lines()
|
||||||
|
.filter_map(|l| l.split_once('='))
|
||||||
|
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
|
||||||
|
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let (minor, patch) = version.split_once('.')?;
|
||||||
|
Some((minor.parse().ok()?, patch.parse().ok()?))
|
||||||
|
}
|
||||||
|
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
|
||||||
|
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum UpdateMode {
|
||||||
|
Check,
|
||||||
|
Change,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn exit_with_failure() {
|
||||||
|
println!(
|
||||||
|
"Not all lints defined properly. \
|
||||||
|
Please run `cargo dev update_lints` to make sure all lints are defined properly."
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces a region in a file delimited by two lines matching regexes.
|
||||||
|
///
|
||||||
|
/// `path` is the relative path to the file on which you want to perform the replacement.
|
||||||
|
///
|
||||||
|
/// See `replace_region_in_text` for documentation of the other options.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the path could not read or then written
|
||||||
|
pub(crate) fn replace_region_in_file(
|
||||||
|
update_mode: UpdateMode,
|
||||||
|
path: &Path,
|
||||||
|
start: &str,
|
||||||
|
end: &str,
|
||||||
|
write_replacement: impl FnMut(&mut String),
|
||||||
|
) {
|
||||||
|
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
|
||||||
|
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match update_mode {
|
||||||
|
UpdateMode::Check if contents != new_contents => exit_with_failure(),
|
||||||
|
UpdateMode::Check => (),
|
||||||
|
UpdateMode::Change => {
|
||||||
|
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
|
||||||
|
panic!("Cannot write to `{}`: {e}", path.display());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
|
||||||
|
/// were found, or the missing delimiter if not.
|
||||||
|
pub(crate) fn replace_region_in_text<'a>(
|
||||||
|
text: &str,
|
||||||
|
start: &'a str,
|
||||||
|
end: &'a str,
|
||||||
|
mut write_replacement: impl FnMut(&mut String),
|
||||||
|
) -> Result<String, &'a str> {
|
||||||
|
let (text_start, rest) = text.split_once(start).ok_or(start)?;
|
||||||
|
let (_, text_end) = rest.split_once(end).ok_or(end)?;
|
||||||
|
|
||||||
|
let mut res = String::with_capacity(text.len() + 4096);
|
||||||
|
res.push_str(text_start);
|
||||||
|
res.push_str(start);
|
||||||
|
write_replacement(&mut res);
|
||||||
|
res.push_str(end);
|
||||||
|
res.push_str(text_end);
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "clippy_lints"
|
name = "clippy_lints"
|
||||||
version = "0.1.84"
|
# begin autogenerated version
|
||||||
|
version = "0.1.85"
|
||||||
|
# end autogenerated version
|
||||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||||
repository = "https://github.com/rust-lang/rust-clippy"
|
repository = "https://github.com/rust-lang/rust-clippy"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::{trim_span, walk_span_to_context};
|
use clippy_utils::source::{trim_span, walk_span_to_context};
|
||||||
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
|
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
|
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
|
||||||
use rustc_hir::{Expr, ExprKind};
|
use rustc_hir::{Expr, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
@ -91,7 +91,7 @@ impl ApproxConstant {
|
||||||
let s = s.as_str();
|
let s = s.as_str();
|
||||||
if s.parse::<f64>().is_ok() {
|
if s.parse::<f64>().is_ok() {
|
||||||
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
|
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
|
||||||
if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| self.msrv.meets(msrv)) {
|
if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(msrv)) {
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
APPROX_CONSTANT,
|
APPROX_CONSTANT,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
|
use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
|
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -100,13 +100,13 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
|
||||||
// TODO: This check currently bails if the local variable has no initializer.
|
// TODO: This check currently bails if the local variable has no initializer.
|
||||||
// That is overly conservative - the lint should fire even if there was no initializer,
|
// That is overly conservative - the lint should fire even if there was no initializer,
|
||||||
// but the variable has been initialized before `lhs` was evaluated.
|
// but the variable has been initialized before `lhs` was evaluated.
|
||||||
&& path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs))
|
&& path_to_local(lhs).is_none_or(|lhs| local_is_initialized(cx, lhs))
|
||||||
&& let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id())
|
&& let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id())
|
||||||
// Derived forms don't implement `clone_from`/`clone_into`.
|
// Derived forms don't implement `clone_from`/`clone_into`.
|
||||||
// See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
|
// See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
|
||||||
&& !cx.tcx.is_builtin_derived(resolved_impl)
|
&& !cx.tcx.is_builtin_derived(resolved_impl)
|
||||||
// Don't suggest calling a function we're implementing.
|
// Don't suggest calling a function we're implementing.
|
||||||
&& resolved_impl.as_local().map_or(true, |block_id| {
|
&& resolved_impl.as_local().is_none_or(|block_id| {
|
||||||
cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id)
|
cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id)
|
||||||
})
|
})
|
||||||
&& let resolved_assoc_items = cx.tcx.associated_items(resolved_impl)
|
&& let resolved_assoc_items = cx.tcx.associated_items(resolved_impl)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg};
|
use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg};
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use rustc_ast::AttrStyle;
|
use rustc_ast::AttrStyle;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_lint::EarlyContext;
|
use rustc_lint::EarlyContext;
|
||||||
|
|
|
@ -13,7 +13,7 @@ mod useless_attribute;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
|
use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
|
||||||
use rustc_hir::{ImplItem, Item, TraitItem};
|
use rustc_hir::{ImplItem, Item, TraitItem};
|
||||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
|
use clippy_config::types::create_disallowed_map;
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::{create_disallowed_map, match_def_path, paths};
|
use clippy_utils::{match_def_path, paths};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, DefIdMap};
|
use rustc_hir::def_id::{DefId, DefIdMap};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||||
use clippy_utils::eq_expr_value;
|
use clippy_utils::eq_expr_value;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||||
&& !addrof_target.span.from_expansion()
|
&& !addrof_target.span.from_expansion()
|
||||||
&& let ref_ty = cx.typeck_results().expr_ty(deref_target)
|
&& let ref_ty = cx.typeck_results().expr_ty(deref_target)
|
||||||
&& let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
|
&& let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
|
||||||
&& get_parent_expr(cx, e).map_or(true, |parent| {
|
&& get_parent_expr(cx, e).is_none_or(|parent| {
|
||||||
match parent.kind {
|
match parent.kind {
|
||||||
// `*&*foo` should lint `deref_addrof` instead.
|
// `*&*foo` should lint `deref_addrof` instead.
|
||||||
ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id),
|
ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id),
|
||||||
|
|
|
@ -43,7 +43,7 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: Option<&T>) -> bool {
|
fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: Option<&T>) -> bool {
|
||||||
value.map_or(true, |s| s.as_ref().is_empty())
|
value.is_none_or(|s| s.as_ref().is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty_vec(value: &[String]) -> bool {
|
fn is_empty_vec(value: &[String]) -> bool {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind};
|
use rustc_hir::{Expr, ExprKind};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::is_in_const_context;
|
use clippy_utils::is_in_const_context;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::ty::is_isize_or_usize;
|
use clippy_utils::ty::is_isize_or_usize;
|
||||||
|
|
|
@ -134,7 +134,7 @@ pub(super) fn check(
|
||||||
};
|
};
|
||||||
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
|
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
|
||||||
|
|
||||||
let cast_from_ptr_size = def.repr().int.map_or(true, |ty| matches!(ty, IntegerType::Pointer(_),));
|
let cast_from_ptr_size = def.repr().int.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),));
|
||||||
let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
|
let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
|
||||||
(_, false) if from_nbits > to_nbits => "",
|
(_, false) if from_nbits > to_nbits => "",
|
||||||
(false, true) if from_nbits > 64 => "",
|
(false, true) if from_nbits > 64 => "",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source;
|
use clippy_utils::source;
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_hir::{Expr, ExprKind, Node};
|
use rustc_hir::{Expr, ExprKind, Node};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
|
|
@ -24,8 +24,8 @@ mod utils;
|
||||||
mod zero_ptr;
|
mod zero_ptr;
|
||||||
|
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::is_hir_ty_cfg_dependant;
|
use clippy_utils::is_hir_ty_cfg_dependant;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use rustc_hir::{Expr, ExprKind};
|
use rustc_hir::{Expr, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::std_or_core;
|
use clippy_utils::std_or_core;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
|
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -212,7 +212,7 @@ fn lint_if_same_then_else(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[&
|
||||||
.array_windows::<2>()
|
.array_windows::<2>()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.fold(true, |all_eq, (i, &[lhs, rhs])| {
|
.fold(true, |all_eq, (i, &[lhs, rhs])| {
|
||||||
if eq.eq_block(lhs, rhs) && !contains_let(conds[i]) && conds.get(i + 1).map_or(true, |e| !contains_let(e)) {
|
if eq.eq_block(lhs, rhs) && !contains_let(conds[i]) && conds.get(i + 1).is_none_or(|e| !contains_let(e)) {
|
||||||
span_lint_and_note(
|
span_lint_and_note(
|
||||||
cx,
|
cx,
|
||||||
IF_SAME_THEN_ELSE,
|
IF_SAME_THEN_ELSE,
|
||||||
|
@ -470,7 +470,7 @@ fn scan_block_for_eq<'tcx>(
|
||||||
b.stmts
|
b.stmts
|
||||||
// the bounds check will catch the underflow
|
// the bounds check will catch the underflow
|
||||||
.get(b.stmts.len().wrapping_sub(offset + 1))
|
.get(b.stmts.len().wrapping_sub(offset + 1))
|
||||||
.map_or(true, |s| hash != hash_stmt(cx, s))
|
.is_none_or(|s| hash != hash_stmt(cx, s))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map_or(block.stmts.len() - start_end_eq, |(i, _)| i);
|
.map_or(block.stmts.len() - start_end_eq, |(i, _)| i);
|
||||||
|
|
|
@ -135,6 +135,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::disallowed_names::DISALLOWED_NAMES_INFO,
|
crate::disallowed_names::DISALLOWED_NAMES_INFO,
|
||||||
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
|
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
|
||||||
crate::disallowed_types::DISALLOWED_TYPES_INFO,
|
crate::disallowed_types::DISALLOWED_TYPES_INFO,
|
||||||
|
crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO,
|
||||||
crate::doc::DOC_LAZY_CONTINUATION_INFO,
|
crate::doc::DOC_LAZY_CONTINUATION_INFO,
|
||||||
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
|
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
|
||||||
crate::doc::DOC_MARKDOWN_INFO,
|
crate::doc::DOC_MARKDOWN_INFO,
|
||||||
|
|
|
@ -10,12 +10,12 @@ use core::mem;
|
||||||
use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
|
use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::{Visitor, walk_ty};
|
use rustc_hir::intravisit::{Visitor, walk_ty};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
|
self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
|
||||||
PatKind, Path, QPath, TyKind, UnOp,
|
PatKind, Path, QPath, TyKind, UnOp,
|
||||||
};
|
};
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
|
||||||
|
@ -453,7 +453,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
||||||
));
|
));
|
||||||
} else if stability.is_deref_stable()
|
} else if stability.is_deref_stable()
|
||||||
// Auto-deref doesn't combine with other adjustments
|
// Auto-deref doesn't combine with other adjustments
|
||||||
&& next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
&& next_adjust.is_none_or(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
||||||
&& iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
&& iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
||||||
{
|
{
|
||||||
self.state = Some((State::Borrow { mutability }, StateData {
|
self.state = Some((State::Borrow { mutability }, StateData {
|
||||||
|
@ -1070,12 +1070,11 @@ fn report<'tcx>(
|
||||||
let mut app = Applicability::MachineApplicable;
|
let mut app = Applicability::MachineApplicable;
|
||||||
let (snip, snip_is_macro) =
|
let (snip, snip_is_macro) =
|
||||||
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
|
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
|
||||||
let sugg =
|
let sugg = if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
|
||||||
if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
|
format!("{prefix}({snip})")
|
||||||
format!("{prefix}({snip})")
|
} else {
|
||||||
} else {
|
format!("{prefix}{snip}")
|
||||||
format!("{prefix}{snip}")
|
};
|
||||||
};
|
|
||||||
diag.span_suggestion(data.first_expr.span, "try", sugg, app);
|
diag.span_suggestion(data.first_expr.span, "try", sugg, app);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::indent_of;
|
use clippy_utils::source::indent_of;
|
||||||
use clippy_utils::{is_default_equivalent, peel_blocks};
|
use clippy_utils::{is_default_equivalent, peel_blocks};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -132,17 +132,15 @@ fn check_struct<'tcx>(
|
||||||
|
|
||||||
if should_emit {
|
if should_emit {
|
||||||
let struct_span = cx.tcx.def_span(adt_def.did());
|
let struct_span = cx.tcx.def_span(adt_def.did());
|
||||||
|
let suggestions = vec![
|
||||||
|
(item.span, String::new()), // Remove the manual implementation
|
||||||
|
(struct_span.shrink_to_lo(), "#[derive(Default)]\n".to_string()), // Add the derive attribute
|
||||||
|
];
|
||||||
|
|
||||||
span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
|
span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
|
||||||
diag.span_suggestion_hidden(
|
diag.multipart_suggestion(
|
||||||
item.span,
|
"replace the manual implementation with a derive attribute",
|
||||||
"remove the manual implementation...",
|
suggestions,
|
||||||
String::new(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
diag.span_suggestion(
|
|
||||||
struct_span.shrink_to_lo(),
|
|
||||||
"...and instead derive it",
|
|
||||||
"#[derive(Default)]\n".to_string(),
|
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -161,23 +159,23 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
|
||||||
let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
|
let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
|
||||||
let variant_span = cx.tcx.def_span(variant_def.def_id);
|
let variant_span = cx.tcx.def_span(variant_def.def_id);
|
||||||
let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
|
let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
|
||||||
span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
|
|
||||||
diag.span_suggestion_hidden(
|
let suggestions = vec![
|
||||||
item.span,
|
(item.span, String::new()), // Remove the manual implementation
|
||||||
"remove the manual implementation...",
|
(
|
||||||
String::new(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
diag.span_suggestion(
|
|
||||||
enum_span.shrink_to_lo(),
|
enum_span.shrink_to_lo(),
|
||||||
"...and instead derive it...",
|
format!("#[derive(Default)]\n{}", " ".repeat(indent_enum)),
|
||||||
format!("#[derive(Default)]\n{indent}", indent = " ".repeat(indent_enum),),
|
), // Add the derive attribute
|
||||||
Applicability::MachineApplicable,
|
(
|
||||||
);
|
|
||||||
diag.span_suggestion(
|
|
||||||
variant_span.shrink_to_lo(),
|
variant_span.shrink_to_lo(),
|
||||||
"...and mark the default variant",
|
format!("#[default]\n{}", " ".repeat(indent_variant)),
|
||||||
format!("#[default]\n{indent}", indent = " ".repeat(indent_variant),),
|
), // Mark the default variant
|
||||||
|
];
|
||||||
|
|
||||||
|
span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
|
||||||
|
diag.multipart_suggestion(
|
||||||
|
"replace the manual implementation with a derive attribute and mark the default variant",
|
||||||
|
suggestions,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -505,17 +505,15 @@ fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let param_env = ParamEnv::new(
|
let param_env = ParamEnv::new(tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
|
||||||
tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
|
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
|
||||||
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
|
ClauseKind::Trait(TraitPredicate {
|
||||||
ClauseKind::Trait(TraitPredicate {
|
trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
|
||||||
trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
|
polarity: ty::PredicatePolarity::Positive,
|
||||||
polarity: ty::PredicatePolarity::Positive,
|
})
|
||||||
})
|
.upcast(tcx)
|
||||||
.upcast(tcx)
|
}),
|
||||||
}),
|
)));
|
||||||
)),
|
|
||||||
);
|
|
||||||
ty::TypingEnv {
|
ty::TypingEnv {
|
||||||
typing_mode: ty::TypingMode::non_body_analysis(),
|
typing_mode: ty::TypingMode::non_body_analysis(),
|
||||||
param_env,
|
param_env,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_utils::create_disallowed_map;
|
use clippy_config::types::create_disallowed_map;
|
||||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||||
use clippy_utils::macros::macro_backtrace;
|
use clippy_utils::macros::macro_backtrace;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_utils::create_disallowed_map;
|
use clippy_config::types::create_disallowed_map;
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefIdMap;
|
use rustc_hir::def_id::DefIdMap;
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::source::snippet_opt;
|
||||||
|
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, AttrStyle, Attribute};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
use super::DOC_INCLUDE_WITHOUT_CFG;
|
||||||
|
|
||||||
|
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
|
||||||
|
for attr in attrs {
|
||||||
|
if !attr.span.from_expansion()
|
||||||
|
&& let AttrKind::Normal(ref normal) = attr.kind
|
||||||
|
&& normal.item.path == sym::doc
|
||||||
|
&& let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args
|
||||||
|
&& !attr.span.contains(meta.span)
|
||||||
|
// Since the `include_str` is already expanded at this point, we can only take the
|
||||||
|
// whole attribute snippet and then modify for our suggestion.
|
||||||
|
&& let Some(snippet) = snippet_opt(cx, attr.span)
|
||||||
|
// We cannot remove this because a `#[doc = include_str!("...")]` attribute can occupy
|
||||||
|
// several lines.
|
||||||
|
&& let Some(start) = snippet.find('[')
|
||||||
|
&& let Some(end) = snippet.rfind(']')
|
||||||
|
&& let snippet = &snippet[start + 1..end]
|
||||||
|
// We check that the expansion actually comes from `include_str!` and not just from
|
||||||
|
// another macro.
|
||||||
|
&& let Some(sub_snippet) = snippet.trim().strip_prefix("doc")
|
||||||
|
&& let Some(sub_snippet) = sub_snippet.trim().strip_prefix("=")
|
||||||
|
&& sub_snippet.trim().starts_with("include_str!")
|
||||||
|
{
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
DOC_INCLUDE_WITHOUT_CFG,
|
||||||
|
attr.span,
|
||||||
|
"included a file in documentation unconditionally",
|
||||||
|
"use `cfg_attr(doc, doc = \"...\")`",
|
||||||
|
format!(
|
||||||
|
"#{}[cfg_attr(doc, {snippet})]",
|
||||||
|
if attr.style == AttrStyle::Inner { "!" } else { "" }
|
||||||
|
),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::lint_without_lint_pass)]
|
||||||
|
|
||||||
mod lazy_continuation;
|
mod lazy_continuation;
|
||||||
mod too_long_first_doc_paragraph;
|
mod too_long_first_doc_paragraph;
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ use std::ops::Range;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
mod empty_line_after;
|
mod empty_line_after;
|
||||||
|
mod include_in_doc_without_cfg;
|
||||||
mod link_with_quotes;
|
mod link_with_quotes;
|
||||||
mod markdown;
|
mod markdown;
|
||||||
mod missing_headers;
|
mod missing_headers;
|
||||||
|
@ -532,6 +535,35 @@ declare_clippy_lint! {
|
||||||
"empty line after doc comments"
|
"empty line after doc comments"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks if included files in doc comments are included only for `cfg(doc)`.
|
||||||
|
///
|
||||||
|
/// ### Why restrict this?
|
||||||
|
/// These files are not useful for compilation but will still be included.
|
||||||
|
/// Also, if any of these non-source code file is updated, it will trigger a
|
||||||
|
/// recompilation.
|
||||||
|
///
|
||||||
|
/// ### Known problems
|
||||||
|
///
|
||||||
|
/// Excluding this will currently result in the file being left out if
|
||||||
|
/// the item's docs are inlined from another crate. This may be fixed in a
|
||||||
|
/// future version of rustdoc.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```ignore
|
||||||
|
/// #![doc = include_str!("some_file.md")]
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```no_run
|
||||||
|
/// #![cfg_attr(doc, doc = include_str!("some_file.md"))]
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.84.0"]
|
||||||
|
pub DOC_INCLUDE_WITHOUT_CFG,
|
||||||
|
restriction,
|
||||||
|
"check if files included in documentation are behind `cfg(doc)`"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Documentation {
|
pub struct Documentation {
|
||||||
valid_idents: FxHashSet<String>,
|
valid_idents: FxHashSet<String>,
|
||||||
check_private_items: bool,
|
check_private_items: bool,
|
||||||
|
@ -561,6 +593,7 @@ impl_lint_pass!(Documentation => [
|
||||||
EMPTY_LINE_AFTER_OUTER_ATTR,
|
EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||||
EMPTY_LINE_AFTER_DOC_COMMENTS,
|
EMPTY_LINE_AFTER_DOC_COMMENTS,
|
||||||
TOO_LONG_FIRST_DOC_PARAGRAPH,
|
TOO_LONG_FIRST_DOC_PARAGRAPH,
|
||||||
|
DOC_INCLUDE_WITHOUT_CFG,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for Documentation {
|
impl<'tcx> LateLintPass<'tcx> for Documentation {
|
||||||
|
@ -690,6 +723,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
|
||||||
Some(("fake".into(), "fake".into()))
|
Some(("fake".into(), "fake".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
include_in_doc_without_cfg::check(cx, attrs);
|
||||||
if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) {
|
if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -917,6 +951,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||||
}
|
}
|
||||||
let trimmed_text = text.trim();
|
let trimmed_text = text.trim();
|
||||||
headers.safety |= in_heading && trimmed_text == "Safety";
|
headers.safety |= in_heading && trimmed_text == "Safety";
|
||||||
|
headers.safety |= in_heading && trimmed_text == "SAFETY";
|
||||||
headers.safety |= in_heading && trimmed_text == "Implementation safety";
|
headers.safety |= in_heading && trimmed_text == "Implementation safety";
|
||||||
headers.safety |= in_heading && trimmed_text == "Implementation Safety";
|
headers.safety |= in_heading && trimmed_text == "Implementation Safety";
|
||||||
headers.errors |= in_heading && trimmed_text == "Errors";
|
headers.errors |= in_heading && trimmed_text == "Errors";
|
||||||
|
|
|
@ -276,7 +276,7 @@ fn check_inputs(
|
||||||
&& typeck
|
&& typeck
|
||||||
.expr_adjustments(arg)
|
.expr_adjustments(arg)
|
||||||
.last()
|
.last()
|
||||||
.map_or(true, |a| a.target == typeck.expr_ty(arg))
|
.is_none_or(|a| a.target == typeck.expr_ty(arg))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
||||||
&& fn_header.abi == Abi::Rust
|
&& fn_header.abi == Abi::Rust
|
||||||
&& fn_decl.inputs.len() as u64 > self.max_fn_params_bools
|
&& 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))
|
&& 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())
|
.is_none_or(|impl_item| impl_item.of_trait.is_none())
|
||||||
{
|
{
|
||||||
check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools);
|
check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty};
|
use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
|
BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
|
||||||
PredicateOrigin, Ty, WherePredicate, WherePredicateKind
|
PredicateOrigin, Ty, WherePredicate, WherePredicateKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||||
use clippy_utils::is_diag_trait_item;
|
use clippy_utils::is_diag_trait_item;
|
||||||
use clippy_utils::macros::{
|
use clippy_utils::macros::{
|
||||||
|
@ -8,6 +7,7 @@ use clippy_utils::macros::{
|
||||||
format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call,
|
format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call,
|
||||||
root_macro_call_first_node,
|
root_macro_call_first_node,
|
||||||
};
|
};
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::macros::span_is_local;
|
use clippy_utils::macros::span_is_local;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::path_def_id;
|
use clippy_utils::path_def_id;
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
||||||
|diag| {
|
|diag| {
|
||||||
// If the target type is likely foreign mention the orphan rules as it's a common source of
|
// If the target type is likely foreign mention the orphan rules as it's a common source of
|
||||||
// confusion
|
// confusion
|
||||||
if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
|
if path_def_id(cx, target_ty.peel_refs()).is_none_or(|id| !id.is_local()) {
|
||||||
diag.help(
|
diag.help(
|
||||||
"`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
|
"`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
|
||||||
https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
|
https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::return_ty;
|
use clippy_utils::return_ty;
|
||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
|
@ -5,7 +7,9 @@ use rustc_hir::{Body, FnDecl};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::print::PrintTraitRefExt;
|
use rustc_middle::ty::print::PrintTraitRefExt;
|
||||||
use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
|
use rustc_middle::ty::{
|
||||||
|
self, AliasTy, Binder, ClauseKind, PredicateKind, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||||
|
};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::{Span, sym};
|
use rustc_span::{Span, sym};
|
||||||
|
@ -15,9 +19,16 @@ use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// This lint requires Future implementations returned from
|
/// This lint requires Future implementations returned from
|
||||||
/// functions and methods to implement the `Send` marker trait. It is mostly
|
/// functions and methods to implement the `Send` marker trait,
|
||||||
/// used by library authors (public and internal) that target an audience where
|
/// ignoring type parameters.
|
||||||
/// multithreaded executors are likely to be used for running these Futures.
|
///
|
||||||
|
/// If a function is generic and its Future conditionally implements `Send`
|
||||||
|
/// based on a generic parameter then it is considered `Send` and no warning is emitted.
|
||||||
|
///
|
||||||
|
/// This can be used by library authors (public and internal) to ensure
|
||||||
|
/// their functions are compatible with both multi-threaded runtimes that require `Send` futures,
|
||||||
|
/// as well as single-threaded runtimes where callers may choose `!Send` types
|
||||||
|
/// for generic parameters.
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// A Future implementation captures some state that it
|
/// A Future implementation captures some state that it
|
||||||
|
@ -64,22 +75,46 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
|
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() {
|
if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind()
|
||||||
|
&& let Some(future_trait) = cx.tcx.lang_items().future_trait()
|
||||||
|
&& let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
|
||||||
|
{
|
||||||
let preds = cx.tcx.explicit_item_super_predicates(def_id);
|
let preds = cx.tcx.explicit_item_super_predicates(def_id);
|
||||||
let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
|
let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
|
||||||
p.as_trait_clause().is_some_and(|trait_pred| {
|
p.as_trait_clause()
|
||||||
Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait()
|
.is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
|
||||||
})
|
|
||||||
});
|
});
|
||||||
if is_future {
|
if is_future {
|
||||||
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
|
||||||
let span = decl.output.span();
|
let span = decl.output.span();
|
||||||
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
|
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
|
||||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||||
let cause = traits::ObligationCause::misc(span, fn_def_id);
|
let cause = traits::ObligationCause::misc(span, fn_def_id);
|
||||||
ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
|
ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
|
||||||
let send_errors = ocx.select_all_or_error();
|
let send_errors = ocx.select_all_or_error();
|
||||||
if !send_errors.is_empty() {
|
|
||||||
|
// Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top
|
||||||
|
// level".
|
||||||
|
// For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors,
|
||||||
|
// which is always unconditionally `!Send` for any possible type `T`.
|
||||||
|
//
|
||||||
|
// We also allow associated type projections if the self type is either itself a projection or a
|
||||||
|
// type parameter.
|
||||||
|
// This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await
|
||||||
|
// points, where `Fut` is a type parameter.
|
||||||
|
|
||||||
|
let is_send = send_errors.iter().all(|err| {
|
||||||
|
err.obligation
|
||||||
|
.predicate
|
||||||
|
.as_trait_clause()
|
||||||
|
.map(Binder::skip_binder)
|
||||||
|
.is_some_and(|pred| {
|
||||||
|
pred.def_id() == send_trait
|
||||||
|
&& pred.self_ty().has_param()
|
||||||
|
&& TyParamAtTopLevelVisitor.visit_ty(pred.self_ty()) == ControlFlow::Break(true)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if !is_send {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
FUTURE_NOT_SEND,
|
FUTURE_NOT_SEND,
|
||||||
|
@ -107,3 +142,15 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TyParamAtTopLevelVisitor;
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TyParamAtTopLevelVisitor {
|
||||||
|
type Result = ControlFlow<bool>;
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||||
|
match ty.kind() {
|
||||||
|
ty::Param(_) => ControlFlow::Break(true),
|
||||||
|
ty::Alias(ty::AliasTyKind::Projection, ty) => ty.visit_with(self),
|
||||||
|
_ => ControlFlow::Break(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use rustc_errors::Diag;
|
||||||
use rustc_hir::{Expr, ExprKind};
|
use rustc_hir::{Expr, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
use rustc_span::edition::Edition::Edition2024;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
|
@ -14,6 +15,12 @@ declare_clippy_lint! {
|
||||||
/// Checks for `Mutex::lock` calls in `if let` expression
|
/// Checks for `Mutex::lock` calls in `if let` expression
|
||||||
/// with lock calls in any of the else blocks.
|
/// with lock calls in any of the else blocks.
|
||||||
///
|
///
|
||||||
|
/// ### Disabled starting in Edition 2024
|
||||||
|
/// This lint is effectively disabled starting in
|
||||||
|
/// Edition 2024 as `if let ... else` scoping was reworked
|
||||||
|
/// such that this is no longer an issue. See
|
||||||
|
/// [Proposal: stabilize if_let_rescope for Edition 2024](https://github.com/rust-lang/rust/issues/131154)
|
||||||
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// The Mutex lock remains held for the whole
|
/// The Mutex lock remains held for the whole
|
||||||
/// `if let ... else` block and deadlocks.
|
/// `if let ... else` block and deadlocks.
|
||||||
|
@ -45,6 +52,10 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||||
|
if cx.tcx.sess.edition() >= Edition2024 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(higher::IfLet {
|
if let Some(higher::IfLet {
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
|
@ -86,7 +97,7 @@ fn mutex_lock_call<'tcx>(
|
||||||
&& path.ident.as_str() == "lock"
|
&& path.ident.as_str() == "lock"
|
||||||
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
|
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
|
||||||
&& is_type_diagnostic_item(cx, ty, sym::Mutex)
|
&& is_type_diagnostic_item(cx, ty, sym::Mutex)
|
||||||
&& op_mutex.map_or(true, |op| eq_expr_value(cx, self_arg, op))
|
&& op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op))
|
||||||
{
|
{
|
||||||
ControlFlow::Break(self_arg)
|
ControlFlow::Break(self_arg)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
|
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::{
|
use clippy_utils::{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_opt;
|
use clippy_utils::source::snippet_opt;
|
||||||
use clippy_utils::{
|
use clippy_utils::{
|
||||||
SpanlessEq, higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt,
|
SpanlessEq, higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::Msrv;
|
|
||||||
use clippy_utils::diagnostics::span_lint;
|
use clippy_utils::diagnostics::span_lint;
|
||||||
use clippy_utils::is_in_test;
|
use clippy_utils::is_in_test;
|
||||||
|
use clippy_utils::msrvs::Msrv;
|
||||||
use rustc_attr::{StabilityLevel, StableSince};
|
use rustc_attr::{StabilityLevel, StableSince};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::{Expr, ExprKind, HirId};
|
use rustc_hir::{Expr, ExprKind, HirId};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::higher::IfLet;
|
use clippy_utils::higher::IfLet;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::ty::is_copy;
|
use clippy_utils::ty::is_copy;
|
||||||
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
|
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::ty;
|
use clippy_utils::ty;
|
||||||
|
|
|
@ -3,8 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Item, ItemKind};
|
use rustc_hir::{Item, ItemKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::layout::LayoutOf;
|
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
use rustc_middle::ty::layout::LayoutOf;
|
||||||
use rustc_session::impl_lint_pass;
|
use rustc_session::impl_lint_pass;
|
||||||
use rustc_span::{BytePos, Pos, Span};
|
use rustc_span::{BytePos, Pos, Span};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS};
|
|
||||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::{get_parent_expr, is_from_proc_macro};
|
use clippy_utils::{get_parent_expr, is_from_proc_macro};
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
||||||
// Integer modules are "TBD" deprecated, and the contents are too,
|
// Integer modules are "TBD" deprecated, and the contents are too,
|
||||||
// so lint on the `use` statement directly.
|
// so lint on the `use` statement directly.
|
||||||
if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
|
if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
|
||||||
&& self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
|
&& self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
|
||||||
&& !in_external_macro(cx.sess(), item.span)
|
&& !in_external_macro(cx.sess(), item.span)
|
||||||
&& let Some(def_id) = path.res[0].opt_def_id()
|
&& let Some(def_id) = path.res[0].opt_def_id()
|
||||||
{
|
{
|
||||||
|
@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
|
if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
|
||||||
&& !in_external_macro(cx.sess(), expr.span)
|
&& !in_external_macro(cx.sess(), expr.span)
|
||||||
&& !is_from_proc_macro(cx, expr)
|
&& !is_from_proc_macro(cx, expr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||||
use clippy_utils::trait_ref_of_method;
|
use clippy_utils::trait_ref_of_method;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use rustc_ast::visit::{try_visit, walk_list};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::FnRetTy::Return;
|
use rustc_hir::FnRetTy::Return;
|
||||||
|
@ -11,8 +12,9 @@ use rustc_hir::intravisit::{
|
||||||
};
|
};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
|
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
|
||||||
Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
|
HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
|
||||||
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, WherePredicateKind, lang_items,
|
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
|
||||||
|
WherePredicateKind, lang_items,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
|
@ -483,6 +485,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
|
||||||
struct Usage {
|
struct Usage {
|
||||||
lifetime: Lifetime,
|
lifetime: Lifetime,
|
||||||
in_where_predicate: bool,
|
in_where_predicate: bool,
|
||||||
|
in_bounded_ty: bool,
|
||||||
in_generics_arg: bool,
|
in_generics_arg: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,11 +493,15 @@ struct LifetimeChecker<'cx, 'tcx, F> {
|
||||||
cx: &'cx LateContext<'tcx>,
|
cx: &'cx LateContext<'tcx>,
|
||||||
map: FxIndexMap<LocalDefId, Vec<Usage>>,
|
map: FxIndexMap<LocalDefId, Vec<Usage>>,
|
||||||
where_predicate_depth: usize,
|
where_predicate_depth: usize,
|
||||||
|
bounded_ty_depth: usize,
|
||||||
generic_args_depth: usize,
|
generic_args_depth: usize,
|
||||||
phantom: std::marker::PhantomData<F>,
|
phantom: std::marker::PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
|
impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F>
|
||||||
|
where
|
||||||
|
F: NestedFilter<'tcx>,
|
||||||
|
{
|
||||||
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> {
|
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> {
|
||||||
let map = generics
|
let map = generics
|
||||||
.params
|
.params
|
||||||
|
@ -510,10 +517,30 @@ impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
|
||||||
cx,
|
cx,
|
||||||
map,
|
map,
|
||||||
where_predicate_depth: 0,
|
where_predicate_depth: 0,
|
||||||
|
bounded_ty_depth: 0,
|
||||||
generic_args_depth: 0,
|
generic_args_depth: 0,
|
||||||
phantom: std::marker::PhantomData,
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `visit_where_bound_predicate` is based on:
|
||||||
|
// https://github.com/rust-lang/rust/blob/864cee3ea383cc8254ba394ba355e648faa9cfa5/compiler/rustc_hir/src/intravisit.rs#L936-L939
|
||||||
|
fn visit_where_bound_predicate(
|
||||||
|
&mut self,
|
||||||
|
hir_id: HirId,
|
||||||
|
bounded_ty: &'tcx Ty<'tcx>,
|
||||||
|
bounds: &'tcx [GenericBound<'tcx>],
|
||||||
|
bound_generic_params: &'tcx [GenericParam<'tcx>],
|
||||||
|
) {
|
||||||
|
try_visit!(self.visit_id(hir_id));
|
||||||
|
|
||||||
|
self.bounded_ty_depth += 1;
|
||||||
|
try_visit!(self.visit_ty(bounded_ty));
|
||||||
|
self.bounded_ty_depth -= 1;
|
||||||
|
|
||||||
|
walk_list!(self, visit_param_bound, bounds);
|
||||||
|
walk_list!(self, visit_generic_param, bound_generic_params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
|
impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
|
||||||
|
@ -531,6 +558,7 @@ where
|
||||||
usages.push(Usage {
|
usages.push(Usage {
|
||||||
lifetime: *lifetime,
|
lifetime: *lifetime,
|
||||||
in_where_predicate: self.where_predicate_depth != 0,
|
in_where_predicate: self.where_predicate_depth != 0,
|
||||||
|
in_bounded_ty: self.bounded_ty_depth != 0,
|
||||||
in_generics_arg: self.generic_args_depth != 0,
|
in_generics_arg: self.generic_args_depth != 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -538,7 +566,17 @@ where
|
||||||
|
|
||||||
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
||||||
self.where_predicate_depth += 1;
|
self.where_predicate_depth += 1;
|
||||||
walk_where_predicate(self, predicate);
|
if let &WherePredicateKind::BoundPredicate(WhereBoundPredicate {
|
||||||
|
bounded_ty,
|
||||||
|
bounds,
|
||||||
|
bound_generic_params,
|
||||||
|
origin: _,
|
||||||
|
}) = predicate.kind
|
||||||
|
{
|
||||||
|
self.visit_where_bound_predicate(predicate.hir_id, bounded_ty, bounds, bound_generic_params);
|
||||||
|
} else {
|
||||||
|
walk_where_predicate(self, predicate);
|
||||||
|
}
|
||||||
self.where_predicate_depth -= 1;
|
self.where_predicate_depth -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,7 +600,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
|
||||||
for (def_id, usages) in checker.map {
|
for (def_id, usages) in checker.map {
|
||||||
if usages
|
if usages
|
||||||
.iter()
|
.iter()
|
||||||
.all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
|
.all(|usage| usage.in_where_predicate && !usage.in_bounded_ty && !usage.in_generics_arg)
|
||||||
{
|
{
|
||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
|
@ -589,7 +627,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
|
||||||
for (&def_id, usages) in &checker.map {
|
for (&def_id, usages) in &checker.map {
|
||||||
if usages
|
if usages
|
||||||
.iter()
|
.iter()
|
||||||
.all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
|
.all(|usage| usage.in_where_predicate && !usage.in_bounded_ty && !usage.in_generics_arg)
|
||||||
{
|
{
|
||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
|
@ -605,8 +643,8 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
|
||||||
|
|
||||||
// An `impl` lifetime is elidable if it satisfies the following conditions:
|
// An `impl` lifetime is elidable if it satisfies the following conditions:
|
||||||
// - It is used exactly once.
|
// - It is used exactly once.
|
||||||
// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are
|
// - That single use is not in a bounded type or `GenericArgs` in a `WherePredicate`. (Note that
|
||||||
// different from `GenericParam`s.)
|
// `GenericArgs` are different from `GenericParam`s.)
|
||||||
fn report_elidable_impl_lifetimes<'tcx>(
|
fn report_elidable_impl_lifetimes<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
impl_: &'tcx Impl<'_>,
|
impl_: &'tcx Impl<'_>,
|
||||||
|
@ -623,6 +661,7 @@ fn report_elidable_impl_lifetimes<'tcx>(
|
||||||
}
|
}
|
||||||
| Usage {
|
| Usage {
|
||||||
lifetime,
|
lifetime,
|
||||||
|
in_bounded_ty: false,
|
||||||
in_generics_arg: false,
|
in_generics_arg: false,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::EXPLICIT_ITER_LOOP;
|
use super::EXPLICIT_ITER_LOOP;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::ty::{
|
use clippy_utils::ty::{
|
||||||
implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
|
implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
|
||||||
|
@ -29,7 +29,7 @@ pub(super) fn check(
|
||||||
if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) {
|
if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if count.try_to_target_usize(cx.tcx).map_or(true, |x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) {
|
} else if count.try_to_target_usize(cx.tcx).is_none_or(|x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,8 @@ fn is_ref_iterable<'tcx>(
|
||||||
// Attempt to borrow
|
// Attempt to borrow
|
||||||
let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl);
|
let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl);
|
||||||
if implements_trait(cx, self_ty, trait_id, &[])
|
if implements_trait(cx, self_ty, trait_id, &[])
|
||||||
&& let Some(ty) = make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
|
&& let Some(ty) =
|
||||||
|
make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
|
||||||
&& ty == res_ty
|
&& ty == res_ty
|
||||||
{
|
{
|
||||||
return Some((AdjustKind::borrow(mutbl), self_ty));
|
return Some((AdjustKind::borrow(mutbl), self_ty));
|
||||||
|
|
|
@ -23,8 +23,8 @@ mod while_let_loop;
|
||||||
mod while_let_on_iterator;
|
mod while_let_on_iterator;
|
||||||
|
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::Msrv;
|
|
||||||
use clippy_utils::higher;
|
use clippy_utils::higher;
|
||||||
|
use clippy_utils::msrvs::Msrv;
|
||||||
use rustc_ast::Label;
|
use rustc_ast::Label;
|
||||||
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
|
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
use clippy_utils::get_parent_expr;
|
use clippy_utils::get_parent_expr;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_data_structures::packed::Pu128;
|
use rustc_data_structures::packed::Pu128;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||||
use clippy_utils::higher::If;
|
use clippy_utils::higher::If;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::ty::implements_trait;
|
use clippy_utils::ty::implements_trait;
|
||||||
use clippy_utils::visitors::is_const_evaluatable;
|
use clippy_utils::visitors::is_const_evaluatable;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::SpanlessEq;
|
use clippy_utils::SpanlessEq;
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use rustc_ast::{BinOpKind, LitKind};
|
use rustc_ast::{BinOpKind, LitKind};
|
||||||
|
@ -35,7 +35,7 @@ declare_clippy_lint! {
|
||||||
/// let y: i32 = 4;
|
/// let y: i32 = 4;
|
||||||
/// let div = x.div_ceil(y);
|
/// let div = x.div_ceil(y);
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.81.0"]
|
#[clippy::version = "1.83.0"]
|
||||||
pub MANUAL_DIV_CEIL,
|
pub MANUAL_DIV_CEIL,
|
||||||
complexity,
|
complexity,
|
||||||
"manually reimplementing `div_ceil`"
|
"manually reimplementing `div_ceil`"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::msrvs::Msrv;
|
use clippy_config::Conf;
|
||||||
use clippy_config::{Conf, msrvs};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::{is_from_proc_macro, path_to_local};
|
use clippy_utils::{is_from_proc_macro, path_to_local};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::visitors::{is_local_used, local_used_once};
|
use clippy_utils::visitors::{is_local_used, local_used_once};
|
||||||
use clippy_utils::{is_trait_method, path_to_local_id};
|
use clippy_utils::{is_trait_method, path_to_local_id};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::macros::matching_root_macro_call;
|
use clippy_utils::macros::matching_root_macro_call;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
|
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
|
||||||
use rustc_ast::LitKind::{Byte, Char};
|
use rustc_ast::LitKind::{Byte, Char};
|
||||||
|
|
|
@ -27,7 +27,7 @@ declare_clippy_lint! {
|
||||||
/// let a: u32 = 4;
|
/// let a: u32 = 4;
|
||||||
/// let result = a.is_power_of_two();
|
/// let result = a.is_power_of_two();
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.82.0"]
|
#[clippy::version = "1.83.0"]
|
||||||
pub MANUAL_IS_POWER_OF_TWO,
|
pub MANUAL_IS_POWER_OF_TWO,
|
||||||
pedantic,
|
pedantic,
|
||||||
"manually reimplementing `is_power_of_two`"
|
"manually reimplementing `is_power_of_two`"
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::question_mark::{QUESTION_MARK, QuestionMark};
|
use crate::question_mark::{QUESTION_MARK, QuestionMark};
|
||||||
use clippy_config::msrvs;
|
|
||||||
use clippy_config::types::MatchLintBehaviour;
|
use clippy_config::types::MatchLintBehaviour;
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::higher::IfLetOrMatch;
|
use clippy_utils::higher::IfLetOrMatch;
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use clippy_utils::{is_lint_allowed, is_never_expr, pat_and_expr_can_be_question_mark, peel_blocks};
|
use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
|
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::{is_trait_method, peel_hir_expr_refs};
|
use clippy_utils::{is_trait_method, peel_hir_expr_refs};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||||
use clippy_utils::is_doc_hidden;
|
use clippy_utils::is_doc_hidden;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_indent;
|
use clippy_utils::source::snippet_indent;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_ast::attr;
|
use rustc_ast::attr;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use clippy_utils::{is_in_const_context, path_to_local};
|
use clippy_utils::{is_in_const_context, path_to_local};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::SpanlessEq;
|
use clippy_utils::SpanlessEq;
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
|
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::usage::mutated_variables;
|
use clippy_utils::usage::mutated_variables;
|
||||||
use clippy_utils::{eq_expr_value, higher};
|
use clippy_utils::{eq_expr_value, higher};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::Msrv;
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::higher::IfLetOrMatch;
|
use clippy_utils::higher::IfLetOrMatch;
|
||||||
|
use clippy_utils::msrvs::Msrv;
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::visitors::is_local_used;
|
use clippy_utils::visitors::is_local_used;
|
||||||
use clippy_utils::{
|
use clippy_utils::{
|
||||||
|
@ -72,14 +72,13 @@ fn check_arm<'tcx>(
|
||||||
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
|
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
|
||||||
}
|
}
|
||||||
// the binding must not be used in the if guard
|
// the binding must not be used in the if guard
|
||||||
&& outer_guard.map_or(
|
&& outer_guard.is_none_or(
|
||||||
true,
|
|
||||||
|e| !is_local_used(cx, e, binding_id)
|
|e| !is_local_used(cx, e, binding_id)
|
||||||
)
|
)
|
||||||
// ...or anywhere in the inner expression
|
// ...or anywhere in the inner expression
|
||||||
&& match inner {
|
&& match inner {
|
||||||
IfLetOrMatch::IfLet(_, _, body, els, _) => {
|
IfLetOrMatch::IfLet(_, _, body, els, _) => {
|
||||||
!is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
|
!is_local_used(cx, body, binding_id) && els.is_none_or(|e| !is_local_used(cx, e, binding_id))
|
||||||
},
|
},
|
||||||
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
|
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ mod try_err;
|
||||||
mod wild_in_or_pats;
|
mod wild_in_or_pats;
|
||||||
|
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::walk_span_to_context;
|
use clippy_utils::source::walk_span_to_context;
|
||||||
use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg};
|
use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
|
use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::Msrv;
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::macros::matching_root_macro_call;
|
use clippy_utils::macros::matching_root_macro_call;
|
||||||
|
use clippy_utils::msrvs::Msrv;
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
|
use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
|
||||||
use clippy_utils::{is_in_const_context, path_to_local};
|
use clippy_utils::{is_in_const_context, path_to_local};
|
||||||
|
@ -243,11 +243,6 @@ fn emit_redundant_guards<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the given `Expr` can also be represented as a `Pat`.
|
/// Checks if the given `Expr` can also be represented as a `Pat`.
|
||||||
///
|
|
||||||
/// All literals generally also work as patterns, however float literals are special.
|
|
||||||
/// They are currently (as of 2023/08/08) still allowed in patterns, but that will become
|
|
||||||
/// an error in the future, and rustc already actively warns against this (see rust#41620),
|
|
||||||
/// so we don't consider those as usable within patterns for linting purposes.
|
|
||||||
fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
for_each_expr_without_closures(expr, |expr| {
|
for_each_expr_without_closures(expr, |expr| {
|
||||||
if match expr.kind {
|
if match expr.kind {
|
||||||
|
@ -267,7 +262,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
| ExprKind::Tup(..)
|
| ExprKind::Tup(..)
|
||||||
| ExprKind::Struct(..)
|
| ExprKind::Struct(..)
|
||||||
| ExprKind::Unary(UnOp::Neg, _) => true,
|
| ExprKind::Unary(UnOp::Neg, _) => true,
|
||||||
ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true,
|
ExprKind::Lit(lit) if !matches!(lit.node, LitKind::CStr(..)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
} {
|
} {
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::ty::is_non_aggregate_primitive_type;
|
use clippy_utils::ty::is_non_aggregate_primitive_type;
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub(super) fn check(
|
||||||
.type_dependent_def_id(expr.hir_id)
|
.type_dependent_def_id(expr.hir_id)
|
||||||
.and_then(|id| cx.tcx.trait_of_item(id))
|
.and_then(|id| cx.tcx.trait_of_item(id))
|
||||||
.zip(cx.tcx.lang_items().clone_trait())
|
.zip(cx.tcx.lang_items().clone_trait())
|
||||||
.map_or(true, |(x, y)| x != y)
|
.is_none_or(|(x, y)| x != y)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
use clippy_utils::is_trait_method;
|
use clippy_utils::is_trait_method;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
|
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::Expr;
|
use rustc_hir::Expr;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::ERR_EXPECT;
|
use super::ERR_EXPECT;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
|
use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||||
use clippy_utils::is_trait_method;
|
use clippy_utils::is_trait_method;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::IS_DIGIT_ASCII_RADIX;
|
use super::IS_DIGIT_ASCII_RADIX;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::Expr;
|
use rustc_hir::Expr;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::ITER_KV_MAP;
|
use super::ITER_KV_MAP;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::pat_is_wild;
|
use clippy_utils::pat_is_wild;
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
use clippy_utils::get_parent_expr;
|
use clippy_utils::get_parent_expr;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use rustc_ast::{LitKind, StrStyle};
|
use rustc_ast::{LitKind, StrStyle};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::{IntoSpan, SpanRangeExt};
|
use clippy_utils::source::{IntoSpan, SpanRangeExt};
|
||||||
use clippy_utils::ty::get_field_by_name;
|
use clippy_utils::ty::get_field_by_name;
|
||||||
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
|
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{Msrv, OPTION_RESULT_IS_VARIANT_AND};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. msrv doesn't meet `OPTION_RESULT_IS_VARIANT_AND`
|
// 4. msrv doesn't meet `OPTION_RESULT_IS_VARIANT_AND`
|
||||||
if !msrv.meets(OPTION_RESULT_IS_VARIANT_AND) {
|
if !msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::ty::implements_trait;
|
use clippy_utils::ty::implements_trait;
|
||||||
use clippy_utils::{is_from_proc_macro, is_trait_method};
|
use clippy_utils::{is_from_proc_macro, is_trait_method};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function};
|
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function};
|
||||||
use clippy_utils::{is_diag_trait_item, peel_blocks};
|
use clippy_utils::{is_diag_trait_item, peel_blocks};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use clippy_utils::usage::mutated_variables;
|
use clippy_utils::usage::mutated_variables;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES;
|
use crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use clippy_utils::{eager_or_lazy, higher, usage};
|
use clippy_utils::{eager_or_lazy, higher, usage};
|
||||||
|
|
|
@ -137,10 +137,10 @@ mod wrong_self_convention;
|
||||||
mod zst_offset;
|
mod zst_offset;
|
||||||
|
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||||
use clippy_utils::macros::FormatArgsStorage;
|
use clippy_utils::macros::FormatArgsStorage;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
|
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
|
||||||
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
|
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
|
||||||
pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
|
pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
|
||||||
|
@ -4107,24 +4107,32 @@ declare_clippy_lint! {
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome,
|
/// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome,
|
||||||
/// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`.
|
/// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`.
|
||||||
|
/// Also, calls such as `opt.map_or(true, |val| val == 5)` can be reduced to
|
||||||
|
/// `opt.is_none_or(|val| val == 5)`.
|
||||||
/// This lint offers readability and conciseness improvements.
|
/// This lint offers readability and conciseness improvements.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// pub fn a(x: Option<i32>) -> bool {
|
/// pub fn a(x: Option<i32>) -> (bool, bool) {
|
||||||
/// x.map_or(false, |n| n == 5)
|
/// (
|
||||||
|
/// x.map_or(false, |n| n == 5),
|
||||||
|
/// x.map_or(true, |n| n > 5),
|
||||||
|
/// )
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// pub fn a(x: Option<i32>) -> bool {
|
/// pub fn a(x: Option<i32>) -> (bool, bool) {
|
||||||
/// x == Some(5)
|
/// (
|
||||||
|
/// x == Some(5),
|
||||||
|
/// x.is_none_or(|n| n > 5),
|
||||||
|
/// )
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.75.0"]
|
#[clippy::version = "1.84.0"]
|
||||||
pub UNNECESSARY_MAP_OR,
|
pub UNNECESSARY_MAP_OR,
|
||||||
style,
|
style,
|
||||||
"reduce unnecessary pattern matching for constructs that implement `PartialEq`"
|
"reduce unnecessary calls to `.map_or(bool, …)`"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
|
@ -4531,7 +4539,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||||
&& method_config.output_type.matches(&sig.decl.output)
|
&& method_config.output_type.matches(&sig.decl.output)
|
||||||
// in case there is no first arg, since we already have checked the number of arguments
|
// in case there is no first arg, since we already have checked the number of arguments
|
||||||
// it's should be always true
|
// it's should be always true
|
||||||
&& first_arg_ty_opt.map_or(true, |first_arg_ty| method_config
|
&& first_arg_ty_opt.is_none_or(|first_arg_ty| method_config
|
||||||
.self_kind.matches(cx, self_ty, first_arg_ty)
|
.self_kind.matches(cx, self_ty, first_arg_ty)
|
||||||
)
|
)
|
||||||
&& fn_header_equals(method_config.fn_header, sig.header)
|
&& fn_header_equals(method_config.fn_header, sig.header)
|
||||||
|
|
|
@ -203,7 +203,8 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
|
||||||
fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
|
fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
|
||||||
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
||||||
&& let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
|
&& let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
|
||||||
&& let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.typing_env(), iter_trait, sym::Item, [iter_ty])
|
&& let Some(iter_item_ty) =
|
||||||
|
make_normalized_projection(cx.tcx, cx.typing_env(), iter_trait, sym::Item, [iter_ty])
|
||||||
&& let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty])
|
&& let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty])
|
||||||
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
|
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
|
||||||
cx.typing_env(),
|
cx.typing_env(),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use clippy_config::msrvs::{self, Msrv};
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use clippy_utils::{path_to_local_id, peel_blocks};
|
use clippy_utils::{path_to_local_id, peel_blocks};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue