Auto merge of #133588 - flip1995:clippy-subtree-update, r=Manishearth

Clippy subtree update

r? `@Manishearth`
This commit is contained in:
bors 2024-11-29 19:52:08 +00:00
commit d10a6823f4
196 changed files with 1965 additions and 652 deletions

View file

@ -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]]

View file

@ -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

View file

@ -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"

View file

@ -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)

View 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);
}
}
```

View file

@ -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).

View file

@ -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`

View file

@ -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"

View file

@ -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,

View file

@ -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};

View file

@ -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,

View file

@ -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"

View file

@ -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

View file

@ -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;

View file

@ -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);
},
}
}

View file

@ -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};

View file

@ -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,
}

View file

@ -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};

View 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();
},
);
}
}

View 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();
},
);
}

View file

@ -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),

View 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)
}

View file

@ -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"

View file

@ -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;

View file

@ -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,

View file

@ -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)

View file

@ -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;

View file

@ -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};

View file

@ -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};

View file

@ -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;

View file

@ -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),

View file

@ -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 {

View file

@ -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};

View file

@ -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;

View file

@ -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 => "",

View file

@ -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};

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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);
}, },
); );

View file

@ -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,
); );
}); });

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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,
);
}
}
}

View file

@ -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";

View file

@ -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))
}) })
} }

View file

@ -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);
} }

View file

@ -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;

View file

@ -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;

View file

@ -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"

View file

@ -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),
}
}
}

View file

@ -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 {

View file

@ -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::{

View file

@ -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,

View file

@ -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};

View file

@ -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};

View file

@ -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;

View file

@ -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};

View file

@ -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)
{ {

View file

@ -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,
.. ..
}, },

View file

@ -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));

View file

@ -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};

View file

@ -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;

View file

@ -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;

View file

@ -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`"

View file

@ -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;

View file

@ -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};

View file

@ -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};

View file

@ -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`"

View file

@ -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};

View file

@ -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};

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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};

View file

@ -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)),
} }

View file

@ -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};

View file

@ -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(());

View file

@ -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;

View file

@ -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;
} }

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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};

View file

@ -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;
} }

View file

@ -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};

View file

@ -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};

View file

@ -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;

View file

@ -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};

View file

@ -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)

View file

@ -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(),

View file

@ -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