Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones 2024-04-18 17:25:59 +02:00
commit 846f6e7e00
No known key found for this signature in database
GPG Key ID: 1CA0DF2AF59D68A5
97 changed files with 1121 additions and 459 deletions

View File

@ -24,7 +24,7 @@ jobs:
node-version: '18.x' node-version: '18.x'
- name: Install remark - name: Install remark
run: npm install remark-cli remark-lint remark-lint-maximum-line-length remark-preset-lint-recommended remark-gfm run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm
- name: Install mdbook - name: Install mdbook
run: | run: |

View File

@ -5894,6 +5894,7 @@ Released 2018-09-13
[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates
[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
[`allowed-prefixes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-prefixes
[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts [`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts
[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports [`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports
[`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed [`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed

View File

@ -18,17 +18,27 @@ category.
| `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** |
| `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** |
| `clippy::suspicious` | code that is most likely wrong or useless | **warn** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** |
| `clippy::style` | code that should be written in a more idiomatic way | **warn** |
| `clippy::complexity` | code that does something simple but in a complex way | **warn** | | `clippy::complexity` | code that does something simple but in a complex way | **warn** |
| `clippy::perf` | code that can be written to run faster | **warn** | | `clippy::perf` | code that can be written to run faster | **warn** |
| `clippy::style` | code that should be written in a more idiomatic way | **warn** | | `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow |
| `clippy::pedantic` | lints which are rather strict or might have false positives | allow | | `clippy::restriction` | lints which prevent the use of language and library features[^restrict] | allow |
| `clippy::nursery` | new lints that are still under development | allow | | `clippy::nursery` | new lints that are still under development | allow |
| `clippy::cargo` | lints for the cargo manifest | allow | | allow | | `clippy::cargo` | lints for the cargo manifest | allow |
More to come, please [file an More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also The `restriction` category should, *emphatically*, not be enabled as a whole. The contained
contains "restriction lints", which are for things which are usually not lints may lint against perfectly reasonable code, may not have an alternative suggestion,
considered "bad", but may be useful to turn on in specific cases. These should and may contradict any other lints (including other categories). Lints should be considered
be used very selectively, if at all. on a case-by-case basis before enabling.
[^restrict]: Some use cases for `restriction` lints include:
- Strict coding styles (e.g. [`clippy::else_if_without_else`]).
- Additional restrictions on CI (e.g. [`clippy::todo`]).
- Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]).
- Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module).
[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used

View File

@ -18,7 +18,6 @@ because that's clearly a non-descriptive name.
- [Cargo lints](#cargo-lints) - [Cargo lints](#cargo-lints)
- [Rustfix tests](#rustfix-tests) - [Rustfix tests](#rustfix-tests)
- [Testing manually](#testing-manually) - [Testing manually](#testing-manually)
- [Running directly](#running-directly)
- [Lint declaration](#lint-declaration) - [Lint declaration](#lint-declaration)
- [Lint registration](#lint-registration) - [Lint registration](#lint-registration)
- [Lint passes](#lint-passes) - [Lint passes](#lint-passes)
@ -176,23 +175,26 @@ the tests.
Manually testing against an example file can be useful if you have added some Manually testing against an example file can be useful if you have added some
`println!`s and the test suite output becomes unreadable. To try Clippy with `println!`s and the test suite output becomes unreadable. To try Clippy with
your local modifications, run your local modifications, run the following from the Clippy directory:
``` ```bash
cargo dev lint input.rs cargo dev lint input.rs
``` ```
from the working copy root. With tests in place, let's have a look at To run Clippy on an existing project rather than a single file you can use
implementing our lint now.
## Running directly ```bash
cargo dev lint /path/to/project
```
While it's easier to just use `cargo dev lint`, it might be desirable to get Or set up a rustup toolchain that points to the local Clippy binaries
`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases.
By default, they don't work because clippy dynamically links rustc. To help them find rustc, ```bash
add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) cargo dev setup toolchain
to your library search path.
On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. # Then in `/path/to/project` you can run
cargo +clippy clippy
```
## Lint declaration ## Lint declaration

View File

@ -164,6 +164,32 @@ configuration of Clippy. By default, any configuration will replace the default
* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) * [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars)
## `allowed-prefixes`
List of prefixes to allow when determining whether an item's name ends with the module's name.
If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
then don't emit a warning.
#### Example
```toml
allowed-prefixes = [ "to", "from" ]
```
#### Noteworthy
- By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
- PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
`TryInto` will also be included)
- Use `".."` as part of the list to indicate that the configured values should be appended to the
default configuration of Clippy. By default, any configuration will replace the default value
**Default Value:** `["to", "as", "into", "from", "try_into", "try_from"]`
---
**Affected lints:**
* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions)
## `allowed-scripts` ## `allowed-scripts`
The list of unicode scripts allowed to be used in the scope. The list of unicode scripts allowed to be used in the scope.

View File

@ -39,6 +39,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
]; ];
const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
/// Conf with parse errors /// Conf with parse errors
#[derive(Default)] #[derive(Default)]
@ -589,6 +590,26 @@ define_Conf! {
/// 2. Paths with any segment that containing the word 'prelude' /// 2. Paths with any segment that containing the word 'prelude'
/// are already allowed by default. /// are already allowed by default.
(allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()), (allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
/// Lint: MODULE_NAME_REPETITIONS.
///
/// List of prefixes to allow when determining whether an item's name ends with the module's name.
/// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
/// then don't emit a warning.
///
/// #### Example
///
/// ```toml
/// allowed-prefixes = [ "to", "from" ]
/// ```
///
/// #### Noteworthy
///
/// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
/// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
/// `TryInto` will also be included)
/// - Use `".."` as part of the list to indicate that the configured values should be appended to the
/// default configuration of Clippy. By default, any configuration will replace the default value
(allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
} }
/// Search for the configuration file. /// Search for the configuration file.
@ -649,6 +670,7 @@ fn deserialize(file: &SourceFile) -> TryConf {
Ok(mut conf) => { Ok(mut conf) => {
extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES);
// TODO: THIS SHOULD BE TESTED, this comment will be gone soon // TODO: THIS SHOULD BE TESTED, this comment will be gone soon
if conf.conf.allowed_idents_below_min_chars.contains("..") { if conf.conf.allowed_idents_below_min_chars.contains("..") {
conf.conf conf.conf

View File

@ -35,7 +35,6 @@ struct FmtContext {
} }
// the "main" function of cargo dev fmt // the "main" function of cargo dev fmt
#[allow(clippy::missing_panics_doc)]
pub fn run(check: bool, verbose: bool) { pub fn run(check: bool, verbose: bool) {
fn try_run(context: &FmtContext) -> Result<bool, CliError> { fn try_run(context: &FmtContext) -> Result<bool, CliError> {
let mut success = true; let mut success = true;

View File

@ -9,6 +9,7 @@
unused_lifetimes, unused_lifetimes,
unused_qualifications unused_qualifications
)] )]
#![allow(clippy::missing_panics_doc)]
// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]

View File

@ -46,6 +46,13 @@ fn main() {
} }
}, },
Some(("setup", sub_command)) => match sub_command.subcommand() { Some(("setup", sub_command)) => match sub_command.subcommand() {
Some(("git-hook", matches)) => {
if matches.get_flag("remove") {
setup::git_hook::remove_hook();
} else {
setup::git_hook::install_hook(matches.get_flag("force-override"));
}
},
Some(("intellij", matches)) => { Some(("intellij", matches)) => {
if matches.get_flag("remove") { if matches.get_flag("remove") {
setup::intellij::remove_rustc_src(); setup::intellij::remove_rustc_src();
@ -57,12 +64,12 @@ fn main() {
); );
} }
}, },
Some(("git-hook", matches)) => { Some(("toolchain", matches)) => {
if matches.get_flag("remove") { setup::toolchain::create(
setup::git_hook::remove_hook(); matches.get_flag("force"),
} else { matches.get_flag("release"),
setup::git_hook::install_hook(matches.get_flag("force-override")); matches.get_one::<String>("name").unwrap(),
} );
}, },
Some(("vscode-tasks", matches)) => { Some(("vscode-tasks", matches)) => {
if matches.get_flag("remove") { if matches.get_flag("remove") {
@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches {
.about("Support for setting up your personal development environment") .about("Support for setting up your personal development environment")
.arg_required_else_help(true) .arg_required_else_help(true)
.subcommands([ .subcommands([
Command::new("git-hook")
.about("Add a pre-commit git hook that formats your code to make it look pretty")
.args([
Arg::new("remove")
.long("remove")
.action(ArgAction::SetTrue)
.help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
Arg::new("force-override")
.long("force-override")
.short('f')
.action(ArgAction::SetTrue)
.help("Forces the override of an existing git pre-commit hook"),
]),
Command::new("intellij") Command::new("intellij")
.about("Alter dependencies so Intellij Rust can find rustc internals") .about("Alter dependencies so Intellij Rust can find rustc internals")
.args([ .args([
@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches {
.conflicts_with("remove") .conflicts_with("remove")
.required(true), .required(true),
]), ]),
Command::new("git-hook") Command::new("toolchain")
.about("Add a pre-commit git hook that formats your code to make it look pretty") .about("Install a rustup toolchain pointing to the local clippy build")
.args([ .args([
Arg::new("remove") Arg::new("force")
.long("remove") .long("force")
.action(ArgAction::SetTrue)
.help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
Arg::new("force-override")
.long("force-override")
.short('f') .short('f')
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.help("Forces the override of an existing git pre-commit hook"), .help("Override an existing toolchain"),
Arg::new("release")
.long("release")
.short('r')
.action(ArgAction::SetTrue)
.help("Point to --release clippy binaries"),
Arg::new("name")
.long("name")
.default_value("clippy")
.help("The name of the created toolchain"),
]), ]),
Command::new("vscode-tasks") Command::new("vscode-tasks")
.about("Add several tasks to vscode for formatting, validation and testing") .about("Add several tasks to vscode for formatting, validation and testing")

View File

@ -36,7 +36,6 @@ impl<T> Context for io::Result<T> {
/// # Errors /// # Errors
/// ///
/// This function errors out if the files couldn't be created or written to. /// This function errors out if the files couldn't be created or written to.
#[allow(clippy::missing_panics_doc)]
pub fn create( pub fn create(
pass: &String, pass: &String,
lint_name: Option<&String>, lint_name: Option<&String>,

View File

@ -1,5 +1,6 @@
pub mod git_hook; pub mod git_hook;
pub mod intellij; pub mod intellij;
pub mod toolchain;
pub mod vscode; pub mod vscode;
use std::path::Path; use std::path::Path;

View File

@ -0,0 +1,75 @@
use std::env::consts::EXE_SUFFIX;
use std::env::current_dir;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
use super::verify_inside_clippy_dir;
pub fn create(force: bool, release: bool, name: &str) {
if !verify_inside_clippy_dir() {
return;
}
let rustup_home = std::env::var("RUSTUP_HOME").unwrap();
let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap();
let src = PathBuf::from_iter([&rustup_home, "toolchains", &toolchain]);
let dest = PathBuf::from_iter([&rustup_home, "toolchains", name]);
if dest.exists() {
if force {
fs::remove_dir_all(&dest).unwrap();
} else {
println!("{} already exists, pass `--force` to override it", dest.display());
return;
}
}
for entry in WalkDir::new(&src) {
let entry = entry.unwrap();
let relative = entry.path().strip_prefix(&src).unwrap();
if relative.starts_with("bin")
&& matches!(
relative.file_stem().and_then(OsStr::to_str),
Some("cargo-clippy" | "clippy-driver")
)
{
continue;
}
let target = dest.join(relative);
if entry.file_type().is_dir() {
fs::create_dir(&target).unwrap();
} else {
fs::hard_link(entry.path(), target).unwrap();
}
}
symlink_bin("cargo-clippy", &dest, release);
symlink_bin("clippy-driver", &dest, release);
println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`");
println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes");
}
fn symlink_bin(bin: &str, dest: &Path, release: bool) {
#[cfg(windows)]
use std::os::windows::fs::symlink_file as symlink;
#[cfg(not(windows))]
use std::os::unix::fs::symlink;
let profile = if release { "release" } else { "debug" };
let file_name = format!("{bin}{EXE_SUFFIX}");
let mut src = current_dir().unwrap();
src.extend(["target", profile, &file_name]);
let mut dest = dest.to_path_buf();
dest.extend(["bin", &file_name]);
symlink(src, dest).unwrap();
}

View File

@ -56,7 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
&& let Some(send) = cx.tcx.get_diagnostic_item(sym::Send) && let Some(send) = cx.tcx.get_diagnostic_item(sym::Send)
&& let Some(sync) = cx.tcx.lang_items().sync_trait() && let Some(sync) = cx.tcx.lang_items().sync_trait()
&& let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[])) && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
&& !(is_send && is_sync) && let reason = match (is_send, is_sync) {
(false, false) => "neither `Send` nor `Sync`",
(false, true) => "not `Send`",
(true, false) => "not `Sync`",
_ => return,
}
&& !is_from_proc_macro(cx, expr) && !is_from_proc_macro(cx, expr)
{ {
span_lint_and_then( span_lint_and_then(
@ -66,21 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
"usage of an `Arc` that is not `Send` and `Sync`", "usage of an `Arc` that is not `Send` and `Sync`",
|diag| { |diag| {
with_forced_trimmed_paths!({ with_forced_trimmed_paths!({
diag.note(format!("`Arc<{arg_ty}>` is not `Send` and `Sync` as:"));
if !is_send {
diag.note(format!("- the trait `Send` is not implemented for `{arg_ty}`"));
}
if !is_sync {
diag.note(format!("- the trait `Sync` is not implemented for `{arg_ty}`"));
}
diag.help("consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types");
diag.note("if you intend to use `Arc` with `Send` and `Sync` traits");
diag.note(format!( diag.note(format!(
"wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `{arg_ty}`" "`Arc<{arg_ty}>` is not `Send` and `Sync` as `{arg_ty}` is {reason}"
));
diag.help("if the `Arc` will not used be across threads replace it with an `Rc`");
diag.help(format!(
"otherwise make `{arg_ty}` `Send` and `Sync` or consider a wrapper type such as `Mutex`"
)); ));
}); });
}, },

View File

@ -2,12 +2,12 @@ use super::DUPLICATED_ATTRIBUTES;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use rustc_ast::{Attribute, MetaItem}; use rustc_ast::{Attribute, MetaItem};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_lint::EarlyContext; use rustc_lint::LateContext;
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
fn emit_if_duplicated( fn emit_if_duplicated(
cx: &EarlyContext<'_>, cx: &LateContext<'_>,
attr: &MetaItem, attr: &MetaItem,
attr_paths: &mut FxHashMap<String, Span>, attr_paths: &mut FxHashMap<String, Span>,
complete_path: String, complete_path: String,
@ -26,7 +26,7 @@ fn emit_if_duplicated(
} }
fn check_duplicated_attr( fn check_duplicated_attr(
cx: &EarlyContext<'_>, cx: &LateContext<'_>,
attr: &MetaItem, attr: &MetaItem,
attr_paths: &mut FxHashMap<String, Span>, attr_paths: &mut FxHashMap<String, Span>,
parent: &mut Vec<String>, parent: &mut Vec<String>,
@ -64,7 +64,7 @@ fn check_duplicated_attr(
} }
} }
pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
let mut attr_paths = FxHashMap::default(); let mut attr_paths = FxHashMap::default();
for attr in attrs { for attr in attrs {

View File

@ -17,7 +17,7 @@ mod useless_attribute;
mod utils; mod utils;
use clippy_config::msrvs::Msrv; use clippy_config::msrvs::Msrv;
use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem}; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, impl_lint_pass}; use rustc_session::{declare_lint_pass, impl_lint_pass};
@ -534,11 +534,13 @@ declare_lint_pass!(Attributes => [
BLANKET_CLIPPY_RESTRICTION_LINTS, BLANKET_CLIPPY_RESTRICTION_LINTS,
SHOULD_PANIC_WITHOUT_EXPECT, SHOULD_PANIC_WITHOUT_EXPECT,
MIXED_ATTRIBUTES_STYLE, MIXED_ATTRIBUTES_STYLE,
DUPLICATED_ATTRIBUTES,
]); ]);
impl<'tcx> LateLintPass<'tcx> for Attributes { impl<'tcx> LateLintPass<'tcx> for Attributes {
fn check_crate(&mut self, cx: &LateContext<'tcx>) { fn check_crate(&mut self, cx: &LateContext<'tcx>) {
blanket_clippy_restriction_lints::check_command_line(cx); blanket_clippy_restriction_lints::check_command_line(cx);
duplicated_attributes::check(cx, cx.tcx.hir().krate_attrs());
} }
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
@ -578,6 +580,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
_ => {}, _ => {},
} }
mixed_attributes_style::check(cx, item.span, attrs); mixed_attributes_style::check(cx, item.span, attrs);
duplicated_attributes::check(cx, attrs);
} }
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
@ -606,17 +609,11 @@ impl_lint_pass!(EarlyAttributes => [
MAYBE_MISUSED_CFG, MAYBE_MISUSED_CFG,
DEPRECATED_CLIPPY_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR,
UNNECESSARY_CLIPPY_CFG, UNNECESSARY_CLIPPY_CFG,
DUPLICATED_ATTRIBUTES,
]); ]);
impl EarlyLintPass for EarlyAttributes { impl EarlyLintPass for EarlyAttributes {
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
duplicated_attributes::check(cx, &krate.attrs);
}
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
empty_line_after::check(cx, item); empty_line_after::check(cx, item);
duplicated_attributes::check(cx, &item.attrs);
} }
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {

View File

@ -346,11 +346,18 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
_ => None, _ => None,
} }
.and_then(|op| { .and_then(|op| {
Some(format!( let lhs_snippet = snippet_opt(cx, lhs.span)?;
"{}{op}{}", let rhs_snippet = snippet_opt(cx, rhs.span)?;
snippet_opt(cx, lhs.span)?,
snippet_opt(cx, rhs.span)? if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) {
)) if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) {
// e.g. `(a as u64) < b`. Without the parens the `<` is
// interpreted as a start of generic arguments for `u64`
return Some(format!("({lhs_snippet}){op}{rhs_snippet}"));
}
}
Some(format!("{lhs_snippet}{op}{rhs_snippet}"))
}) })
}, },
ExprKind::MethodCall(path, receiver, [], _) => { ExprKind::MethodCall(path, receiver, [], _) => {

View File

@ -754,11 +754,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts { impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) { if in_external_macro(cx.sess(), expr.span) {
ptr_as_ptr::check(cx, expr, &self.msrv);
}
if expr.span.from_expansion() {
return; return;
} }
@ -771,7 +767,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(expr),
); );
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
return; return;
} }
cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv); cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
@ -782,7 +778,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
zero_ptr::check(cx, expr, cast_expr, cast_to_hir); zero_ptr::check(cx, expr, cast_expr, cast_to_hir);
if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { if cast_to.is_numeric() {
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span); cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
if cast_from.is_numeric() { if cast_from.is_numeric() {
cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to);

View File

@ -1016,9 +1016,18 @@ fn report<'tcx>(
}, },
_ => (0, false), _ => (0, false),
}; };
let is_in_tuple = matches!(
get_parent_expr(cx, data.first_expr),
Some(Expr {
kind: ExprKind::Tup(..),
..
})
);
let sugg = if !snip_is_macro let sugg = if !snip_is_macro
&& (calls_field || expr.precedence().order() < precedence) && (calls_field || expr.precedence().order() < precedence)
&& !has_enclosing_paren(&snip) && !has_enclosing_paren(&snip)
&& !is_in_tuple
{ {
format!("({snip})") format!("({snip})")
} else { } else {

View File

@ -132,7 +132,7 @@ declare_clippy_lint! {
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// Deriving `serde::Deserialize` will create a constructor /// Deriving `serde::Deserialize` will create a constructor
/// that may violate invariants hold by another constructor. /// that may violate invariants held by another constructor.
/// ///
/// ### Example /// ### Example
/// ```rust,ignore /// ```rust,ignore

View File

@ -11,7 +11,7 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_D
pub fn check( pub fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
owner_id: OwnerId, owner_id: OwnerId,
sig: &FnSig<'_>, sig: FnSig<'_>,
headers: DocHeaders, headers: DocHeaders,
body_id: Option<BodyId>, body_id: Option<BodyId>,
panic_span: Option<Span>, panic_span: Option<Span>,

View File

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::Visitable; use clippy_utils::visitors::Visitable;
use clippy_utils::{is_entrypoint_fn, method_chain_args}; use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
use pulldown_cmark::Event::{ use pulldown_cmark::Event::{
Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
}; };
@ -11,9 +11,8 @@ use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph}
use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
use rustc_ast::ast::Attribute; use rustc_ast::ast::Attribute;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr}; use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, TraitItemKind, Unsafety};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
@ -366,7 +365,6 @@ declare_clippy_lint! {
#[derive(Clone)] #[derive(Clone)]
pub struct Documentation { pub struct Documentation {
valid_idents: FxHashSet<String>, valid_idents: FxHashSet<String>,
in_trait_impl: bool,
check_private_items: bool, check_private_items: bool,
} }
@ -374,7 +372,6 @@ impl Documentation {
pub fn new(valid_idents: &[String], check_private_items: bool) -> Self { pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
Self { Self {
valid_idents: valid_idents.iter().cloned().collect(), valid_idents: valid_idents.iter().cloned().collect(),
in_trait_impl: false,
check_private_items, check_private_items,
} }
} }
@ -394,36 +391,72 @@ impl_lint_pass!(Documentation => [
]); ]);
impl<'tcx> LateLintPass<'tcx> for Documentation { impl<'tcx> LateLintPass<'tcx> for Documentation {
fn check_crate(&mut self, cx: &LateContext<'tcx>) { fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
check_attrs(cx, &self.valid_idents, attrs);
}
fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::Variant<'tcx>) {
let attrs = cx.tcx.hir().attrs(variant.hir_id);
check_attrs(cx, &self.valid_idents, attrs);
}
fn check_field_def(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::FieldDef<'tcx>) {
let attrs = cx.tcx.hir().attrs(variant.hir_id);
check_attrs(cx, &self.valid_idents, attrs);
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
return; return;
}; };
match item.kind { match cx.tcx.hir_node(cx.last_node_with_lint_attrs) {
hir::ItemKind::Fn(ref sig, _, body_id) => { Node::Item(item) => match item.kind {
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { ItemKind::Fn(sig, _, body_id) => {
let body = cx.tcx.hir().body(body_id); if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
let body = cx.tcx.hir().body(body_id);
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
missing_headers::check(
cx,
item.owner_id,
sig,
headers,
Some(body_id),
panic_span,
self.check_private_items,
);
}
},
ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
(false, Unsafety::Unsafe) => span_lint(
cx,
MISSING_SAFETY_DOC,
cx.tcx.def_span(item.owner_id),
"docs for unsafe trait missing `# Safety` section",
),
(true, Unsafety::Normal) => span_lint(
cx,
UNNECESSARY_SAFETY_DOC,
cx.tcx.def_span(item.owner_id),
"docs for safe trait have unnecessary `# Safety` section",
),
_ => (),
},
_ => (),
},
Node::TraitItem(trait_item) => {
if let TraitItemKind::Fn(sig, ..) = trait_item.kind
&& !in_external_macro(cx.tcx.sess, trait_item.span)
{
missing_headers::check( missing_headers::check(
cx, cx,
item.owner_id, trait_item.owner_id,
sig,
headers,
None,
None,
self.check_private_items,
);
}
},
Node::ImplItem(impl_item) => {
if let ImplItemKind::Fn(sig, body_id) = impl_item.kind
&& !in_external_macro(cx.tcx.sess, impl_item.span)
&& !is_trait_impl_item(cx, impl_item.hir_id())
{
let body = cx.tcx.hir().body(body_id);
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value);
missing_headers::check(
cx,
impl_item.owner_id,
sig, sig,
headers, headers,
Some(body_id), Some(body_id),
@ -432,67 +465,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
); );
} }
}, },
hir::ItemKind::Impl(impl_) => { _ => {},
self.in_trait_impl = impl_.of_trait.is_some();
},
hir::ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
(false, hir::Unsafety::Unsafe) => span_lint(
cx,
MISSING_SAFETY_DOC,
cx.tcx.def_span(item.owner_id),
"docs for unsafe trait missing `# Safety` section",
),
(true, hir::Unsafety::Normal) => span_lint(
cx,
UNNECESSARY_SAFETY_DOC,
cx.tcx.def_span(item.owner_id),
"docs for safe trait have unnecessary `# Safety` section",
),
_ => (),
},
_ => (),
}
}
fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if let hir::ItemKind::Impl { .. } = item.kind {
self.in_trait_impl = false;
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
return;
};
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
if !in_external_macro(cx.tcx.sess, item.span) {
missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items);
}
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
return;
};
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
return;
}
if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
let body = cx.tcx.hir().body(body_id);
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
missing_headers::check(
cx,
item.owner_id,
sig,
headers,
Some(body_id),
panic_span,
self.check_private_items,
);
} }
} }
} }

View File

@ -181,6 +181,9 @@ fn convert_to_from(
let from = snippet_opt(cx, self_ty.span)?; let from = snippet_opt(cx, self_ty.span)?;
let into = snippet_opt(cx, target_ty.span)?; let into = snippet_opt(cx, target_ty.span)?;
let return_type = matches!(sig.decl.output, FnRetTy::Return(_))
.then_some(String::from("Self"))
.unwrap_or_default();
let mut suggestions = vec![ let mut suggestions = vec![
// impl Into<T> for U -> impl From<T> for U // impl Into<T> for U -> impl From<T> for U
// ~~~~ ~~~~ // ~~~~ ~~~~
@ -197,13 +200,10 @@ fn convert_to_from(
// fn into([mut] self) -> T -> fn into([mut] v: T) -> T // fn into([mut] self) -> T -> fn into([mut] v: T) -> T
// ~~~~ ~~~~ // ~~~~ ~~~~
(self_ident.span, format!("val: {from}")), (self_ident.span, format!("val: {from}")),
];
if let FnRetTy::Return(_) = sig.decl.output {
// fn into(self) -> T -> fn into(self) -> Self // fn into(self) -> T -> fn into(self) -> Self
// ~ ~~~~ // ~ ~~~~
suggestions.push((sig.decl.output.span(), String::from("Self"))); (sig.decl.output.span(), return_type),
} ];
let mut finder = SelfFinder { let mut finder = SelfFinder {
cx, cx,

View File

@ -7,8 +7,8 @@ use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty; use rustc_middle::ty;

View File

@ -5,6 +5,7 @@ use clippy_utils::is_bool;
use clippy_utils::macros::span_is_local; use clippy_utils::macros::span_is_local;
use clippy_utils::source::is_present_in_source; use clippy_utils::source::is_present_in_source;
use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
@ -147,6 +148,7 @@ pub struct ItemNameRepetitions {
struct_threshold: u64, struct_threshold: u64,
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
allow_private_module_inception: bool, allow_private_module_inception: bool,
allowed_prefixes: FxHashSet<String>,
} }
impl ItemNameRepetitions { impl ItemNameRepetitions {
@ -156,6 +158,7 @@ impl ItemNameRepetitions {
struct_threshold: u64, struct_threshold: u64,
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
allow_private_module_inception: bool, allow_private_module_inception: bool,
allowed_prefixes: &[String],
) -> Self { ) -> Self {
Self { Self {
modules: Vec::new(), modules: Vec::new(),
@ -163,8 +166,13 @@ impl ItemNameRepetitions {
struct_threshold, struct_threshold,
avoid_breaking_exported_api, avoid_breaking_exported_api,
allow_private_module_inception, allow_private_module_inception,
allowed_prefixes: allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
} }
} }
fn is_allowed_prefix(&self, prefix: &str) -> bool {
self.allowed_prefixes.contains(prefix)
}
} }
impl_lint_pass!(ItemNameRepetitions => [ impl_lint_pass!(ItemNameRepetitions => [
@ -423,7 +431,9 @@ impl LateLintPass<'_> for ItemNameRepetitions {
_ => (), _ => (),
} }
} }
if rmatching.char_count == nchars { if rmatching.char_count == nchars
&& !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count])
{
span_lint( span_lint(
cx, cx,
MODULE_NAME_REPETITIONS, MODULE_NAME_REPETITIONS,

View File

@ -17,7 +17,7 @@ declare_clippy_lint! {
/// `std::<float>::EPSILON`, etc. /// `std::<float>::EPSILON`, etc.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// All of these have been superceded by the associated constants on their respective types, /// All of these have been superseded by the associated constants on their respective types,
/// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust. /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust.
/// ///
/// ### Example /// ### Example

View File

@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
pub_underscore_fields_behavior, pub_underscore_fields_behavior,
ref allowed_duplicate_crates, ref allowed_duplicate_crates,
allow_comparison_to_zero, allow_comparison_to_zero,
ref allowed_prefixes,
blacklisted_names: _, blacklisted_names: _,
cyclomatic_complexity_threshold: _, cyclomatic_complexity_threshold: _,
@ -864,6 +865,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
struct_field_name_threshold, struct_field_name_threshold,
avoid_breaking_exported_api, avoid_breaking_exported_api,
allow_private_module_inception, allow_private_module_inception,
allowed_prefixes,
)) ))
}); });
store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));

View File

@ -291,10 +291,7 @@ fn elision_suggestions(
}) => { }) => {
// expand `&'a T` to `&'a T` // expand `&'a T` to `&'a T`
// ^^ ^^^ // ^^ ^^^
let span = cx let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
.sess()
.source_map()
.span_extend_while_whitespace(usage.ident.span);
(span, String::new()) (span, String::new())
}, },

View File

@ -1,13 +1,14 @@
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath}; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::GenericArgKind;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::sym; use rustc_span::sym;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt; use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait; use clippy_utils::ty::implements_trait;
use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment}; use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment};
@ -105,19 +106,39 @@ fn get_some_and_none_bodies<'tcx>(
} }
} }
fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { #[allow(clippy::needless_pass_by_value)]
let ExprKind::Match(match_expr, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) = expr.kind else { fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, expr: &'tcx Expr<'tcx>) {
return false; // Get expr_name ("if let" or "match" depending on kind of expression), the condition, the body for
// the some arm, the body for the none arm and the binding id of the some arm
let (expr_name, condition, body_some, body_none, binding_id) = match if_let_or_match {
IfLetOrMatch::Match(condition, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar)
// Make sure there are no guards to keep things simple
if arm1.guard.is_none()
&& arm2.guard.is_none()
// Get the some and none bodies and the binding id of the some arm
&& let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) =>
{
("match", condition, body_some, body_none, binding_id)
},
IfLetOrMatch::IfLet(condition, pat, if_expr, Some(else_expr), _)
if let Some(binding_id) = get_some(cx, pat) =>
{
("if let", condition, if_expr, else_expr, binding_id)
},
_ => {
// All other cases (match with number of arms != 2, if let without else, etc.)
return;
},
}; };
// We don't want conditions on the arms to simplify things.
if arm1.guard.is_none() // We check if the return type of the expression implements Default.
&& arm2.guard.is_none() let expr_type = cx.typeck_results().expr_ty(expr);
// We check that the returned type implements the `Default` trait. if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
&& let match_ty = cx.typeck_results().expr_ty(expr) && implements_trait(cx, expr_type, default_trait_id, &[])
&& let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) // We check if the initial condition implements Default.
&& implements_trait(cx, match_ty, default_trait_id, &[]) && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1)
// We now get the bodies for both the `Some` and `None` arms. && let GenericArgKind::Type(condition_ty) = condition_ty.unpack()
&& let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) && implements_trait(cx, condition_ty, default_trait_id, &[])
// We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
&& let Res::Local(local_id) = path.res && let Res::Local(local_id) = path.res
@ -125,8 +146,9 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
// We now check the `None` arm is calling a method equivalent to `Default::default`. // We now check the `None` arm is calling a method equivalent to `Default::default`.
&& let body_none = peel_blocks(body_none) && let body_none = peel_blocks(body_none)
&& is_default_equivalent(cx, body_none) && is_default_equivalent(cx, body_none)
&& let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par) && let Some(receiver) = Sugg::hir_opt(cx, condition).map(Sugg::maybe_par)
{ {
// Machine applicable only if there are no comments present
let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
Applicability::MaybeIncorrect Applicability::MaybeIncorrect
} else { } else {
@ -136,48 +158,12 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
cx, cx,
MANUAL_UNWRAP_OR_DEFAULT, MANUAL_UNWRAP_OR_DEFAULT,
expr.span, expr.span,
"match can be simplified with `.unwrap_or_default()`", format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
"replace it with", "replace it with",
format!("{receiver}.unwrap_or_default()"), format!("{receiver}.unwrap_or_default()"),
applicability, applicability,
); );
} }
true
}
fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::If(cond, if_block, Some(else_expr)) = expr.kind
&& let ExprKind::Let(let_) = cond.kind
&& let ExprKind::Block(_, _) = else_expr.kind
// We check that the returned type implements the `Default` trait.
&& let match_ty = cx.typeck_results().expr_ty(expr)
&& let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
&& implements_trait(cx, match_ty, default_trait_id, &[])
&& let Some(binding_id) = get_some(cx, let_.pat)
// We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind
&& let Res::Local(local_id) = path.res
&& local_id == binding_id
// We now check the `None` arm is calling a method equivalent to `Default::default`.
&& let body_else = peel_blocks(else_expr)
&& is_default_equivalent(cx, body_else)
&& let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span)
{
let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
Applicability::MaybeIncorrect
} else {
Applicability::MachineApplicable
};
span_lint_and_sugg(
cx,
MANUAL_UNWRAP_OR_DEFAULT,
expr.span,
"if let can be simplified with `.unwrap_or_default()`",
"replace it with",
format!("{if_let_expr_snippet}.unwrap_or_default()"),
applicability,
);
}
} }
impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
@ -185,8 +171,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
return; return;
} }
if !handle_match(cx, expr) { // Call handle only if the expression is `if let` or `match`
handle_if_let(cx, expr); if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) {
handle(cx, if_let_or_match, expr);
} }
} }
} }

View File

@ -3938,7 +3938,6 @@ declare_clippy_lint! {
/// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or /// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or
/// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is
/// valid. /// valid.
/// ```
#[clippy::version = "1.77.0"] #[clippy::version = "1.77.0"]
pub STR_SPLIT_AT_NEWLINE, pub STR_SPLIT_AT_NEWLINE,
pedantic, pedantic,

View File

@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::deref_closure_args; use clippy_utils::sugg::deref_closure_args;
use clippy_utils::ty::is_type_lang_item; use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{is_trait_method, strip_pat_refs}; use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs};
use hir::ExprKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::PatKind; use rustc_hir::PatKind;
@ -35,7 +36,7 @@ pub(super) fn check<'tcx>(
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let any_search_snippet = if search_method == "find" let any_search_snippet = if search_method == "find"
&& let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
&& let closure_body = cx.tcx.hir().body(body) && let closure_body = cx.tcx.hir().body(body)
&& let Some(closure_arg) = closure_body.params.first() && let Some(closure_arg) = closure_body.params.first()
{ {
@ -72,16 +73,24 @@ pub(super) fn check<'tcx>(
); );
} else { } else {
let iter = snippet(cx, search_recv.span, ".."); let iter = snippet(cx, search_recv.span, "..");
let sugg = if is_receiver_of_method_call(cx, expr) {
format!(
"(!{iter}.any({}))",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
)
} else {
format!(
"!{iter}.any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
)
};
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
SEARCH_IS_SOME, SEARCH_IS_SOME,
expr.span, expr.span,
msg, msg,
"consider using", "consider using",
format!( sugg,
"!{iter}.any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
applicability, applicability,
); );
} }
@ -127,13 +136,18 @@ pub(super) fn check<'tcx>(
let string = snippet(cx, search_recv.span, ".."); let string = snippet(cx, search_recv.span, "..");
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
let sugg = if is_receiver_of_method_call(cx, expr) {
format!("(!{string}.contains({find_arg}))")
} else {
format!("!{string}.contains({find_arg})")
};
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
SEARCH_IS_SOME, SEARCH_IS_SOME,
expr.span, expr.span,
msg, msg,
"consider using", "consider using",
format!("!{string}.contains({find_arg})"), sugg,
applicability, applicability,
); );
}, },
@ -142,3 +156,13 @@ pub(super) fn check<'tcx>(
} }
} }
} }
fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind
&& receiver.hir_id == expr.hir_id
{
return true;
}
false
}

View File

@ -5,7 +5,8 @@ use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind}; use rustc_middle::ty;
use rustc_middle::ty::GenericArgKind;
use rustc_span::sym; use rustc_span::sym;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use std::iter; use std::iter;

View File

@ -96,10 +96,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
self.found = true; self.found = true;
return; return;
}, },
ExprKind::If(..) => {
self.found = true;
return;
},
ExprKind::Path(_) => { ExprKind::Path(_) => {
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) { if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
if adj if adj

View File

@ -23,7 +23,7 @@ use std::collections::VecDeque;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Checks for borrow operations (`&`) that used as a generic argument to a /// Checks for borrow operations (`&`) that are used as a generic argument to a
/// function when the borrowed value could be used. /// function when the borrowed value could be used.
/// ///
/// ### Why is this bad? /// ### Why is this bad?

View File

@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{sym, DUMMY_SP, InnerSpan, Span}; use rustc_span::{sym, InnerSpan, Span, DUMMY_SP};
use rustc_target::abi::VariantIdx; use rustc_target::abi::VariantIdx;
// FIXME: this is a correctness problem but there's no suitable // FIXME: this is a correctness problem but there's no suitable
@ -297,12 +297,7 @@ impl NonCopyConst {
fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
let args = cx.typeck_results().node_args(hir_id); let args = cx.typeck_results().node_args(hir_id);
let result = Self::const_eval_resolve( let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP);
cx.tcx,
cx.param_env,
ty::UnevaluatedConst::new(def_id, args),
DUMMY_SP,
);
self.is_value_unfrozen_raw(cx, result, ty) self.is_value_unfrozen_raw(cx, result, ty)
} }

View File

@ -300,11 +300,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
e.span, e.span,
"calling `as_bytes()` on `include_str!(..)`", "calling `as_bytes()` on `include_str!(..)`",
"consider using `include_bytes!(..)` instead", "consider using `include_bytes!(..)` instead",
snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability).replacen( snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability)
"include_str", .replacen("include_str", "include_bytes", 1),
"include_bytes",
1,
),
applicability, applicability,
); );
} else if lit_content.as_str().is_ascii() } else if lit_content.as_str().is_ascii()

View File

@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
}; };
// FIXME: This can be simplified once `NonZero<T>` is stable. // FIXME: This can be simplified once `NonZero<T>` is stable.
let coercable_types = [ let coercible_types = [
("NonZeroU8", tcx.types.u8), ("NonZeroU8", tcx.types.u8),
("NonZeroU16", tcx.types.u16), ("NonZeroU16", tcx.types.u16),
("NonZeroU32", tcx.types.u32), ("NonZeroU32", tcx.types.u32),
@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
let int_type = substs.type_at(0); let int_type = substs.type_at(0);
let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { let Some(nonzero_alias) = coercible_types.iter().find_map(|(nonzero_alias, t)| {
if *t == int_type && *t == from_ty { if *t == int_type && *t == from_ty {
Some(nonzero_alias) Some(nonzero_alias)
} else { } else {

View File

@ -1,10 +1,10 @@
use rustc_hir_typeck::cast::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::ExprPrecedence; use rustc_ast::ExprPrecedence;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, Node}; use rustc_hir::{Expr, Node};
use rustc_hir_typeck::cast::check_cast;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::cast::CastKind;
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;

View File

@ -709,8 +709,12 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
(ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => {
over(lg, rg, eq_generic_bound) && both(lc, rc, |lc, rc| over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)), over(lg, rg, eq_generic_bound)
&& both(lc, rc, |lc, rc| {
over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)
})
},
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r), (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
_ => false, _ => false,

View File

@ -3285,7 +3285,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
Right(r) => Right(r.data), Right(r) => Right(r.data),
}); });
// 2. for the remaning segments, construct relative path using only mod names and `super` // 2. for the remaining segments, construct relative path using only mod names and `super`
let mut go_up_by = 0; let mut go_up_by = 0;
let mut path = Vec::new(); let mut path = Vec::new();
for el in unique_parts { for el in unique_parts {

View File

@ -8,7 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::source_map::{original_sp, SourceMap}; use rustc_span::source_map::{original_sp, SourceMap};
use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP};
use std::borrow::Cow; use std::borrow::Cow;
use std::ops::Range; use std::ops::Range;

View File

@ -10,7 +10,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
use rustc_infer::infer::type_variable::{TypeVariableOrigin}; use rustc_infer::infer::type_variable::TypeVariableOrigin;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::interpret::Scalar;

View File

@ -90,7 +90,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
if let Some(def_id) = adt_def_id(expr_ty) { if let Some(def_id) = adt_def_id(expr_ty) {
certainty.with_def_id(def_id) certainty.with_def_id(def_id)
} else { } else {
certainty certainty.clear_def_id()
} }
} }

View File

@ -26,12 +26,12 @@ use std::env::consts::EXE_SUFFIX;
use std::fmt::{self, Write as _}; use std::fmt::{self, Write as _};
use std::io::{self, ErrorKind}; use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::{Command, ExitStatus};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration; use std::time::Duration;
use std::{env, fs, thread}; use std::{env, fs, thread};
use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel}; use cargo_metadata::diagnostic::Diagnostic;
use cargo_metadata::Message; use cargo_metadata::Message;
use rayon::prelude::*; use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -97,16 +97,43 @@ struct Crate {
options: Option<Vec<String>>, options: Option<Vec<String>>,
} }
/// A single emitted output from clippy being executed on a crate. It may either be a
/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
#[derive(Debug)]
enum ClippyCheckOutput {
ClippyWarning(ClippyWarning),
RustcIce(RustcIce),
}
#[derive(Debug)]
struct RustcIce {
pub crate_name: String,
pub ice_content: String,
}
impl RustcIce {
pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> {
if status.code().unwrap_or(0) == 101
/* ice exit status */
{
Some(Self {
crate_name: crate_name.to_owned(),
ice_content: stderr.to_owned(),
})
} else {
None
}
}
}
/// A single warning that clippy issued while checking a `Crate` /// A single warning that clippy issued while checking a `Crate`
#[derive(Debug)] #[derive(Debug)]
struct ClippyWarning { struct ClippyWarning {
crate_name: String,
file: String, file: String,
line: usize, line: usize,
column: usize, column: usize,
lint_type: String, lint_type: String,
message: String, message: String,
is_ice: bool,
} }
#[allow(unused)] #[allow(unused)]
@ -131,13 +158,11 @@ impl ClippyWarning {
}; };
Some(Self { Some(Self {
crate_name: crate_name.to_owned(),
file, file,
line: span.line_start, line: span.line_start,
column: span.column_start, column: span.column_start,
lint_type, lint_type,
message: diag.message, message: diag.message,
is_ice: diag.level == DiagnosticLevel::Ice,
}) })
} }
@ -318,7 +343,7 @@ impl Crate {
config: &LintcheckConfig, config: &LintcheckConfig,
lint_filter: &[String], lint_filter: &[String],
server: &Option<LintcheckServer>, server: &Option<LintcheckServer>,
) -> Vec<ClippyWarning> { ) -> Vec<ClippyCheckOutput> {
// advance the atomic index by one // advance the atomic index by one
let index = target_dir_index.fetch_add(1, Ordering::SeqCst); let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
// "loop" the index within 0..thread_limit // "loop" the index within 0..thread_limit
@ -342,9 +367,9 @@ impl Crate {
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
let mut cargo_clippy_args = if config.fix { let mut cargo_clippy_args = if config.fix {
vec!["--fix", "--"] vec!["--quiet", "--fix", "--"]
} else { } else {
vec!["--", "--message-format=json", "--"] vec!["--quiet", "--message-format=json", "--"]
}; };
let mut clippy_args = Vec::<&str>::new(); let mut clippy_args = Vec::<&str>::new();
@ -435,14 +460,21 @@ impl Crate {
} }
// get all clippy warnings and ICEs // get all clippy warnings and ICEs
let warnings: Vec<ClippyWarning> = Message::parse_stream(stdout.as_bytes()) let mut entries: Vec<ClippyCheckOutput> = Message::parse_stream(stdout.as_bytes())
.filter_map(|msg| match msg { .filter_map(|msg| match msg {
Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version),
_ => None, _ => None,
}) })
.map(ClippyCheckOutput::ClippyWarning)
.collect(); .collect();
warnings if let Some(ice) = RustcIce::from_stderr_and_status(&self.name, *status, &stderr) {
entries.push(ClippyCheckOutput::RustcIce(ice));
} else if !status.success() {
println!("non-ICE bad exit status for {} {}: {}", self.name, self.version, stderr);
}
entries
} }
} }
@ -642,7 +674,7 @@ fn main() {
LintcheckServer::spawn(recursive_options) LintcheckServer::spawn(recursive_options)
}); });
let mut clippy_warnings: Vec<ClippyWarning> = crates let mut clippy_entries: Vec<ClippyCheckOutput> = crates
.par_iter() .par_iter()
.flat_map(|krate| { .flat_map(|krate| {
krate.run_clippy_lints( krate.run_clippy_lints(
@ -658,7 +690,9 @@ fn main() {
.collect(); .collect();
if let Some(server) = server { if let Some(server) = server {
clippy_warnings.extend(server.warnings()); let server_clippy_entries = server.warnings().map(ClippyCheckOutput::ClippyWarning);
clippy_entries.extend(server_clippy_entries);
} }
// if we are in --fix mode, don't change the log files, terminate here // if we are in --fix mode, don't change the log files, terminate here
@ -666,20 +700,21 @@ fn main() {
return; return;
} }
// split up warnings and ices
let mut warnings: Vec<ClippyWarning> = vec![];
let mut raw_ices: Vec<RustcIce> = vec![];
for entry in clippy_entries {
if let ClippyCheckOutput::ClippyWarning(x) = entry {
warnings.push(x);
} else if let ClippyCheckOutput::RustcIce(x) = entry {
raw_ices.push(x);
}
}
// generate some stats // generate some stats
let (stats_formatted, new_stats) = gather_stats(&clippy_warnings); let (stats_formatted, new_stats) = gather_stats(&warnings);
// grab crashes/ICEs, save the crate name and the ice message let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect();
let ices: Vec<(&String, &String)> = clippy_warnings
.iter()
.filter(|warning| warning.is_ice)
.map(|w| (&w.crate_name, &w.message))
.collect();
let mut all_msgs: Vec<String> = clippy_warnings
.iter()
.map(|warn| warn.to_output(config.markdown))
.collect();
all_msgs.sort(); all_msgs.sort();
all_msgs.push("\n\n### Stats:\n\n".into()); all_msgs.push("\n\n### Stats:\n\n".into());
all_msgs.push(stats_formatted); all_msgs.push(stats_formatted);
@ -693,11 +728,18 @@ fn main() {
} }
write!(text, "{}", all_msgs.join("")).unwrap(); write!(text, "{}", all_msgs.join("")).unwrap();
text.push_str("\n\n### ICEs:\n"); text.push_str("\n\n### ICEs:\n");
for (cratename, msg) in &ices { for ice in &raw_ices {
let _: fmt::Result = write!(text, "{cratename}: '{msg}'"); let _: fmt::Result = write!(
text,
"{}:\n{}\n========================================\n\n",
ice.crate_name, ice.ice_content
);
} }
println!("Writing logs to {}", config.lintcheck_results_path.display()); println!("Writing logs to {}", config.lintcheck_results_path.display());
if !raw_ices.is_empty() {
println!("WARNING: at least one ICE reported, check log file");
}
fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap(); fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
fs::write(&config.lintcheck_results_path, text).unwrap(); fs::write(&config.lintcheck_results_path, text).unwrap();

View File

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2024-04-04" channel = "nightly-2024-04-05"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View File

@ -5,7 +5,6 @@
//@normalize-stderr-test: "'rustc'" -> "'<unnamed>'" //@normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
//@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc <version> running on <target>" //@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc <version> running on <target>"
//@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
//@normalize-stderr-test: "this compiler `.*` is outdated" -> "this compiler <version> is outdated"
#![deny(clippy::internal)] #![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)] #![allow(clippy::missing_clippy_version_attribute)]

View File

@ -4,10 +4,9 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: the compiler unexpectedly panicked. this is a bug. error: the compiler unexpectedly panicked. this is a bug.
note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the meantime note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
|
= note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists note: please make sure that you have updated to the latest nightly
= note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
note: rustc <version> running on <target> note: rustc <version> running on <target>

View File

@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
error: hardcoded path to a diagnostic item error: hardcoded path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:43 --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:43
| |
LL | const OPS_MOD: [&str; 5] = ["core", "ops"]; LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: convert all references to use `sym::deref_method` = help: convert all references to use `sym::deref_method`

View File

@ -0,0 +1 @@
allowed-prefixes = ["bar"]

View File

@ -0,0 +1,15 @@
#![warn(clippy::module_name_repetitions)]
#![allow(dead_code)]
mod foo {
// #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
// In this test, allowed prefixes are configured to be ["bar"].
// this line should produce a warning:
pub fn to_foo() {}
// but this line shouldn't
pub fn bar_foo() {}
}
fn main() {}

View File

@ -0,0 +1,11 @@
error: item name ends with its containing module's name
--> tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs:9:12
|
LL | pub fn to_foo() {}
| ^^^^^^
|
= note: `-D clippy::module-name-repetitions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
error: aborting due to 1 previous error

View File

@ -0,0 +1 @@
allowed-prefixes = ["..", "bar"]

View File

@ -0,0 +1,21 @@
#![warn(clippy::module_name_repetitions)]
#![allow(dead_code)]
mod foo {
// #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
// In this test, allowed prefixes are configured to be all of the default prefixes and ["bar"].
// this line should produce a warning:
pub fn something_foo() {}
// but none of the following should:
pub fn bar_foo() {}
pub fn to_foo() {}
pub fn as_foo() {}
pub fn into_foo() {}
pub fn from_foo() {}
pub fn try_into_foo() {}
pub fn try_from_foo() {}
}
fn main() {}

View File

@ -0,0 +1,11 @@
error: item name ends with its containing module's name
--> tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs:9:12
|
LL | pub fn something_foo() {}
| ^^^^^^^^^^^^^
|
= note: `-D clippy::module-name-repetitions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
error: aborting due to 1 previous error

View File

@ -14,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
allowed-dotfiles allowed-dotfiles
allowed-duplicate-crates allowed-duplicate-crates
allowed-idents-below-min-chars allowed-idents-below-min-chars
allowed-prefixes
allowed-scripts allowed-scripts
allowed-wildcard-imports allowed-wildcard-imports
arithmetic-side-effects-allowed arithmetic-side-effects-allowed
@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
allowed-dotfiles allowed-dotfiles
allowed-duplicate-crates allowed-duplicate-crates
allowed-idents-below-min-chars allowed-idents-below-min-chars
allowed-prefixes
allowed-scripts allowed-scripts
allowed-wildcard-imports allowed-wildcard-imports
arithmetic-side-effects-allowed arithmetic-side-effects-allowed
@ -172,6 +174,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
allowed-dotfiles allowed-dotfiles
allowed-duplicate-crates allowed-duplicate-crates
allowed-idents-below-min-chars allowed-idents-below-min-chars
allowed-prefixes
allowed-scripts allowed-scripts
allowed-wildcard-imports allowed-wildcard-imports
arithmetic-side-effects-allowed arithmetic-side-effects-allowed

View File

@ -33,16 +33,9 @@ fn main() {
let _ = Arc::new(42); let _ = Arc::new(42);
let _ = Arc::new(RefCell::new(42)); let _ = Arc::new(RefCell::new(42));
//~^ ERROR: usage of an `Arc` that is not `Send` and `Sync`
//~| NOTE: the trait `Sync` is not implemented for `RefCell<i32>`
let mutex = Mutex::new(1); let mutex = Mutex::new(1);
let _ = Arc::new(mutex.lock().unwrap()); let _ = Arc::new(mutex.lock().unwrap());
//~^ ERROR: usage of an `Arc` that is not `Send` and `Sync`
//~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>`
let _ = Arc::new(&42 as *const i32); let _ = Arc::new(&42 as *const i32);
//~^ ERROR: usage of an `Arc` that is not `Send` and `Sync`
//~| NOTE: the trait `Send` is not implemented for `*const i32`
//~| NOTE: the trait `Sync` is not implemented for `*const i32`
} }

View File

@ -4,38 +4,31 @@ error: usage of an `Arc` that is not `Send` and `Sync`
LL | let _ = Arc::new(RefCell::new(42)); LL | let _ = Arc::new(RefCell::new(42));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: `Arc<RefCell<i32>>` is not `Send` and `Sync` as: = note: `Arc<RefCell<i32>>` is not `Send` and `Sync` as `RefCell<i32>` is not `Sync`
= note: - the trait `Sync` is not implemented for `RefCell<i32>` = help: if the `Arc` will not used be across threads replace it with an `Rc`
= help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types = help: otherwise make `RefCell<i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex`
= note: if you intend to use `Arc` with `Send` and `Sync` traits
= note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `RefCell<i32>`
= note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]` = help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]`
error: usage of an `Arc` that is not `Send` and `Sync` error: usage of an `Arc` that is not `Send` and `Sync`
--> tests/ui/arc_with_non_send_sync.rs:40:13 --> tests/ui/arc_with_non_send_sync.rs:38:13
| |
LL | let _ = Arc::new(mutex.lock().unwrap()); LL | let _ = Arc::new(mutex.lock().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: `Arc<MutexGuard<'_, i32>>` is not `Send` and `Sync` as: = note: `Arc<MutexGuard<'_, i32>>` is not `Send` and `Sync` as `MutexGuard<'_, i32>` is not `Send`
= note: - the trait `Send` is not implemented for `MutexGuard<'_, i32>` = help: if the `Arc` will not used be across threads replace it with an `Rc`
= help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types = help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex`
= note: if you intend to use `Arc` with `Send` and `Sync` traits
= note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `MutexGuard<'_, i32>`
error: usage of an `Arc` that is not `Send` and `Sync` error: usage of an `Arc` that is not `Send` and `Sync`
--> tests/ui/arc_with_non_send_sync.rs:44:13 --> tests/ui/arc_with_non_send_sync.rs:40:13
| |
LL | let _ = Arc::new(&42 as *const i32); LL | let _ = Arc::new(&42 as *const i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: `Arc<*const i32>` is not `Send` and `Sync` as: = note: `Arc<*const i32>` is not `Send` and `Sync` as `*const i32` is neither `Send` nor `Sync`
= note: - the trait `Send` is not implemented for `*const i32` = help: if the `Arc` will not used be across threads replace it with an `Rc`
= note: - the trait `Sync` is not implemented for `*const i32` = help: otherwise make `*const i32` `Send` and `Sync` or consider a wrapper type such as `Mutex`
= help: consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types
= note: if you intend to use `Arc` with `Send` and `Sync` traits
= note: wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `*const i32`
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View File

@ -176,3 +176,17 @@ pub fn with_empty_docs(_attr: TokenStream, input: TokenStream) -> TokenStream {
} }
.into() .into()
} }
#[proc_macro_attribute]
pub fn duplicated_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
let item = parse_macro_input!(input as syn::Item);
let attrs: Vec<syn::Attribute> = vec![];
quote! {
#(#attrs)*
#[allow(unused)]
#[allow(unused)]
#[allow(unused)]
#item
}
.into()
}

View File

@ -463,6 +463,18 @@ fn issue11642() {
} }
} }
fn issue11738() {
macro_rules! m {
() => {
let _ = i32::MIN as u32; // cast_sign_loss
let _ = u32::MAX as u8; // cast_possible_truncation
let _ = std::f64::consts::PI as f32; // cast_possible_truncation
let _ = 0i8 as i32; // cast_lossless
};
}
m!();
}
fn issue12506() -> usize { fn issue12506() -> usize {
let bar: Result<Option<i64>, u32> = Ok(Some(10)); let bar: Result<Option<i64>, u32> = Ok(Some(10));
bar.unwrap().unwrap() as usize bar.unwrap().unwrap() as usize

View File

@ -650,8 +650,47 @@ error: casting `i32` to `u32` may lose the sign of the value
LL | (a.abs() * b.pow(2) / c.abs()) as u32 LL | (a.abs() * b.pow(2) / c.abs()) as u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:469:21
|
LL | let _ = i32::MIN as u32; // cast_sign_loss
| ^^^^^^^^^^^^^^^
...
LL | m!();
| ---- in this macro invocation
|
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: casting `u32` to `u8` may truncate the value
--> tests/ui/cast.rs:470:21
|
LL | let _ = u32::MAX as u8; // cast_possible_truncation
| ^^^^^^^^^^^^^^
...
LL | m!();
| ---- in this macro invocation
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
help: ... or use `try_from` and handle the error accordingly
|
LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation
| ~~~~~~~~~~~~~~~~~~~~~~
error: casting `f64` to `f32` may truncate the value
--> tests/ui/cast.rs:471:21
|
LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | m!();
| ---- in this macro invocation
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:468:5 --> tests/ui/cast.rs:480:5
| |
LL | bar.unwrap().unwrap() as usize LL | bar.unwrap().unwrap() as usize
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -663,10 +702,10 @@ LL | usize::try_from(bar.unwrap().unwrap())
| |
error: casting `i64` to `usize` may lose the sign of the value error: casting `i64` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:468:5 --> tests/ui/cast.rs:480:5
| |
LL | bar.unwrap().unwrap() as usize LL | bar.unwrap().unwrap() as usize
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 87 previous errors error: aborting due to 90 previous errors

View File

@ -0,0 +1,26 @@
#![allow(clippy::unit_arg)]
struct One {
x: i32,
}
struct Two {
x: i32,
}
struct Product {}
impl Product {
pub fn a_method(self, _: ()) {}
}
fn from_array(_: [i32; 2]) -> Product {
todo!()
}
pub fn main() {
let one = One { x: 1 };
let two = Two { x: 2 };
let product = from_array([one.x, two.x]);
product.a_method(<()>::default());
}

View File

@ -7,13 +7,5 @@ LL | s() as *const ();
= note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
error: `as` casting between raw pointers without changing its mutability error: aborting due to 1 previous error
--> tests/ui/crashes/ice-12616.rs:6:5
|
LL | s() as *const ();
| ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()`
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 2 previous errors

View File

@ -1,7 +1,6 @@
#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)] #![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
#![warn(clippy::expl_impl_clone_on_copy)] #![warn(clippy::expl_impl_clone_on_copy)]
#[derive(Copy)] #[derive(Copy)]
struct Qux; struct Qux;

View File

@ -1,5 +1,5 @@
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:8:1 --> tests/ui/derive.rs:7:1
| |
LL | / impl Clone for Qux { LL | / impl Clone for Qux {
LL | | LL | |
@ -10,7 +10,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:8:1 --> tests/ui/derive.rs:7:1
| |
LL | / impl Clone for Qux { LL | / impl Clone for Qux {
LL | | LL | |
@ -23,7 +23,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]` = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:33:1 --> tests/ui/derive.rs:32:1
| |
LL | / impl<'a> Clone for Lt<'a> { LL | / impl<'a> Clone for Lt<'a> {
LL | | LL | |
@ -34,7 +34,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:33:1 --> tests/ui/derive.rs:32:1
| |
LL | / impl<'a> Clone for Lt<'a> { LL | / impl<'a> Clone for Lt<'a> {
LL | | LL | |
@ -45,7 +45,7 @@ LL | | }
| |_^ | |_^
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:45:1 --> tests/ui/derive.rs:44:1
| |
LL | / impl Clone for BigArray { LL | / impl Clone for BigArray {
LL | | LL | |
@ -56,7 +56,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:45:1 --> tests/ui/derive.rs:44:1
| |
LL | / impl Clone for BigArray { LL | / impl Clone for BigArray {
LL | | LL | |
@ -67,7 +67,7 @@ LL | | }
| |_^ | |_^
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:57:1 --> tests/ui/derive.rs:56:1
| |
LL | / impl Clone for FnPtr { LL | / impl Clone for FnPtr {
LL | | LL | |
@ -78,7 +78,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:57:1 --> tests/ui/derive.rs:56:1
| |
LL | / impl Clone for FnPtr { LL | / impl Clone for FnPtr {
LL | | LL | |
@ -89,7 +89,7 @@ LL | | }
| |_^ | |_^
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:78:1 --> tests/ui/derive.rs:77:1
| |
LL | / impl<T: Clone> Clone for Generic2<T> { LL | / impl<T: Clone> Clone for Generic2<T> {
LL | | LL | |
@ -100,7 +100,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:78:1 --> tests/ui/derive.rs:77:1
| |
LL | / impl<T: Clone> Clone for Generic2<T> { LL | / impl<T: Clone> Clone for Generic2<T> {
LL | | LL | |

View File

@ -235,3 +235,8 @@ fn parenthesized_word() {}
/// OSes /// OSes
/// UXes /// UXes
fn plural_acronym_test() {} fn plural_acronym_test() {}
extern {
/// `foo()`
fn in_extern();
}

View File

@ -235,3 +235,8 @@ fn parenthesized_word() {}
/// OSes /// OSes
/// UXes /// UXes
fn plural_acronym_test() {} fn plural_acronym_test() {}
extern {
/// foo()
fn in_extern();
}

View File

@ -352,5 +352,16 @@ help: try
LL | /// `ABes` LL | /// `ABes`
| ~~~~~~ | ~~~~~~
error: aborting due to 32 previous errors error: item in documentation is missing backticks
--> tests/ui/doc/doc-fixable.rs:240:9
|
LL | /// foo()
| ^^^^^
|
help: try
|
LL | /// `foo()`
| ~~~~~~~
error: aborting due to 33 previous errors

View File

@ -1,9 +1,14 @@
//@aux-build:proc_macro_attr.rs
#![warn(clippy::duplicated_attributes)] #![warn(clippy::duplicated_attributes)]
#![cfg(any(unix, windows))] #![cfg(any(unix, windows))]
#![allow(dead_code)] #![allow(dead_code)]
#![allow(dead_code)] //~ ERROR: duplicated attribute #![allow(dead_code)] //~ ERROR: duplicated attribute
#![cfg(any(unix, windows))] // Should not warn! #![cfg(any(unix, windows))] // Should not warn!
#[macro_use]
extern crate proc_macro_attr;
#[cfg(any(unix, windows, target_os = "linux"))] #[cfg(any(unix, windows, target_os = "linux"))]
#[allow(dead_code)] #[allow(dead_code)]
#[allow(dead_code)] //~ ERROR: duplicated attribute #[allow(dead_code)] //~ ERROR: duplicated attribute
@ -12,7 +17,10 @@ fn foo() {}
#[cfg(unix)] #[cfg(unix)]
#[cfg(windows)] #[cfg(windows)]
#[cfg(unix)] //~ ERROR: duplicated attribute #[cfg(unix)] // cfgs are not handled
fn bar() {} fn bar() {}
#[proc_macro_attr::duplicated_attr()] // Should not warn!
fn babar() {}
fn main() {} fn main() {}

View File

@ -1,16 +1,16 @@
error: duplicated attribute error: duplicated attribute
--> tests/ui/duplicated_attributes.rs:4:10 --> tests/ui/duplicated_attributes.rs:6:10
| |
LL | #![allow(dead_code)] LL | #![allow(dead_code)]
| ^^^^^^^^^ | ^^^^^^^^^
| |
note: first defined here note: first defined here
--> tests/ui/duplicated_attributes.rs:3:10 --> tests/ui/duplicated_attributes.rs:5:10
| |
LL | #![allow(dead_code)] LL | #![allow(dead_code)]
| ^^^^^^^^^ | ^^^^^^^^^
help: remove this attribute help: remove this attribute
--> tests/ui/duplicated_attributes.rs:4:10 --> tests/ui/duplicated_attributes.rs:6:10
| |
LL | #![allow(dead_code)] LL | #![allow(dead_code)]
| ^^^^^^^^^ | ^^^^^^^^^
@ -18,38 +18,21 @@ LL | #![allow(dead_code)]
= help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]`
error: duplicated attribute error: duplicated attribute
--> tests/ui/duplicated_attributes.rs:9:9 --> tests/ui/duplicated_attributes.rs:14:9
| |
LL | #[allow(dead_code)] LL | #[allow(dead_code)]
| ^^^^^^^^^ | ^^^^^^^^^
| |
note: first defined here note: first defined here
--> tests/ui/duplicated_attributes.rs:8:9 --> tests/ui/duplicated_attributes.rs:13:9
| |
LL | #[allow(dead_code)] LL | #[allow(dead_code)]
| ^^^^^^^^^ | ^^^^^^^^^
help: remove this attribute help: remove this attribute
--> tests/ui/duplicated_attributes.rs:9:9 --> tests/ui/duplicated_attributes.rs:14:9
| |
LL | #[allow(dead_code)] LL | #[allow(dead_code)]
| ^^^^^^^^^ | ^^^^^^^^^
error: duplicated attribute error: aborting due to 2 previous errors
--> tests/ui/duplicated_attributes.rs:15:7
|
LL | #[cfg(unix)]
| ^^^^
|
note: first defined here
--> tests/ui/duplicated_attributes.rs:13:7
|
LL | #[cfg(unix)]
| ^^^^
help: remove this attribute
--> tests/ui/duplicated_attributes.rs:15:7
|
LL | #[cfg(unix)]
| ^^^^
error: aborting due to 3 previous errors

View File

@ -16,6 +16,16 @@ fn main() {
let x: Option<Vec<String>> = None; let x: Option<Vec<String>> = None;
x.unwrap_or_default(); x.unwrap_or_default();
// Issue #12564
// No error as &Vec<_> doesn't implement std::default::Default
let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]);
let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] };
// Same code as above written using match.
let x: &[_] = match map.get(&0) {
Some(x) => x,
None => &[],
};
} }
// Issue #12531 // Issue #12531

View File

@ -37,6 +37,16 @@ fn main() {
} else { } else {
Vec::default() Vec::default()
}; };
// Issue #12564
// No error as &Vec<_> doesn't implement std::default::Default
let mut map = std::collections::HashMap::from([(0, vec![0; 3]), (1, vec![1; 3]), (2, vec![2])]);
let x: &[_] = if let Some(x) = map.get(&0) { x } else { &[] };
// Same code as above written using match.
let x: &[_] = match map.get(&0) {
Some(x) => x,
None => &[],
};
} }
// Issue #12531 // Issue #12531

View File

@ -53,7 +53,7 @@ LL | | };
| |_____^ help: replace it with: `x.unwrap_or_default()` | |_____^ help: replace it with: `x.unwrap_or_default()`
error: match can be simplified with `.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()`
--> tests/ui/manual_unwrap_or_default.rs:46:20 --> tests/ui/manual_unwrap_or_default.rs:56:20
| |
LL | Some(_) => match *b { LL | Some(_) => match *b {
| ____________________^ | ____________________^

View File

@ -19,6 +19,20 @@ mod foo {
// Should not warn // Should not warn
pub struct Foobar; pub struct Foobar;
// #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name.
pub fn to_foo() {}
pub fn into_foo() {}
pub fn as_foo() {}
pub fn from_foo() {}
pub fn try_into_foo() {}
pub fn try_from_foo() {}
pub trait IntoFoo {}
pub trait ToFoo {}
pub trait AsFoo {}
pub trait FromFoo {}
pub trait TryIntoFoo {}
pub trait TryFromFoo {}
} }
fn main() {} fn main() {}

View File

@ -1,3 +1,4 @@
//@needs-asm-support
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
#![allow(unused)] #![allow(unused)]
#![allow(deref_nullptr)] #![allow(deref_nullptr)]

View File

@ -1,5 +1,5 @@
error: this `unsafe` block contains 2 unsafe operations, expected only one error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:36:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:37:5
| |
LL | / unsafe { LL | / unsafe {
LL | | STATIC += 1; LL | | STATIC += 1;
@ -8,12 +8,12 @@ LL | | }
| |_____^ | |_____^
| |
note: modification of a mutable static occurs here note: modification of a mutable static occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:37:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:38:9
| |
LL | STATIC += 1; LL | STATIC += 1;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:38:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:39:9
| |
LL | not_very_safe(); LL | not_very_safe();
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -21,7 +21,7 @@ LL | not_very_safe();
= help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]`
error: this `unsafe` block contains 2 unsafe operations, expected only one error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:45:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:46:5
| |
LL | / unsafe { LL | / unsafe {
LL | | drop(u.u); LL | | drop(u.u);
@ -30,18 +30,18 @@ LL | | }
| |_____^ | |_____^
| |
note: union field access occurs here note: union field access occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:46:14 --> tests/ui/multiple_unsafe_ops_per_block.rs:47:14
| |
LL | drop(u.u); LL | drop(u.u);
| ^^^ | ^^^
note: raw pointer dereference occurs here note: raw pointer dereference occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:47:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:48:9
| |
LL | *raw_ptr(); LL | *raw_ptr();
| ^^^^^^^^^^ | ^^^^^^^^^^
error: this `unsafe` block contains 3 unsafe operations, expected only one error: this `unsafe` block contains 3 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:52:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:53:5
| |
LL | / unsafe { LL | / unsafe {
LL | | asm!("nop"); LL | | asm!("nop");
@ -51,23 +51,23 @@ LL | | }
| |_____^ | |_____^
| |
note: inline assembly used here note: inline assembly used here
--> tests/ui/multiple_unsafe_ops_per_block.rs:53:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:54:9
| |
LL | asm!("nop"); LL | asm!("nop");
| ^^^^^^^^^^^ | ^^^^^^^^^^^
note: unsafe method call occurs here note: unsafe method call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:54:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9
| |
LL | sample.not_very_safe(); LL | sample.not_very_safe();
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
note: modification of a mutable static occurs here note: modification of a mutable static occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:56:9
| |
LL | STATIC = 0; LL | STATIC = 0;
| ^^^^^^^^^^ | ^^^^^^^^^^
error: this `unsafe` block contains 6 unsafe operations, expected only one error: this `unsafe` block contains 6 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:61:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:62:5
| |
LL | / unsafe { LL | / unsafe {
LL | | drop(u.u); LL | | drop(u.u);
@ -79,55 +79,55 @@ LL | | }
| |_____^ | |_____^
| |
note: union field access occurs here note: union field access occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:62:14 --> tests/ui/multiple_unsafe_ops_per_block.rs:63:14
| |
LL | drop(u.u); LL | drop(u.u);
| ^^^ | ^^^
note: access of a mutable static occurs here note: access of a mutable static occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:63:14 --> tests/ui/multiple_unsafe_ops_per_block.rs:64:14
| |
LL | drop(STATIC); LL | drop(STATIC);
| ^^^^^^ | ^^^^^^
note: unsafe method call occurs here note: unsafe method call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:64:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:65:9
| |
LL | sample.not_very_safe(); LL | sample.not_very_safe();
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:65:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9
| |
LL | not_very_safe(); LL | not_very_safe();
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
note: raw pointer dereference occurs here note: raw pointer dereference occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9
| |
LL | *raw_ptr(); LL | *raw_ptr();
| ^^^^^^^^^^ | ^^^^^^^^^^
note: inline assembly used here note: inline assembly used here
--> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:68:9
| |
LL | asm!("nop"); LL | asm!("nop");
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:105:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:106:5
| |
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:105:14 --> tests/ui/multiple_unsafe_ops_per_block.rs:106:14
| |
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: raw pointer dereference occurs here note: raw pointer dereference occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:105:39 --> tests/ui/multiple_unsafe_ops_per_block.rs:106:39
| |
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:123:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:124:5
| |
LL | / unsafe { LL | / unsafe {
LL | | x(); LL | | x();
@ -136,18 +136,18 @@ LL | | }
| |_____^ | |_____^
| |
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:124:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:125:9
| |
LL | x(); LL | x();
| ^^^ | ^^^
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:125:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:126:9
| |
LL | x(); LL | x();
| ^^^ | ^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:134:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:135:9
| |
LL | / unsafe { LL | / unsafe {
LL | | T::X(); LL | | T::X();
@ -156,18 +156,18 @@ LL | | }
| |_________^ | |_________^
| |
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:135:13 --> tests/ui/multiple_unsafe_ops_per_block.rs:136:13
| |
LL | T::X(); LL | T::X();
| ^^^^^^ | ^^^^^^
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:136:13 --> tests/ui/multiple_unsafe_ops_per_block.rs:137:13
| |
LL | T::X(); LL | T::X();
| ^^^^^^ | ^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:144:5 --> tests/ui/multiple_unsafe_ops_per_block.rs:145:5
| |
LL | / unsafe { LL | / unsafe {
LL | | x.0(); LL | | x.0();
@ -176,12 +176,12 @@ LL | | }
| |_____^ | |_____^
| |
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:145:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:146:9
| |
LL | x.0(); LL | x.0();
| ^^^^^ | ^^^^^
note: unsafe function call occurs here note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:146:9 --> tests/ui/multiple_unsafe_ops_per_block.rs:147:9
| |
LL | x.0(); LL | x.0();
| ^^^^^ | ^^^^^

View File

@ -251,3 +251,11 @@ mod issue_10253 {
(&S).f::<()>(); (&S).f::<()>();
} }
} }
fn issue_12268() {
let option = Some((&1,));
let x = (&1,);
option.unwrap_or((x.0,));
//~^ ERROR: this expression creates a reference which is immediately dereferenced by the
// compiler
}

View File

@ -251,3 +251,11 @@ mod issue_10253 {
(&S).f::<()>(); (&S).f::<()>();
} }
} }
fn issue_12268() {
let option = Some((&1,));
let x = (&1,);
option.unwrap_or((&x.0,));
//~^ ERROR: this expression creates a reference which is immediately dereferenced by the
// compiler
}

View File

@ -163,5 +163,11 @@ error: this expression borrows a value the compiler would automatically borrow
LL | let _ = &mut (&mut { x.u }).x; LL | let _ = &mut (&mut { x.u }).x;
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
error: aborting due to 27 previous errors error: this expression creates a reference which is immediately dereferenced by the compiler
--> tests/ui/needless_borrow.rs:258:23
|
LL | option.unwrap_or((&x.0,));
| ^^^^ help: change this to: `x.0`
error: aborting due to 28 previous errors

View File

@ -10,7 +10,7 @@
/// unimplemented!(); /// unimplemented!();
/// } /// }
/// ``` /// ```
/// ///
/// With an explicit return type it should lint too /// With an explicit return type it should lint too
/// ```edition2015 /// ```edition2015
/// fn main() -> () { /// fn main() -> () {
@ -18,7 +18,7 @@
/// unimplemented!(); /// unimplemented!();
/// } /// }
/// ``` /// ```
/// ///
/// This should, too. /// This should, too.
/// ```rust /// ```rust
/// fn main() { /// fn main() {
@ -26,7 +26,7 @@
/// unimplemented!(); /// unimplemented!();
/// } /// }
/// ``` /// ```
/// ///
/// This one too. /// This one too.
/// ```no_run /// ```no_run
/// // the fn is not always the first line /// // the fn is not always the first line

View File

@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() {
let _ = !(a >= b); let _ = !(a >= b);
} }
fn issue_12625() {
let a = 0;
let b = 0;
if (a as u64) < b {} //~ ERROR: this boolean expression can be simplified
if (a as u64) < b {} //~ ERROR: this boolean expression can be simplified
if a as u64 > b {} //~ ERROR: this boolean expression can be simplified
}
fn main() {} fn main() {}

View File

@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() {
let _ = !(a >= b); let _ = !(a >= b);
} }
fn issue_12625() {
let a = 0;
let b = 0;
if !(a as u64 >= b) {} //~ ERROR: this boolean expression can be simplified
if !((a as u64) >= b) {} //~ ERROR: this boolean expression can be simplified
if !(a as u64 <= b) {} //~ ERROR: this boolean expression can be simplified
}
fn main() {} fn main() {}

View File

@ -79,5 +79,23 @@ error: this boolean expression can be simplified
LL | if !res.is_none() {} LL | if !res.is_none() {}
| ^^^^^^^^^^^^^^ help: try: `res.is_some()` | ^^^^^^^^^^^^^^ help: try: `res.is_some()`
error: aborting due to 13 previous errors error: this boolean expression can be simplified
--> tests/ui/nonminimal_bool_methods.rs:115:8
|
LL | if !(a as u64 >= b) {}
| ^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b`
error: this boolean expression can be simplified
--> tests/ui/nonminimal_bool_methods.rs:116:8
|
LL | if !((a as u64) >= b) {}
| ^^^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b`
error: this boolean expression can be simplified
--> tests/ui/nonminimal_bool_methods.rs:117:8
|
LL | if !(a as u64 <= b) {}
| ^^^^^^^^^^^^^^^^ help: try: `a as u64 > b`
error: aborting due to 16 previous errors

View File

@ -1,5 +1,4 @@
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
//@compile-flags: -Zdeduplicate-diagnostics=yes
#![warn(clippy::ptr_as_ptr)] #![warn(clippy::ptr_as_ptr)]

View File

@ -1,5 +1,4 @@
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
//@compile-flags: -Zdeduplicate-diagnostics=yes
#![warn(clippy::ptr_as_ptr)] #![warn(clippy::ptr_as_ptr)]

View File

@ -1,5 +1,5 @@
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:19:33 --> tests/ui/ptr_as_ptr.rs:18:33
| |
LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) } LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()`
@ -8,37 +8,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i
= help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:28:13 --> tests/ui/ptr_as_ptr.rs:27:13
| |
LL | let _ = ptr as *const i32; LL | let _ = ptr as *const i32;
| ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()` | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:29:13 --> tests/ui/ptr_as_ptr.rs:28:13
| |
LL | let _ = mut_ptr as *mut i32; LL | let _ = mut_ptr as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:34:17 --> tests/ui/ptr_as_ptr.rs:33:17
| |
LL | let _ = *ptr_ptr as *const i32; LL | let _ = *ptr_ptr as *const i32;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()` | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:47:25 --> tests/ui/ptr_as_ptr.rs:46:25
| |
LL | let _: *const i32 = ptr as *const _; LL | let _: *const i32 = ptr as *const _;
| ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:48:23 --> tests/ui/ptr_as_ptr.rs:47:23
| |
LL | let _: *mut i32 = mut_ptr as _; LL | let _: *mut i32 = mut_ptr as _;
| ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:51:21 --> tests/ui/ptr_as_ptr.rs:50:21
| |
LL | let _ = inline!($ptr as *const i32); LL | let _ = inline!($ptr as *const i32);
| ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()` | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
@ -46,157 +46,157 @@ LL | let _ = inline!($ptr as *const i32);
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:72:13 --> tests/ui/ptr_as_ptr.rs:71:13
| |
LL | let _ = ptr as *const i32; LL | let _ = ptr as *const i32;
| ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()` | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:73:13 --> tests/ui/ptr_as_ptr.rs:72:13
| |
LL | let _ = mut_ptr as *mut i32; LL | let _ = mut_ptr as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:80:9 --> tests/ui/ptr_as_ptr.rs:79:9
| |
LL | ptr::null_mut() as *mut u32 LL | ptr::null_mut() as *mut u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:84:9 --> tests/ui/ptr_as_ptr.rs:83:9
| |
LL | std::ptr::null_mut() as *mut u32 LL | std::ptr::null_mut() as *mut u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:89:9 --> tests/ui/ptr_as_ptr.rs:88:9
| |
LL | ptr::null_mut() as *mut u32 LL | ptr::null_mut() as *mut u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:93:9 --> tests/ui/ptr_as_ptr.rs:92:9
| |
LL | core::ptr::null_mut() as *mut u32 LL | core::ptr::null_mut() as *mut u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:98:9 --> tests/ui/ptr_as_ptr.rs:97:9
| |
LL | ptr::null() as *const u32 LL | ptr::null() as *const u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:102:9 --> tests/ui/ptr_as_ptr.rs:101:9
| |
LL | std::ptr::null() as *const u32 LL | std::ptr::null() as *const u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:107:9 --> tests/ui/ptr_as_ptr.rs:106:9
| |
LL | ptr::null() as *const u32 LL | ptr::null() as *const u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:111:9 --> tests/ui/ptr_as_ptr.rs:110:9
| |
LL | core::ptr::null() as *const u32 LL | core::ptr::null() as *const u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:118:9 --> tests/ui/ptr_as_ptr.rs:117:9
| |
LL | ptr::null_mut() as *mut _ LL | ptr::null_mut() as *mut _
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:122:9 --> tests/ui/ptr_as_ptr.rs:121:9
| |
LL | std::ptr::null_mut() as *mut _ LL | std::ptr::null_mut() as *mut _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:127:9 --> tests/ui/ptr_as_ptr.rs:126:9
| |
LL | ptr::null_mut() as *mut _ LL | ptr::null_mut() as *mut _
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:131:9 --> tests/ui/ptr_as_ptr.rs:130:9
| |
LL | core::ptr::null_mut() as *mut _ LL | core::ptr::null_mut() as *mut _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:136:9 --> tests/ui/ptr_as_ptr.rs:135:9
| |
LL | ptr::null() as *const _ LL | ptr::null() as *const _
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:140:9 --> tests/ui/ptr_as_ptr.rs:139:9
| |
LL | std::ptr::null() as *const _ LL | std::ptr::null() as *const _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:145:9 --> tests/ui/ptr_as_ptr.rs:144:9
| |
LL | ptr::null() as *const _ LL | ptr::null() as *const _
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:149:9 --> tests/ui/ptr_as_ptr.rs:148:9
| |
LL | core::ptr::null() as *const _ LL | core::ptr::null() as *const _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:156:9 --> tests/ui/ptr_as_ptr.rs:155:9
| |
LL | ptr::null_mut() as _ LL | ptr::null_mut() as _
| ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:160:9 --> tests/ui/ptr_as_ptr.rs:159:9
| |
LL | std::ptr::null_mut() as _ LL | std::ptr::null_mut() as _
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:165:9 --> tests/ui/ptr_as_ptr.rs:164:9
| |
LL | ptr::null_mut() as _ LL | ptr::null_mut() as _
| ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:169:9 --> tests/ui/ptr_as_ptr.rs:168:9
| |
LL | core::ptr::null_mut() as _ LL | core::ptr::null_mut() as _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:174:9 --> tests/ui/ptr_as_ptr.rs:173:9
| |
LL | ptr::null() as _ LL | ptr::null() as _
| ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:178:9 --> tests/ui/ptr_as_ptr.rs:177:9
| |
LL | std::ptr::null() as _ LL | std::ptr::null() as _
| ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:183:9 --> tests/ui/ptr_as_ptr.rs:182:9
| |
LL | ptr::null() as _ LL | ptr::null() as _
| ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
error: `as` casting between raw pointers without changing its mutability error: `as` casting between raw pointers without changing its mutability
--> tests/ui/ptr_as_ptr.rs:187:9 --> tests/ui/ptr_as_ptr.rs:186:9
| |
LL | core::ptr::null() as _ LL | core::ptr::null() as _
| ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`

View File

@ -213,3 +213,53 @@ mod issue7392 {
let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); let _ = !v.iter().any(|fp| test_u32_2(*fp.field));
} }
} }
mod issue_11910 {
fn computations() -> u32 {
0
}
struct Foo;
impl Foo {
fn bar(&self, _: bool) {}
}
fn test_normal_for_iter() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
let _ = !v.iter().any(|x| *x == 42);
Foo.bar(!v.iter().any(|x| *x == 42));
}
fn test_then_for_iter() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
(!v.iter().any(|x| *x == 42)).then(computations);
}
fn test_then_some_for_iter() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
(!v.iter().any(|x| *x == 42)).then_some(0);
}
fn test_normal_for_str() {
let s = "hello";
let _ = !s.contains("world");
Foo.bar(!s.contains("world"));
let s = String::from("hello");
let _ = !s.contains("world");
Foo.bar(!s.contains("world"));
}
fn test_then_for_str() {
let s = "hello";
let _ = (!s.contains("world")).then(computations);
let s = String::from("hello");
let _ = (!s.contains("world")).then(computations);
}
fn test_then_some_for_str() {
let s = "hello";
let _ = (!s.contains("world")).then_some(0);
let s = String::from("hello");
let _ = (!s.contains("world")).then_some(0);
}
}

View File

@ -219,3 +219,53 @@ mod issue7392 {
let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
} }
} }
mod issue_11910 {
fn computations() -> u32 {
0
}
struct Foo;
impl Foo {
fn bar(&self, _: bool) {}
}
fn test_normal_for_iter() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
let _ = v.iter().find(|x| **x == 42).is_none();
Foo.bar(v.iter().find(|x| **x == 42).is_none());
}
fn test_then_for_iter() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
v.iter().find(|x| **x == 42).is_none().then(computations);
}
fn test_then_some_for_iter() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
v.iter().find(|x| **x == 42).is_none().then_some(0);
}
fn test_normal_for_str() {
let s = "hello";
let _ = s.find("world").is_none();
Foo.bar(s.find("world").is_none());
let s = String::from("hello");
let _ = s.find("world").is_none();
Foo.bar(s.find("world").is_none());
}
fn test_then_for_str() {
let s = "hello";
let _ = s.find("world").is_none().then(computations);
let s = String::from("hello");
let _ = s.find("world").is_none().then(computations);
}
fn test_then_some_for_str() {
let s = "hello";
let _ = s.find("world").is_none().then_some(0);
let s = String::from("hello");
let _ = s.find("world").is_none().then_some(0);
}
}

View File

@ -282,5 +282,77 @@ error: called `is_none()` after searching an `Iterator` with `find`
LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))`
error: aborting due to 43 previous errors error: called `is_none()` after searching an `Iterator` with `find`
--> tests/ui/search_is_some_fixable_none.rs:235:17
|
LL | let _ = v.iter().find(|x| **x == 42).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)`
error: called `is_none()` after searching an `Iterator` with `find`
--> tests/ui/search_is_some_fixable_none.rs:236:17
|
LL | Foo.bar(v.iter().find(|x| **x == 42).is_none());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)`
error: called `is_none()` after searching an `Iterator` with `find`
--> tests/ui/search_is_some_fixable_none.rs:241:9
|
LL | v.iter().find(|x| **x == 42).is_none().then(computations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))`
error: called `is_none()` after searching an `Iterator` with `find`
--> tests/ui/search_is_some_fixable_none.rs:246:9
|
LL | v.iter().find(|x| **x == 42).is_none().then_some(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:251:17
|
LL | let _ = s.find("world").is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:252:17
|
LL | Foo.bar(s.find("world").is_none());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:254:17
|
LL | let _ = s.find("world").is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:255:17
|
LL | Foo.bar(s.find("world").is_none());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:260:17
|
LL | let _ = s.find("world").is_none().then(computations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:262:17
|
LL | let _ = s.find("world").is_none().then(computations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:267:17
|
LL | let _ = s.find("world").is_none().then_some(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: called `is_none()` after calling `find()` on a string
--> tests/ui/search_is_some_fixable_none.rs:269:17
|
LL | let _ = s.find("world").is_none().then_some(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: aborting due to 55 previous errors

View File

@ -1,5 +1,4 @@
#![warn(clippy::temporary_assignment)] #![warn(clippy::temporary_assignment)]
#![allow(const_item_mutation)]
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};

View File

@ -1,5 +1,5 @@
error: assignment to temporary error: assignment to temporary
--> tests/ui/temporary_assignment.rs:48:5 --> tests/ui/temporary_assignment.rs:47:5
| |
LL | Struct { field: 0 }.field = 1; LL | Struct { field: 0 }.field = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -8,7 +8,7 @@ LL | Struct { field: 0 }.field = 1;
= help: to override `-D warnings` add `#[allow(clippy::temporary_assignment)]` = help: to override `-D warnings` add `#[allow(clippy::temporary_assignment)]`
error: assignment to temporary error: assignment to temporary
--> tests/ui/temporary_assignment.rs:51:5 --> tests/ui/temporary_assignment.rs:50:5
| |
LL | / MultiStruct { LL | / MultiStruct {
LL | | LL | |
@ -19,13 +19,13 @@ LL | | .field = 1;
| |______________^ | |______________^
error: assignment to temporary error: assignment to temporary
--> tests/ui/temporary_assignment.rs:57:5 --> tests/ui/temporary_assignment.rs:56:5
| |
LL | ArrayStruct { array: [0] }.array[0] = 1; LL | ArrayStruct { array: [0] }.array[0] = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: assignment to temporary error: assignment to temporary
--> tests/ui/temporary_assignment.rs:59:5 --> tests/ui/temporary_assignment.rs:58:5
| |
LL | (0, 0).0 = 1; LL | (0, 0).0 = 1;
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^

View File

@ -0,0 +1,8 @@
//@compile-flags: -C incremental=target/debug/test/incr
// see https://github.com/rust-lang/rust-clippy/issues/10969
fn main() {
let s = "Hello, world!";
println!("{}", s);
}

View File

@ -0,0 +1,8 @@
//@compile-flags: -C incremental=target/debug/test/incr
// see https://github.com/rust-lang/rust-clippy/issues/10969
fn main() {
let s = "Hello, world!";
println!("{}", s.to_string());
}

View File

@ -0,0 +1,11 @@
error: `to_string` applied to a type that implements `Display` in `println!` args
--> tests/ui/to_string_in_format_args_incremental.rs:7:21
|
LL | println!("{}", s.to_string());
| ^^^^^^^^^^^^ help: remove this
|
= note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::to_string_in_format_args)]`
error: aborting due to 1 previous error

View File

@ -266,7 +266,7 @@ struct S13 {
impl S13 { impl S13 {
fn new() -> Self { fn new() -> Self {
// Shoud not warn! // Should not warn!
Self::default() Self::default()
} }
} }

View File

@ -57,5 +57,41 @@ error: no need to put clippy lints behind a `clippy` cfg
LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]`
error: aborting due to 8 previous errors error: duplicated attribute
--> tests/ui/unnecessary_clippy_cfg.rs:8:26
|
LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))]
| ^^^^^^^^^
|
note: first defined here
--> tests/ui/unnecessary_clippy_cfg.rs:6:26
|
LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
| ^^^^^^^^^
help: remove this attribute
--> tests/ui/unnecessary_clippy_cfg.rs:8:26
|
LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))]
| ^^^^^^^^^
= note: `-D clippy::duplicated-attributes` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]`
error: duplicated attribute
--> tests/ui/unnecessary_clippy_cfg.rs:17:25
|
LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))]
| ^^^^^^^^^
|
note: first defined here
--> tests/ui/unnecessary_clippy_cfg.rs:15:25
|
LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
| ^^^^^^^^^
help: remove this attribute
--> tests/ui/unnecessary_clippy_cfg.rs:17:25
|
LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))]
| ^^^^^^^^^
error: aborting due to 10 previous errors

View File

@ -1,6 +1,6 @@
//@aux-build:proc_macro_derive.rs //@aux-build:proc_macro_derive.rs
#![allow(unused)] #![allow(unused, clippy::duplicated_attributes)]
#![warn(clippy::useless_attribute)] #![warn(clippy::useless_attribute)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
#![feature(rustc_private)] #![feature(rustc_private)]

View File

@ -1,6 +1,6 @@
//@aux-build:proc_macro_derive.rs //@aux-build:proc_macro_derive.rs
#![allow(unused)] #![allow(unused, clippy::duplicated_attributes)]
#![warn(clippy::useless_attribute)] #![warn(clippy::useless_attribute)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
#![feature(rustc_private)] #![feature(rustc_private)]

View File

@ -19,7 +19,12 @@ new_pr = true
[assign] [assign]
contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
users_on_vacation = ["y21"] users_on_vacation = [
"y21",
"matthiaskrgr",
"giraffate",
"Centri3",
]
[assign.owners] [assign.owners]
"/.github" = ["@flip1995"] "/.github" = ["@flip1995"]