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]]
name = "clippy"
version = "0.1.84"
version = "0.1.85"
dependencies = [
"anstream",
"cargo_metadata",
@ -567,8 +567,9 @@ dependencies = [
[[package]]
name = "clippy_config"
version = "0.1.84"
version = "0.1.85"
dependencies = [
"clippy_utils",
"itertools",
"serde",
"toml 0.7.8",
@ -580,6 +581,7 @@ name = "clippy_dev"
version = "0.0.1"
dependencies = [
"aho-corasick",
"chrono",
"clap",
"indoc",
"itertools",
@ -590,7 +592,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
version = "0.1.84"
version = "0.1.85"
dependencies = [
"arrayvec",
"cargo_metadata",
@ -613,12 +615,12 @@ dependencies = [
[[package]]
name = "clippy_utils"
version = "0.1.84"
version = "0.1.85"
dependencies = [
"arrayvec",
"clippy_config",
"itertools",
"rustc_apfloat",
"serde",
]
[[package]]

View File

@ -6,11 +6,56 @@ document.
## 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
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)
@ -5441,6 +5486,7 @@ Released 2018-09-13
[`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
[`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_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

View File

@ -1,6 +1,8 @@
[package]
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"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@ -27,7 +29,7 @@ rustc_tools_util = "0.4.0"
tempfile = { version = "3.3", optional = true }
termize = "0.1"
color-print = "0.3.4"
anstream = "0.6.0"
anstream = "0.6.18"
[dev-dependencies]
cargo_metadata = "0.18.1"

View File

@ -7,6 +7,7 @@
- [Configuration](configuration.md)
- [Lint Configuration](lint_configuration.md)
- [Clippy's Lints](lints.md)
- [Attributes for Crate Authors](attribs.md)
- [Continuous Integration](continuous_integration/README.md)
- [GitHub Actions](continuous_integration/github_actions.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
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.
```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).

View File

@ -895,7 +895,7 @@ The order of associated items in traits.
## `trivial-copy-size-limit`
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`

View File

@ -1,11 +1,15 @@
[package]
name = "clippy_config"
version = "0.1.84"
# begin autogenerated version
version = "0.1.85"
# end autogenerated version
edition = "2021"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clippy_utils = { path = "../clippy_utils" }
itertools = "0.12"
serde = { version = "1.0", features = ["derive"] }
toml = "0.7.3"

View File

@ -1,10 +1,10 @@
use crate::ClippyConfiguration;
use crate::msrvs::Msrv;
use crate::types::{
DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering,
SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
};
use clippy_utils::msrvs::Msrv;
use rustc_errors::Applicability;
use rustc_session::Session;
use rustc_span::edit_distance::edit_distance;
@ -181,7 +181,7 @@ macro_rules! define_Conf {
)*) => {
/// Clippy lint configuration
pub struct Conf {
$($(#[doc = $doc])+ pub $name: $ty,)*
$($(#[cfg_attr(doc, doc = $doc)])+ pub $name: $ty,)*
}
mod defaults {
@ -678,7 +678,7 @@ define_Conf! {
#[lints(arbitrary_source_item_ordering)]
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
/// reference. By default there is no limit
/// reference.
#[default_text = "target_pointer_width * 2"]
#[lints(trivially_copy_pass_by_ref)]
trivial_copy_size_limit: Option<u64> = None,

View File

@ -13,18 +13,14 @@
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_hir;
extern crate rustc_middle;
extern crate rustc_session;
extern crate rustc_span;
extern crate smallvec;
mod conf;
mod metadata;
pub mod msrvs;
pub mod types;
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::{Deserialize, Serialize, ser};
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)]
pub enum MatchLintBehaviour {
AllTypes,

View File

@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
aho-corasick = "1.0"
chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
clap = { version = "4.4", features = ["derive"] }
indoc = "1.0"
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;
/// # Panics

View File

@ -1,4 +1,4 @@
use crate::clippy_project_root;
use crate::utils::clippy_project_root;
use itertools::Itertools;
use rustc_lexer::{TokenKind, tokenize};
use shell_escape::escape;

View File

@ -14,69 +14,13 @@
extern crate rustc_driver;
extern crate rustc_lexer;
use std::io;
use std::path::PathBuf;
use std::process::{self, ExitStatus};
pub mod dogfood;
pub mod fmt;
pub mod lint;
pub mod new_lint;
pub mod release;
pub mod serve;
pub mod setup;
pub mod sync;
pub mod update_lints;
#[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);
},
}
}
pub mod utils;

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::{env, fs};

View File

@ -3,7 +3,7 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
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;
fn main() {
@ -23,9 +23,9 @@ fn main() {
if print_only {
update_lints::print_lints();
} else if check {
update_lints::update(update_lints::UpdateMode::Check);
update_lints::update(utils::UpdateMode::Check);
} else {
update_lints::update(update_lints::UpdateMode::Change);
update_lints::update(utils::UpdateMode::Change);
}
},
DevCommand::NewLint {
@ -35,7 +35,7 @@ fn main() {
r#type,
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}"),
},
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
@ -75,6 +75,12 @@ fn main() {
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::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
reason: String,
},
/// Sync between the rust repo and the Clippy repo
Sync(SyncCommand),
/// Manage Clippy releases
Release(ReleaseCommand),
}
#[derive(Args)]
@ -291,3 +301,29 @@ enum RemoveSubcommand {
/// Remove the tasks added with 'cargo dev setup vscode-tasks'
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 std::fmt;
use std::fmt::Write as _;
@ -186,23 +186,8 @@ fn to_camel_case(name: &str) -> String {
}
pub(crate) fn get_stabilization_version() -> String {
fn parse_manifest(contents: &str) -> Option<String> {
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(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`")
let (minor, patch) = clippy_version();
format!("{minor}.{patch}.0")
}
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 {
formatdoc!(
r"
use clippy_config::msrvs::{{self, Msrv}};
use clippy_utils::msrvs::{{self, Msrv}};
use clippy_config::Conf;
{pass_import}
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!(
lint_file_contents,
r#"
use clippy_config::msrvs::{{self, Msrv}};
use clippy_utils::msrvs::{{self, Msrv}};
use rustc_lint::{{{context_import}, LintContext}};
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 itertools::Itertools;
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";
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum UpdateMode {
Check,
Change,
}
/// Runs the `update_lints` command.
///
/// 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.
#[derive(Clone, PartialEq, Eq, Debug)]
struct Lint {
@ -851,61 +837,6 @@ fn remove_line_splices(s: &str) -> String {
});
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 {
match OpenOptions::new().create_new(true).write(true).open(new_name) {
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]
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"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{trim_span, walk_span_to_context};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
use rustc_errors::Applicability;

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@ -91,7 +91,7 @@ impl ApproxConstant {
let s = s.as_str();
if s.parse::<f64>().is_ok() {
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(
cx,
APPROX_CONSTANT,

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
use clippy_utils::msrvs::{self, Msrv};
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 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.
// That is overly conservative - the lint should fire even if there was no initializer,
// 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())
// Derived forms don't implement `clone_from`/`clone_into`.
// See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
&& !cx.tcx.is_builtin_derived(resolved_impl)
// 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)
})
&& 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 clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::AttrStyle;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;

View File

@ -13,7 +13,7 @@ mod useless_attribute;
mod utils;
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_hir::{ImplItem, Item, TraitItem};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};

View File

@ -1,6 +1,7 @@
use clippy_config::Conf;
use clippy_config::types::create_disallowed_map;
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::def_id::{DefId, DefIdMap};
use rustc_lint::{LateContext, LateLintPass};

View File

@ -1,7 +1,7 @@
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::eq_expr_value;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use rustc_ast::ast::LitKind;

View File

@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
&& !addrof_target.span.from_expansion()
&& let ref_ty = cx.typeck_results().expr_ty(deref_target)
&& let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
&& get_parent_expr(cx, e).map_or(true, |parent| {
&& get_parent_expr(cx, e).is_none_or(|parent| {
match parent.kind {
// `*&*foo` should lint `deref_addrof` instead.
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 {
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 {

View File

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

View File

@ -1,6 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_in_const_context;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::sugg::Sugg;
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 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)) {
(_, false) if from_nbits > to_nbits => "",
(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::msrvs::{self, Msrv};
use clippy_utils::source;
use rustc_ast::Mutability;
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::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;

View File

@ -24,8 +24,8 @@ mod utils;
mod zero_ptr;
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::is_hir_ty_cfg_dependant;
use clippy_utils::msrvs::{self, Msrv};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;

View File

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

View File

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

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
use rustc_errors::Applicability;

View File

@ -212,7 +212,7 @@ fn lint_if_same_then_else(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[&
.array_windows::<2>()
.enumerate()
.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(
cx,
IF_SAME_THEN_ELSE,
@ -470,7 +470,7 @@ fn scan_block_for_eq<'tcx>(
b.stmts
// the bounds check will catch the underflow
.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);

View File

@ -135,6 +135,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::disallowed_names::DISALLOWED_NAMES_INFO,
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
crate::disallowed_types::DISALLOWED_TYPES_INFO,
crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO,
crate::doc::DOC_LAZY_CONTINUATION_INFO,
crate::doc::DOC_LINK_WITH_QUOTES_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_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{
self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
PatKind, Path, QPath, TyKind, UnOp,
};
use rustc_hir::def_id::DefId;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
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()
// 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(_)))
{
self.state = Some((State::Borrow { mutability }, StateData {
@ -1070,8 +1070,7 @@ fn report<'tcx>(
let mut app = Applicability::MachineApplicable;
let (snip, snip_is_macro) =
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
let sugg =
if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
let sugg = if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
format!("{prefix}({snip})")
} else {
format!("{prefix}{snip}")

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::indent_of;
use clippy_utils::{is_default_equivalent, peel_blocks};
use rustc_errors::Applicability;
@ -132,17 +132,15 @@ fn check_struct<'tcx>(
if should_emit {
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| {
diag.span_suggestion_hidden(
item.span,
"remove the manual implementation...",
String::new(),
Applicability::MachineApplicable,
);
diag.span_suggestion(
struct_span.shrink_to_lo(),
"...and instead derive it",
"#[derive(Default)]\n".to_string(),
diag.multipart_suggestion(
"replace the manual implementation with a derive attribute",
suggestions,
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 variant_span = cx.tcx.def_span(variant_def.def_id);
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(
item.span,
"remove the manual implementation...",
String::new(),
Applicability::MachineApplicable,
);
diag.span_suggestion(
let suggestions = vec![
(item.span, String::new()), // Remove the manual implementation
(
enum_span.shrink_to_lo(),
"...and instead derive it...",
format!("#[derive(Default)]\n{indent}", indent = " ".repeat(indent_enum),),
Applicability::MachineApplicable,
);
diag.span_suggestion(
format!("#[derive(Default)]\n{}", " ".repeat(indent_enum)),
), // Add the derive attribute
(
variant_span.shrink_to_lo(),
"...and mark the default variant",
format!("#[default]\n{indent}", indent = " ".repeat(indent_variant),),
format!("#[default]\n{}", " ".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,
);
});

View File

@ -505,8 +505,7 @@ fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId
}
}
let param_env = ParamEnv::new(
tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
let param_env = ParamEnv::new(tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
ClauseKind::Trait(TraitPredicate {
trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
@ -514,8 +513,7 @@ fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId
})
.upcast(tcx)
}),
)),
);
)));
ty::TypingEnv {
typing_mode: ty::TypingMode::non_body_analysis(),
param_env,

View File

@ -1,5 +1,5 @@
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::macros::macro_backtrace;
use rustc_data_structures::fx::FxHashSet;

View File

@ -1,5 +1,5 @@
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 rustc_hir::def::{CtorKind, DefKind, Res};
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 too_long_first_doc_paragraph;
@ -33,6 +35,7 @@ use std::ops::Range;
use url::Url;
mod empty_line_after;
mod include_in_doc_without_cfg;
mod link_with_quotes;
mod markdown;
mod missing_headers;
@ -532,6 +535,35 @@ declare_clippy_lint! {
"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 {
valid_idents: FxHashSet<String>,
check_private_items: bool,
@ -561,6 +593,7 @@ impl_lint_pass!(Documentation => [
EMPTY_LINE_AFTER_OUTER_ATTR,
EMPTY_LINE_AFTER_DOC_COMMENTS,
TOO_LONG_FIRST_DOC_PARAGRAPH,
DOC_INCLUDE_WITHOUT_CFG,
]);
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()))
}
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) {
return None;
}
@ -917,6 +951,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
}
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 == "Implementation safety";
headers.safety |= in_heading && trimmed_text == "Implementation Safety";
headers.errors |= in_heading && trimmed_text == "Errors";

View File

@ -276,7 +276,7 @@ fn check_inputs(
&& typeck
.expr_adjustments(arg)
.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_decl.inputs.len() as u64 > self.max_fn_params_bools
&& get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id))
.map_or(true, |impl_item| impl_item.of_trait.is_none())
.is_none_or(|impl_item| impl_item.of_trait.is_none())
{
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::{
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_middle::hir::nested_filter;

View File

@ -1,6 +1,5 @@
use arrayvec::ArrayVec;
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::is_diag_trait_item;
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,
root_macro_call_first_node,
};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use itertools::Itertools;

View File

@ -1,9 +1,9 @@
use std::ops::ControlFlow;
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::path_def_id;
use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability;
@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|diag| {
// If the target type is likely foreign mention the orphan rules as it's a common source of
// confusion
if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
if path_def_id(cx, target_ty.peel_refs()).is_none_or(|id| !id.is_local()) {
diag.help(
"`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"

View File

@ -1,3 +1,5 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::return_ty;
use rustc_hir::intravisit::FnKind;
@ -5,7 +7,9 @@ use rustc_hir::{Body, FnDecl};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
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_span::def_id::LocalDefId;
use rustc_span::{Span, sym};
@ -15,9 +19,16 @@ use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
declare_clippy_lint! {
/// ### What it does
/// This lint requires Future implementations returned from
/// functions and methods to implement the `Send` marker trait. It is mostly
/// used by library authors (public and internal) that target an audience where
/// multithreaded executors are likely to be used for running these Futures.
/// functions and methods to implement the `Send` marker trait,
/// ignoring type parameters.
///
/// 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?
/// A Future implementation captures some state that it
@ -64,22 +75,46 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
return;
}
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 is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
p.as_trait_clause().is_some_and(|trait_pred| {
Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait()
})
p.as_trait_clause()
.is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
});
if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let cause = traits::ObligationCause::misc(span, fn_def_id);
ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
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(
cx,
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_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::edition::Edition::Edition2024;
use rustc_span::sym;
declare_clippy_lint! {
@ -14,6 +15,12 @@ declare_clippy_lint! {
/// Checks for `Mutex::lock` calls in `if let` expression
/// 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?
/// The Mutex lock remains held for the whole
/// `if let ... else` block and deadlocks.
@ -45,6 +52,10 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if cx.tcx.sess.edition() >= Edition2024 {
return;
}
if let Some(higher::IfLet {
let_expr,
if_then,
@ -86,7 +97,7 @@ fn mutex_lock_call<'tcx>(
&& path.ident.as_str() == "lock"
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
&& 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)
} else {

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::{

View File

@ -1,6 +1,6 @@
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::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::{
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::msrvs::Msrv;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_in_test;
use clippy_utils::msrvs::Msrv;
use rustc_attr::{StabilityLevel, StableSince};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{Expr, ExprKind, HirId};

View File

@ -1,8 +1,8 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_copy;
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty;

View File

@ -3,8 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty;
use rustc_middle::ty::layout::LayoutOf;
use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Pos, Span};

View File

@ -1,6 +1,6 @@
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::msrvs::{self, Msrv};
use clippy_utils::{get_parent_expr, is_from_proc_macro};
use hir::def_id::DefId;
use rustc_errors::Applicability;
@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
// Integer modules are "TBD" deprecated, and the contents are too,
// so lint on the `use` statement directly.
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)
&& let Some(def_id) = path.res[0].opt_def_id()
{
@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
return;
};
if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
&& !in_external_macro(cx.sess(), expr.span)
&& !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::trait_ref_of_method;
use itertools::Itertools;
use rustc_ast::visit::{try_visit, walk_list};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::Applicability;
use rustc_hir::FnRetTy::Return;
@ -11,8 +12,9 @@ use rustc_hir::intravisit::{
};
use rustc_hir::{
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, WherePredicateKind, lang_items,
HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
WherePredicateKind, lang_items,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
@ -483,6 +485,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
struct Usage {
lifetime: Lifetime,
in_where_predicate: bool,
in_bounded_ty: bool,
in_generics_arg: bool,
}
@ -490,11 +493,15 @@ struct LifetimeChecker<'cx, 'tcx, F> {
cx: &'cx LateContext<'tcx>,
map: FxIndexMap<LocalDefId, Vec<Usage>>,
where_predicate_depth: usize,
bounded_ty_depth: usize,
generic_args_depth: usize,
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> {
let map = generics
.params
@ -510,10 +517,30 @@ impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
cx,
map,
where_predicate_depth: 0,
bounded_ty_depth: 0,
generic_args_depth: 0,
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>
@ -531,6 +558,7 @@ where
usages.push(Usage {
lifetime: *lifetime,
in_where_predicate: self.where_predicate_depth != 0,
in_bounded_ty: self.bounded_ty_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>) {
self.where_predicate_depth += 1;
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;
}
@ -562,7 +600,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
for (def_id, usages) in checker.map {
if usages
.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(
cx,
@ -589,7 +627,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
for (&def_id, usages) in &checker.map {
if usages
.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(
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:
// - It is used exactly once.
// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are
// different from `GenericParam`s.)
// - That single use is not in a bounded type or `GenericArgs` in a `WherePredicate`. (Note that
// `GenericArgs` are different from `GenericParam`s.)
fn report_elidable_impl_lifetimes<'tcx>(
cx: &LateContext<'tcx>,
impl_: &'tcx Impl<'_>,
@ -623,6 +661,7 @@ fn report_elidable_impl_lifetimes<'tcx>(
}
| Usage {
lifetime,
in_bounded_ty: false,
in_generics_arg: false,
..
},

View File

@ -1,6 +1,6 @@
use super::EXPLICIT_ITER_LOOP;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{
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) {
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;
}
}
@ -181,7 +181,8 @@ fn is_ref_iterable<'tcx>(
// Attempt to borrow
let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl);
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
{
return Some((AdjustKind::borrow(mutbl), self_ty));

View File

@ -23,8 +23,8 @@ mod while_let_loop;
mod while_let_on_iterator;
use clippy_config::Conf;
use clippy_config::msrvs::Msrv;
use clippy_utils::higher;
use clippy_utils::msrvs::Msrv;
use rustc_ast::Label;
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
use rustc_lint::{LateContext, LateLintPass};

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_expr;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use rustc_ast::ast::LitKind;
use rustc_data_structures::packed::Pu128;

View File

@ -1,8 +1,8 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::higher::If;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
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::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_ast::{BinOpKind, LitKind};
@ -35,7 +35,7 @@ declare_clippy_lint! {
/// let y: i32 = 4;
/// let div = x.div_ceil(y);
/// ```
#[clippy::version = "1.81.0"]
#[clippy::version = "1.83.0"]
pub MANUAL_DIV_CEIL,
complexity,
"manually reimplementing `div_ceil`"

View File

@ -1,7 +1,7 @@
use clippy_config::msrvs::Msrv;
use clippy_config::{Conf, msrvs};
use clippy_config::Conf;
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{is_from_proc_macro, path_to_local};
use rustc_errors::Applicability;

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::visitors::{is_local_used, local_used_once};
use clippy_utils::{is_trait_method, path_to_local_id};

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
use rustc_ast::LitKind::{Byte, Char};

View File

@ -27,7 +27,7 @@ declare_clippy_lint! {
/// let a: u32 = 4;
/// let result = a.is_power_of_two();
/// ```
#[clippy::version = "1.82.0"]
#[clippy::version = "1.83.0"]
pub MANUAL_IS_POWER_OF_TWO,
pedantic,
"manually reimplementing `is_power_of_two`"

View File

@ -1,11 +1,10 @@
use crate::question_mark::{QUESTION_MARK, QuestionMark};
use clippy_config::msrvs;
use clippy_config::types::MatchLintBehaviour;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::source::snippet_with_context;
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_errors::Applicability;
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};

View File

@ -1,6 +1,6 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
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 rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};

View File

@ -1,7 +1,7 @@
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::is_doc_hidden;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_indent;
use itertools::Itertools;
use rustc_ast::attr;

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::{is_in_const_context, path_to_local};
use rustc_errors::Applicability;

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::SpanlessEq;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
use rustc_errors::Applicability;

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
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::higher::IfLetOrMatch;
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet;
use clippy_utils::visitors::is_local_used;
use clippy_utils::{
@ -72,14 +72,13 @@ fn check_arm<'tcx>(
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
}
// the binding must not be used in the if guard
&& outer_guard.map_or(
true,
&& outer_guard.is_none_or(
|e| !is_local_used(cx, e, binding_id)
)
// ...or anywhere in the inner expression
&& match inner {
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)),
}

View File

@ -25,7 +25,7 @@ mod try_err;
mod wild_in_or_pats;
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::{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};

View File

@ -1,6 +1,6 @@
use clippy_config::msrvs::Msrv;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet;
use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
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`.
///
/// 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 {
for_each_expr_without_closures(expr, |expr| {
if match expr.kind {
@ -267,7 +262,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
| ExprKind::Tup(..)
| ExprKind::Struct(..)
| 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,
} {
return ControlFlow::Continue(());

View File

@ -1,6 +1,6 @@
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::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
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)
.and_then(|id| cx.tcx.trait_of_item(id))
.zip(cx.tcx.lang_items().clone_trait())
.map_or(true, |(x, y)| x != y)
.is_none_or(|(x, y)| x != y)
{
return;
}

View File

@ -1,6 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
use rustc_errors::Applicability;
use rustc_hir::Expr;

View File

@ -1,6 +1,6 @@
use super::ERR_EXPECT;
use clippy_config::msrvs::{self, Msrv};
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 rustc_errors::Applicability;
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::is_trait_method;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir as hir;

View File

@ -1,7 +1,7 @@
use super::IS_DIGIT_ASCII_RADIX;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::Expr;

View File

@ -1,6 +1,6 @@
use super::ITER_KV_MAP;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::pat_is_wild;
use clippy_utils::source::snippet_with_applicability;
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::get_parent_expr;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use rustc_ast::{LitKind, StrStyle};
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::msrvs::{self, Msrv};
use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::get_field_by_name;
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::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
}
// 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;
}

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait;
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::msrvs::{self, Msrv};
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::{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::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::mutated_variables;

View File

@ -1,6 +1,6 @@
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::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::{eager_or_lazy, higher, usage};

View File

@ -137,10 +137,10 @@ mod wrong_self_convention;
mod zst_offset;
use clippy_config::Conf;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
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::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
@ -4107,24 +4107,32 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// 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`.
/// 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.
///
/// ### Example
/// ```no_run
/// pub fn a(x: Option<i32>) -> bool {
/// x.map_or(false, |n| n == 5)
/// pub fn a(x: Option<i32>) -> (bool, bool) {
/// (
/// x.map_or(false, |n| n == 5),
/// x.map_or(true, |n| n > 5),
/// )
/// }
/// ```
/// Use instead:
/// ```no_run
/// pub fn a(x: Option<i32>) -> bool {
/// x == Some(5)
/// pub fn a(x: Option<i32>) -> (bool, bool) {
/// (
/// x == Some(5),
/// x.is_none_or(|n| n > 5),
/// )
/// }
/// ```
#[clippy::version = "1.75.0"]
#[clippy::version = "1.84.0"]
pub UNNECESSARY_MAP_OR,
style,
"reduce unnecessary pattern matching for constructs that implement `PartialEq`"
"reduce unnecessary calls to `.map_or(bool, …)`"
}
declare_clippy_lint! {
@ -4531,7 +4539,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
&& method_config.output_type.matches(&sig.decl.output)
// in case there is no first arg, since we already have checked the number of arguments
// 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)
)
&& 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 {
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(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 Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
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::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
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