mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 11:53:44 +00:00
Auto merge of #133588 - flip1995:clippy-subtree-update, r=Manishearth
Clippy subtree update r? `@Manishearth`
This commit is contained in:
commit
d10a6823f4
12
Cargo.lock
12
Cargo.lock
@ -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]]
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
53
src/tools/clippy/book/src/attribs.md
Normal file
53
src/tools/clippy/book/src/attribs.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Attributes for Crate Authors
|
||||
|
||||
In some cases it is possible to extend Clippy coverage to 3rd party libraries.
|
||||
To do this, Clippy provides attributes that can be applied to items in the 3rd party crate.
|
||||
|
||||
## `#[clippy::format_args]`
|
||||
|
||||
_Available since Clippy v1.84_
|
||||
|
||||
This attribute can be added to a macro that supports `format!`, `println!`, or similar syntax.
|
||||
It tells Clippy that the macro is a formatting macro, and that the arguments to the macro
|
||||
should be linted as if they were arguments to `format!`. Any lint that would apply to a
|
||||
`format!` call will also apply to the macro call. The macro may have additional arguments
|
||||
before the format string, and these will be ignored.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
/// A macro that prints a message if a condition is true.
|
||||
#[macro_export]
|
||||
#[clippy::format_args]
|
||||
macro_rules! print_if {
|
||||
($condition:expr, $($args:tt)+) => {{
|
||||
if $condition {
|
||||
println!($($args)+)
|
||||
}
|
||||
}};
|
||||
}
|
||||
```
|
||||
|
||||
## `#[clippy::has_significant_drop]`
|
||||
|
||||
_Available since Clippy v1.60_
|
||||
|
||||
The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have an important side effect,
|
||||
such as unlocking a mutex, making it important for users to be able to accurately understand their lifetimes.
|
||||
When a temporary is returned in a function call in a match scrutinee, its lifetime lasts until the end of the match
|
||||
block, which may be surprising.
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
#[clippy::has_significant_drop]
|
||||
struct CounterWrapper<'a> {
|
||||
counter: &'a Counter,
|
||||
}
|
||||
|
||||
impl<'a> Drop for CounterWrapper<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.counter.i.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
```
|
@ -438,7 +438,7 @@ need to ensure that the MSRV configured for the project is >= the MSRV of the
|
||||
required Rust feature. If multiple features are required, just use the one with
|
||||
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).
|
||||
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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};
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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};
|
||||
|
27
src/tools/clippy/clippy_dev/src/release.rs
Normal file
27
src/tools/clippy/clippy_dev/src/release.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::utils::{UpdateMode, clippy_version, replace_region_in_file};
|
||||
|
||||
const CARGO_TOML_FILES: [&str; 4] = [
|
||||
"clippy_config/Cargo.toml",
|
||||
"clippy_lints/Cargo.toml",
|
||||
"clippy_utils/Cargo.toml",
|
||||
"Cargo.toml",
|
||||
];
|
||||
|
||||
pub fn bump_version() {
|
||||
let (minor, mut patch) = clippy_version();
|
||||
patch += 1;
|
||||
for file in &CARGO_TOML_FILES {
|
||||
replace_region_in_file(
|
||||
UpdateMode::Change,
|
||||
Path::new(file),
|
||||
"# begin autogenerated version\n",
|
||||
"# end autogenerated version",
|
||||
|res| {
|
||||
writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
33
src/tools/clippy/clippy_dev/src/sync.rs
Normal file
33
src/tools/clippy/clippy_dev/src/sync.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::offset::Utc;
|
||||
|
||||
use crate::utils::{UpdateMode, replace_region_in_file};
|
||||
|
||||
pub fn update_nightly() {
|
||||
// Update rust-toolchain nightly version
|
||||
let date = Utc::now().format("%Y-%m-%d").to_string();
|
||||
replace_region_in_file(
|
||||
UpdateMode::Change,
|
||||
Path::new("rust-toolchain"),
|
||||
"# begin autogenerated nightly\n",
|
||||
"# end autogenerated nightly",
|
||||
|res| {
|
||||
writeln!(res, "channel = \"nightly-{date}\"").unwrap();
|
||||
},
|
||||
);
|
||||
|
||||
// Update clippy_utils nightly version
|
||||
replace_region_in_file(
|
||||
UpdateMode::Change,
|
||||
Path::new("clippy_utils/README.md"),
|
||||
"<!-- begin autogenerated nightly -->\n",
|
||||
"<!-- end autogenerated nightly -->",
|
||||
|res| {
|
||||
writeln!(res, "```").unwrap();
|
||||
writeln!(res, "nightly-{date}").unwrap();
|
||||
writeln!(res, "```").unwrap();
|
||||
},
|
||||
);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use crate::clippy_project_root;
|
||||
use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file};
|
||||
use aho_corasick::AhoCorasickBuilder;
|
||||
use 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),
|
||||
|
142
src/tools/clippy/clippy_dev/src/utils.rs
Normal file
142
src/tools/clippy/clippy_dev/src/utils.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, ExitStatus};
|
||||
use std::{fs, io};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
||||
#[cfg(windows)]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
|
||||
|
||||
/// Returns the path to the `cargo-clippy` binary
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path of current executable could not be retrieved.
|
||||
#[must_use]
|
||||
pub fn cargo_clippy_path() -> PathBuf {
|
||||
let mut path = std::env::current_exe().expect("failed to get current executable name");
|
||||
path.set_file_name(CARGO_CLIPPY_EXE);
|
||||
path
|
||||
}
|
||||
|
||||
/// Returns the path to the Clippy project directory
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the current directory could not be retrieved, there was an error reading any of the
|
||||
/// Cargo.toml files or ancestor directory is the clippy root directory
|
||||
#[must_use]
|
||||
pub fn clippy_project_root() -> PathBuf {
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
for path in current_dir.ancestors() {
|
||||
let result = fs::read_to_string(path.join("Cargo.toml"));
|
||||
if let Err(err) = &result {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let content = result.unwrap();
|
||||
if content.contains("[package]\nname = \"clippy\"") {
|
||||
return path.to_path_buf();
|
||||
}
|
||||
}
|
||||
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
/// Panics if given command result was failed.
|
||||
pub fn exit_if_err(status: io::Result<ExitStatus>) {
|
||||
match status.expect("failed to run command").code() {
|
||||
Some(0) => {},
|
||||
Some(n) => process::exit(n),
|
||||
None => {
|
||||
eprintln!("Killed by signal");
|
||||
process::exit(1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clippy_version() -> (u32, u32) {
|
||||
fn parse_manifest(contents: &str) -> Option<(u32, u32)> {
|
||||
let version = contents
|
||||
.lines()
|
||||
.filter_map(|l| l.split_once('='))
|
||||
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
|
||||
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
|
||||
return None;
|
||||
};
|
||||
let (minor, patch) = version.split_once('.')?;
|
||||
Some((minor.parse().ok()?, patch.parse().ok()?))
|
||||
}
|
||||
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
|
||||
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UpdateMode {
|
||||
Check,
|
||||
Change,
|
||||
}
|
||||
|
||||
pub(crate) fn exit_with_failure() {
|
||||
println!(
|
||||
"Not all lints defined properly. \
|
||||
Please run `cargo dev update_lints` to make sure all lints are defined properly."
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
/// Replaces a region in a file delimited by two lines matching regexes.
|
||||
///
|
||||
/// `path` is the relative path to the file on which you want to perform the replacement.
|
||||
///
|
||||
/// See `replace_region_in_text` for documentation of the other options.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path could not read or then written
|
||||
pub(crate) fn replace_region_in_file(
|
||||
update_mode: UpdateMode,
|
||||
path: &Path,
|
||||
start: &str,
|
||||
end: &str,
|
||||
write_replacement: impl FnMut(&mut String),
|
||||
) {
|
||||
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
|
||||
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
|
||||
Ok(x) => x,
|
||||
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
|
||||
};
|
||||
|
||||
match update_mode {
|
||||
UpdateMode::Check if contents != new_contents => exit_with_failure(),
|
||||
UpdateMode::Check => (),
|
||||
UpdateMode::Change => {
|
||||
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
|
||||
panic!("Cannot write to `{}`: {e}", path.display());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
|
||||
/// were found, or the missing delimiter if not.
|
||||
pub(crate) fn replace_region_in_text<'a>(
|
||||
text: &str,
|
||||
start: &'a str,
|
||||
end: &'a str,
|
||||
mut write_replacement: impl FnMut(&mut String),
|
||||
) -> Result<String, &'a str> {
|
||||
let (text_start, rest) = text.split_once(start).ok_or(start)?;
|
||||
let (_, text_end) = rest.split_once(end).ok_or(end)?;
|
||||
|
||||
let mut res = String::with_capacity(text.len() + 4096);
|
||||
res.push_str(text_start);
|
||||
res.push_str(start);
|
||||
write_replacement(&mut res);
|
||||
res.push_str(end);
|
||||
res.push_str(text_end);
|
||||
|
||||
Ok(res)
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
[package]
|
||||
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"
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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 => "",
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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}")
|
||||
|
@ -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,
|
||||
);
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -0,0 +1,45 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, AttrStyle, Attribute};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::DOC_INCLUDE_WITHOUT_CFG;
|
||||
|
||||
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
|
||||
for attr in attrs {
|
||||
if !attr.span.from_expansion()
|
||||
&& let AttrKind::Normal(ref normal) = attr.kind
|
||||
&& normal.item.path == sym::doc
|
||||
&& let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args
|
||||
&& !attr.span.contains(meta.span)
|
||||
// Since the `include_str` is already expanded at this point, we can only take the
|
||||
// whole attribute snippet and then modify for our suggestion.
|
||||
&& let Some(snippet) = snippet_opt(cx, attr.span)
|
||||
// We cannot remove this because a `#[doc = include_str!("...")]` attribute can occupy
|
||||
// several lines.
|
||||
&& let Some(start) = snippet.find('[')
|
||||
&& let Some(end) = snippet.rfind(']')
|
||||
&& let snippet = &snippet[start + 1..end]
|
||||
// We check that the expansion actually comes from `include_str!` and not just from
|
||||
// another macro.
|
||||
&& let Some(sub_snippet) = snippet.trim().strip_prefix("doc")
|
||||
&& let Some(sub_snippet) = sub_snippet.trim().strip_prefix("=")
|
||||
&& sub_snippet.trim().starts_with("include_str!")
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DOC_INCLUDE_WITHOUT_CFG,
|
||||
attr.span,
|
||||
"included a file in documentation unconditionally",
|
||||
"use `cfg_attr(doc, doc = \"...\")`",
|
||||
format!(
|
||||
"#{}[cfg_attr(doc, {snippet})]",
|
||||
if attr.style == AttrStyle::Inner { "!" } else { "" }
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#![allow(clippy::lint_without_lint_pass)]
|
||||
|
||||
mod lazy_continuation;
|
||||
mod 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";
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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::{
|
||||
|
@ -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,
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
..
|
||||
},
|
||||
|
@ -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));
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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`"
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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`"
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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)),
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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(());
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user