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

View File

@ -18,17 +18,27 @@ category.
| `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::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::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 might have false positives | allow |
| `clippy::pedantic` | lints which are rather strict or have occasional 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::cargo` | lints for the cargo manifest | allow | | allow |
| `clippy::cargo` | lints for the cargo manifest | allow |
More to come, please [file an
issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
More to come, please [file an 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
contains "restriction lints", which are for things which are usually not
considered "bad", but may be useful to turn on in specific cases. These should
be used very selectively, if at all.
The `restriction` category should, *emphatically*, not be enabled as a whole. The contained
lints may lint against perfectly reasonable code, may not have an alternative suggestion,
and may contradict any other lints (including other categories). Lints should be considered
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)
- [Rustfix tests](#rustfix-tests)
- [Testing manually](#testing-manually)
- [Running directly](#running-directly)
- [Lint declaration](#lint-declaration)
- [Lint registration](#lint-registration)
- [Lint passes](#lint-passes)
@ -176,23 +175,26 @@ the tests.
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
your local modifications, run
your local modifications, run the following from the Clippy directory:
```
```bash
cargo dev lint input.rs
```
from the working copy root. With tests in place, let's have a look at
implementing our lint now.
To run Clippy on an existing project rather than a single file you can use
## 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
`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,
add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches)
to your library search path.
On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path.
Or set up a rustup toolchain that points to the local Clippy binaries
```bash
cargo dev setup toolchain
# Then in `/path/to/project` you can run
cargo +clippy clippy
```
## 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)
## `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`
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_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
#[derive(Default)]
@ -589,6 +590,26 @@ define_Conf! {
/// 2. Paths with any segment that containing the word 'prelude'
/// are already allowed by 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.
@ -649,6 +670,7 @@ fn deserialize(file: &SourceFile) -> TryConf {
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.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
if conf.conf.allowed_idents_below_min_chars.contains("..") {
conf.conf

View File

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

View File

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

View File

@ -46,6 +46,13 @@ fn main() {
}
},
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)) => {
if matches.get_flag("remove") {
setup::intellij::remove_rustc_src();
@ -57,12 +64,12 @@ fn main() {
);
}
},
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(("toolchain", matches)) => {
setup::toolchain::create(
matches.get_flag("force"),
matches.get_flag("release"),
matches.get_one::<String>("name").unwrap(),
);
},
Some(("vscode-tasks", matches)) => {
if matches.get_flag("remove") {
@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches {
.about("Support for setting up your personal development environment")
.arg_required_else_help(true)
.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")
.about("Alter dependencies so Intellij Rust can find rustc internals")
.args([
@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches {
.conflicts_with("remove")
.required(true),
]),
Command::new("git-hook")
.about("Add a pre-commit git hook that formats your code to make it look pretty")
Command::new("toolchain")
.about("Install a rustup toolchain pointing to the local clippy build")
.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")
Arg::new("force")
.long("force")
.short('f')
.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")
.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
///
/// This function errors out if the files couldn't be created or written to.
#[allow(clippy::missing_panics_doc)]
pub fn create(
pass: &String,
lint_name: Option<&String>,

View File

@ -1,5 +1,6 @@
pub mod git_hook;
pub mod intellij;
pub mod toolchain;
pub mod vscode;
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(sync) = cx.tcx.lang_items().sync_trait()
&& 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)
{
span_lint_and_then(
@ -66,21 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
"usage of an `Arc` that is not `Send` and `Sync`",
|diag| {
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!(
"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 rustc_ast::{Attribute, MetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::EarlyContext;
use rustc_lint::LateContext;
use rustc_span::{sym, Span};
use std::collections::hash_map::Entry;
fn emit_if_duplicated(
cx: &EarlyContext<'_>,
cx: &LateContext<'_>,
attr: &MetaItem,
attr_paths: &mut FxHashMap<String, Span>,
complete_path: String,
@ -26,7 +26,7 @@ fn emit_if_duplicated(
}
fn check_duplicated_attr(
cx: &EarlyContext<'_>,
cx: &LateContext<'_>,
attr: &MetaItem,
attr_paths: &mut FxHashMap<String, Span>,
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();
for attr in attrs {

View File

@ -17,7 +17,7 @@ mod useless_attribute;
mod utils;
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_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, impl_lint_pass};
@ -534,11 +534,13 @@ declare_lint_pass!(Attributes => [
BLANKET_CLIPPY_RESTRICTION_LINTS,
SHOULD_PANIC_WITHOUT_EXPECT,
MIXED_ATTRIBUTES_STYLE,
DUPLICATED_ATTRIBUTES,
]);
impl<'tcx> LateLintPass<'tcx> for Attributes {
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
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) {
@ -578,6 +580,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
_ => {},
}
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<'_>) {
@ -606,17 +609,11 @@ impl_lint_pass!(EarlyAttributes => [
MAYBE_MISUSED_CFG,
DEPRECATED_CLIPPY_CFG_ATTR,
UNNECESSARY_CLIPPY_CFG,
DUPLICATED_ATTRIBUTES,
]);
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) {
empty_line_after::check(cx, item);
duplicated_attributes::check(cx, &item.attrs);
}
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,
}
.and_then(|op| {
Some(format!(
"{}{op}{}",
snippet_opt(cx, lhs.span)?,
snippet_opt(cx, rhs.span)?
))
let lhs_snippet = snippet_opt(cx, lhs.span)?;
let rhs_snippet = 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, [], _) => {

View File

@ -754,11 +754,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) {
ptr_as_ptr::check(cx, expr, &self.msrv);
}
if expr.span.from_expansion() {
if in_external_macro(cx.sess(), expr.span) {
return;
}
@ -771,7 +767,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
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;
}
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);
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);
if cast_from.is_numeric() {
cast_possible_wrap::check(cx, expr, cast_from, cast_to);

View File

@ -1016,9 +1016,18 @@ fn report<'tcx>(
},
_ => (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
&& (calls_field || expr.precedence().order() < precedence)
&& !has_enclosing_paren(&snip)
&& !is_in_tuple
{
format!("({snip})")
} else {

View File

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

View File

@ -11,7 +11,7 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_D
pub fn check(
cx: &LateContext<'_>,
owner_id: OwnerId,
sig: &FnSig<'_>,
sig: FnSig<'_>,
headers: DocHeaders,
body_id: Option<BodyId>,
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::ty::is_type_diagnostic_item;
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::{
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 rustc_ast::ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
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_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
@ -366,7 +365,6 @@ declare_clippy_lint! {
#[derive(Clone)]
pub struct Documentation {
valid_idents: FxHashSet<String>,
in_trait_impl: bool,
check_private_items: bool,
}
@ -374,7 +372,6 @@ impl Documentation {
pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
Self {
valid_idents: valid_idents.iter().cloned().collect(),
in_trait_impl: false,
check_private_items,
}
}
@ -394,36 +391,72 @@ impl_lint_pass!(Documentation => [
]);
impl<'tcx> LateLintPass<'tcx> for Documentation {
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
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());
fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
return;
};
match item.kind {
hir::ItemKind::Fn(ref sig, _, 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);
match cx.tcx.hir_node(cx.last_node_with_lint_attrs) {
Node::Item(item) => match item.kind {
ItemKind::Fn(sig, _, 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(
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,
headers,
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 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![
// 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
// ~~~~ ~~~~
(self_ident.span, format!("val: {from}")),
];
if let FnRetTy::Return(_) = sig.decl.output {
// 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 {
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_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
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::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 rustc_data_structures::fx::FxHashSet;
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
@ -147,6 +148,7 @@ pub struct ItemNameRepetitions {
struct_threshold: u64,
avoid_breaking_exported_api: bool,
allow_private_module_inception: bool,
allowed_prefixes: FxHashSet<String>,
}
impl ItemNameRepetitions {
@ -156,6 +158,7 @@ impl ItemNameRepetitions {
struct_threshold: u64,
avoid_breaking_exported_api: bool,
allow_private_module_inception: bool,
allowed_prefixes: &[String],
) -> Self {
Self {
modules: Vec::new(),
@ -163,8 +166,13 @@ impl ItemNameRepetitions {
struct_threshold,
avoid_breaking_exported_api,
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 => [
@ -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(
cx,
MODULE_NAME_REPETITIONS,

View File

@ -17,7 +17,7 @@ declare_clippy_lint! {
/// `std::<float>::EPSILON`, etc.
///
/// ### 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.
///
/// ### Example

View File

@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
pub_underscore_fields_behavior,
ref allowed_duplicate_crates,
allow_comparison_to_zero,
ref allowed_prefixes,
blacklisted_names: _,
cyclomatic_complexity_threshold: _,
@ -864,6 +865,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
struct_field_name_threshold,
avoid_breaking_exported_api,
allow_private_module_inception,
allowed_prefixes,
))
});
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`
// ^^ ^^^
let span = cx
.sess()
.source_map()
.span_extend_while_whitespace(usage.ident.span);
let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
(span, String::new())
},

View File

@ -1,13 +1,14 @@
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::GenericArgKind;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
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::{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 {
let ExprKind::Match(match_expr, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) = expr.kind else {
return false;
#[allow(clippy::needless_pass_by_value)]
fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, expr: &'tcx Expr<'tcx>) {
// 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()
&& arm2.guard.is_none()
// 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, &[])
// We now get the bodies for both the `Some` and `None` arms.
&& let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2)
// We check if the return type of the expression implements Default.
let expr_type = cx.typeck_results().expr_ty(expr);
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
&& implements_trait(cx, expr_type, default_trait_id, &[])
// We check if the initial condition implements Default.
&& let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1)
&& let GenericArgKind::Type(condition_ty) = condition_ty.unpack()
&& 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`.
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
&& 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`.
&& let body_none = peel_blocks(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) {
Applicability::MaybeIncorrect
} else {
@ -136,48 +158,12 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
cx,
MANUAL_UNWRAP_OR_DEFAULT,
expr.span,
"match can be simplified with `.unwrap_or_default()`",
format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
"replace it with",
format!("{receiver}.unwrap_or_default()"),
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 {
@ -185,8 +171,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
return;
}
if !handle_match(cx, expr) {
handle_if_let(cx, expr);
// Call handle only if the expression is `if let` or `match`
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
/// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is
/// valid.
/// ```
#[clippy::version = "1.77.0"]
pub STR_SPLIT_AT_NEWLINE,
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::sugg::deref_closure_args;
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_hir as hir;
use rustc_hir::PatKind;
@ -35,7 +36,7 @@ pub(super) fn check<'tcx>(
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
let mut applicability = Applicability::MachineApplicable;
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 Some(closure_arg) = closure_body.params.first()
{
@ -72,16 +73,24 @@ pub(super) fn check<'tcx>(
);
} else {
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(
cx,
SEARCH_IS_SOME,
expr.span,
msg,
"consider using",
format!(
"!{iter}.any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
sugg,
applicability,
);
}
@ -127,13 +136,18 @@ pub(super) fn check<'tcx>(
let string = snippet(cx, search_recv.span, "..");
let mut applicability = Applicability::MachineApplicable;
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(
cx,
SEARCH_IS_SOME,
expr.span,
msg,
"consider using",
format!("!{string}.contains({find_arg})"),
sugg,
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_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
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::symbol::Ident;
use std::iter;

View File

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

View File

@ -23,7 +23,7 @@ use std::collections::VecDeque;
declare_clippy_lint! {
/// ### 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.
///
/// ### 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::{self, Ty, TyCtxt};
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;
// 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 {
let args = cx.typeck_results().node_args(hir_id);
let result = Self::const_eval_resolve(
cx.tcx,
cx.param_env,
ty::UnevaluatedConst::new(def_id, args),
DUMMY_SP,
);
let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP);
self.is_value_unfrozen_raw(cx, result, ty)
}

View File

@ -300,11 +300,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
e.span,
"calling `as_bytes()` on `include_str!(..)`",
"consider using `include_bytes!(..)` instead",
snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability).replacen(
"include_str",
"include_bytes",
1,
),
snippet_with_applicability(cx, receiver.span.source_callsite(), r#""foo""#, &mut applicability)
.replacen("include_str", "include_bytes", 1),
applicability,
);
} 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.
let coercable_types = [
let coercible_types = [
("NonZeroU8", tcx.types.u8),
("NonZeroU16", tcx.types.u16),
("NonZeroU32", tcx.types.u32),
@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
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 {
Some(nonzero_alias)
} else {

View File

@ -1,10 +1,10 @@
use rustc_hir_typeck::cast::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use rustc_ast::ExprPrecedence;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Node};
use rustc_hir_typeck::cast::check_cast;
use rustc_lint::LateContext;
use rustc_middle::ty::cast::CastKind;
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)),
(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),
(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)),
(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)
})
},
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
_ => 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),
});
// 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 path = Vec::new();
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_session::Session;
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::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_id::DefId;
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_lint::LateContext;
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) {
certainty.with_def_id(def_id)
} 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::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::process::{Command, ExitStatus};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use std::{env, fs, thread};
use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel};
use cargo_metadata::diagnostic::Diagnostic;
use cargo_metadata::Message;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
@ -97,16 +97,43 @@ struct Crate {
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`
#[derive(Debug)]
struct ClippyWarning {
crate_name: String,
file: String,
line: usize,
column: usize,
lint_type: String,
message: String,
is_ice: bool,
}
#[allow(unused)]
@ -131,13 +158,11 @@ impl ClippyWarning {
};
Some(Self {
crate_name: crate_name.to_owned(),
file,
line: span.line_start,
column: span.column_start,
lint_type,
message: diag.message,
is_ice: diag.level == DiagnosticLevel::Ice,
})
}
@ -318,7 +343,7 @@ impl Crate {
config: &LintcheckConfig,
lint_filter: &[String],
server: &Option<LintcheckServer>,
) -> Vec<ClippyWarning> {
) -> Vec<ClippyCheckOutput> {
// advance the atomic index by one
let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
// "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 mut cargo_clippy_args = if config.fix {
vec!["--fix", "--"]
vec!["--quiet", "--fix", "--"]
} else {
vec!["--", "--message-format=json", "--"]
vec!["--quiet", "--message-format=json", "--"]
};
let mut clippy_args = Vec::<&str>::new();
@ -435,14 +460,21 @@ impl Crate {
}
// 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 {
Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version),
_ => None,
})
.map(ClippyCheckOutput::ClippyWarning)
.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)
});
let mut clippy_warnings: Vec<ClippyWarning> = crates
let mut clippy_entries: Vec<ClippyCheckOutput> = crates
.par_iter()
.flat_map(|krate| {
krate.run_clippy_lints(
@ -658,7 +690,9 @@ fn main() {
.collect();
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
@ -666,20 +700,21 @@ fn main() {
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
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 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();
let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect();
all_msgs.sort();
all_msgs.push("\n\n### Stats:\n\n".into());
all_msgs.push(stats_formatted);
@ -693,11 +728,18 @@ fn main() {
}
write!(text, "{}", all_msgs.join("")).unwrap();
text.push_str("\n\n### ICEs:\n");
for (cratename, msg) in &ices {
let _: fmt::Result = write!(text, "{cratename}: '{msg}'");
for ice in &raw_ices {
let _: fmt::Result = write!(
text,
"{}:\n{}\n========================================\n\n",
ice.crate_name, ice.ice_content
);
}
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::write(&config.lintcheck_results_path, text).unwrap();

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2024-04-04"
channel = "nightly-2024-04-05"
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 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: "this compiler `.*` is outdated" -> "this compiler <version> is outdated"
#![deny(clippy::internal)]
#![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.
note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the meantime
|
= note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists
= 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: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
note: please make sure that you have updated to the latest nightly
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
--> 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`

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

View File

@ -33,16 +33,9 @@ fn main() {
let _ = Arc::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 _ = 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);
//~^ 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));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Arc<RefCell<i32>>` is not `Send` and `Sync` as:
= note: - the trait `Sync` is not implemented for `RefCell<i32>`
= 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 `RefCell<i32>`
= note: `Arc<RefCell<i32>>` is not `Send` and `Sync` as `RefCell<i32>` is not `Sync`
= help: if the `Arc` will not used be across threads replace it with an `Rc`
= help: otherwise make `RefCell<i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex`
= 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)]`
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());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Arc<MutexGuard<'_, i32>>` is not `Send` and `Sync` as:
= note: - the trait `Send` is not implemented for `MutexGuard<'_, i32>`
= 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 `MutexGuard<'_, i32>`
= note: `Arc<MutexGuard<'_, i32>>` is not `Send` and `Sync` as `MutexGuard<'_, i32>` is not `Send`
= help: if the `Arc` will not used be across threads replace it with an `Rc`
= help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex`
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);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `Arc<*const i32>` is not `Send` and `Sync` as:
= note: - the trait `Send` is not implemented for `*const i32`
= note: - the trait `Sync` is not implemented for `*const i32`
= 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`
= note: `Arc<*const i32>` is not `Send` and `Sync` as `*const i32` is neither `Send` nor `Sync`
= help: if the `Arc` will not used be across threads replace it with an `Rc`
= help: otherwise make `*const i32` `Send` and `Sync` or consider a wrapper type such as `Mutex`
error: aborting due to 3 previous errors

View File

@ -176,3 +176,17 @@ pub fn with_empty_docs(_attr: TokenStream, input: TokenStream) -> TokenStream {
}
.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 {
let bar: Result<Option<i64>, u32> = Ok(Some(10));
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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
--> tests/ui/cast.rs:468:5
--> tests/ui/cast.rs:480:5
|
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
--> tests/ui/cast.rs:468:5
--> tests/ui/cast.rs:480:5
|
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`
= help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
error: `as` casting between raw pointers without changing its mutability
--> 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
error: aborting due to 1 previous error

View File

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

View File

@ -1,5 +1,5 @@
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 | |
@ -10,7 +10,7 @@ LL | | }
| |_^
|
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 | |
@ -23,7 +23,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
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 | |
@ -34,7 +34,7 @@ LL | | }
| |_^
|
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 | |
@ -45,7 +45,7 @@ LL | | }
| |_^
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 | |
@ -56,7 +56,7 @@ LL | | }
| |_^
|
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 | |
@ -67,7 +67,7 @@ LL | | }
| |_^
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 | |
@ -78,7 +78,7 @@ LL | | }
| |_^
|
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 | |
@ -89,7 +89,7 @@ LL | | }
| |_^
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 | |
@ -100,7 +100,7 @@ LL | | }
| |_^
|
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 | |

View File

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

View File

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

View File

@ -352,5 +352,16 @@ help: try
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)]
#![cfg(any(unix, windows))]
#![allow(dead_code)]
#![allow(dead_code)] //~ ERROR: duplicated attribute
#![cfg(any(unix, windows))] // Should not warn!
#[macro_use]
extern crate proc_macro_attr;
#[cfg(any(unix, windows, target_os = "linux"))]
#[allow(dead_code)]
#[allow(dead_code)] //~ ERROR: duplicated attribute
@ -12,7 +17,10 @@ fn foo() {}
#[cfg(unix)]
#[cfg(windows)]
#[cfg(unix)] //~ ERROR: duplicated attribute
#[cfg(unix)] // cfgs are not handled
fn bar() {}
#[proc_macro_attr::duplicated_attr()] // Should not warn!
fn babar() {}
fn main() {}

View File

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

View File

@ -16,6 +16,16 @@ fn main() {
let x: Option<Vec<String>> = None;
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

View File

@ -37,6 +37,16 @@ fn main() {
} else {
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

View File

@ -53,7 +53,7 @@ LL | | };
| |_____^ help: replace it with: `x.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 {
| ____________________^

View File

@ -19,6 +19,20 @@ mod foo {
// Should not warn
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() {}

View File

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

View File

@ -1,5 +1,5 @@
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 | | STATIC += 1;
@ -8,12 +8,12 @@ LL | | }
| |_____^
|
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;
| ^^^^^^^^^^^
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();
| ^^^^^^^^^^^^^^^
@ -21,7 +21,7 @@ LL | not_very_safe();
= help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]`
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 | | drop(u.u);
@ -30,18 +30,18 @@ LL | | }
| |_____^
|
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);
| ^^^
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();
| ^^^^^^^^^^
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 | | asm!("nop");
@ -51,23 +51,23 @@ LL | | }
| |_____^
|
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");
| ^^^^^^^^^^^
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();
| ^^^^^^^^^^^^^^^^^^^^^^
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;
| ^^^^^^^^^^
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 | | drop(u.u);
@ -79,55 +79,55 @@ LL | | }
| |_____^
|
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);
| ^^^
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);
| ^^^^^^
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();
| ^^^^^^^^^^^^^^^^^^^^^^
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();
| ^^^^^^^^^^^^^^^
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();
| ^^^^^^^^^^
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");
| ^^^^^^^^^^^
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>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
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>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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>()) }
| ^^^^^^^^^^^^^^^^^^
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 | | x();
@ -136,18 +136,18 @@ LL | | }
| |_____^
|
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();
| ^^^
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();
| ^^^
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 | | T::X();
@ -156,18 +156,18 @@ LL | | }
| |_________^
|
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();
| ^^^^^^
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();
| ^^^^^^
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 | | x.0();
@ -176,12 +176,12 @@ LL | | }
| |_____^
|
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();
| ^^^^^
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();
| ^^^^^

View File

@ -251,3 +251,11 @@ mod issue_10253 {
(&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::<()>();
}
}
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;
| ^^^^^^^^^^^^^^ 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!();
/// }
/// ```
///
///
/// With an explicit return type it should lint too
/// ```edition2015
/// fn main() -> () {
@ -18,7 +18,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// This should, too.
/// ```rust
/// fn main() {
@ -26,7 +26,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// This one too.
/// ```no_run
/// // 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);
}
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() {}

View File

@ -109,4 +109,12 @@ fn dont_warn_for_negated_partial_ord_comparison() {
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() {}

View File

@ -79,5 +79,23 @@ error: this boolean expression can be simplified
LL | if !res.is_none() {}
| ^^^^^^^^^^^^^^ 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
//@compile-flags: -Zdeduplicate-diagnostics=yes
#![warn(clippy::ptr_as_ptr)]

View File

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

View File

@ -1,5 +1,5 @@
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>) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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)]`
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;
| ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
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;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
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;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
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 _;
| ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
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 _;
| ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
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);
| ^^^^^^^^^^^^^^^^^^ 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)
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;
| ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
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;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
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 _
| ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
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 _
| ^^^^^^^^^^^^^^^^^^^^^^ 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));
}
}
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();
}
}
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();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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)]
#![allow(const_item_mutation)]
use std::ops::{Deref, DerefMut};

View File

@ -1,5 +1,5 @@
error: assignment to temporary
--> tests/ui/temporary_assignment.rs:48:5
--> tests/ui/temporary_assignment.rs:47:5
|
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)]`
error: assignment to temporary
--> tests/ui/temporary_assignment.rs:51:5
--> tests/ui/temporary_assignment.rs:50:5
|
LL | / MultiStruct {
LL | |
@ -19,13 +19,13 @@ LL | | .field = 1;
| |______________^
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;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: assignment to temporary
--> tests/ui/temporary_assignment.rs:59:5
--> tests/ui/temporary_assignment.rs:58:5
|
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 {
fn new() -> Self {
// Shoud not warn!
// Should not warn!
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))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
#![allow(unused)]
#![allow(unused, clippy::duplicated_attributes)]
#![warn(clippy::useless_attribute)]
#![warn(unreachable_pub)]
#![feature(rustc_private)]

View File

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

View File

@ -19,7 +19,12 @@ new_pr = true
[assign]
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]
"/.github" = ["@flip1995"]