1
Fork 0

Merge commit 'a859e5cc1c' into clippyup

This commit is contained in:
Philipp Krones 2023-12-16 14:12:50 +01:00
parent d517ae683e
commit 3596d44988
108 changed files with 3063 additions and 636 deletions

View file

@ -206,6 +206,7 @@ jobs:
max-parallel: 6 max-parallel: 6
matrix: matrix:
integration: integration:
- 'matthiaskrgr/clippy_ci_panic_test'
- 'rust-lang/cargo' - 'rust-lang/cargo'
- 'rust-lang/chalk' - 'rust-lang/chalk'
- 'rust-lang/rustfmt' - 'rust-lang/rustfmt'
@ -220,7 +221,6 @@ jobs:
- 'rust-itertools/itertools' - 'rust-itertools/itertools'
- 'rust-lang-nursery/failure' - 'rust-lang-nursery/failure'
- 'rust-lang/log' - 'rust-lang/log'
- 'matthiaskrgr/clippy_ci_panic_test'
runs-on: ubuntu-latest runs-on: ubuntu-latest

View file

@ -4946,6 +4946,7 @@ Released 2018-09-13
[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints [`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
[`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr [`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr
[`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt [`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt
[`blocks_in_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_conditions
[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
[`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
@ -5145,9 +5146,11 @@ Released 2018-09-13
[`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice [`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
[`ineffective_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_open_options
[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string [`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
[`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
[`infinite_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_loop
[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
[`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields [`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields
@ -5462,6 +5465,7 @@ Released 2018-09-13
[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
[`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization [`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
@ -5582,6 +5586,7 @@ Released 2018-09-13
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops [`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
[`uninhabited_references`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninhabited_references
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args [`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

View file

@ -1,6 +1,6 @@
use crate::{cargo_clippy_path, exit_if_err}; use crate::{cargo_clippy_path, exit_if_err};
use std::fs;
use std::process::{self, Command}; use std::process::{self, Command};
use std::{env, fs};
pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) { pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
let is_file = match fs::metadata(path) { let is_file = match fs::metadata(path) {
@ -13,7 +13,7 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
if is_file { if is_file {
exit_if_err( exit_if_err(
Command::new("cargo") Command::new(env::var("CARGO").unwrap_or("cargo".into()))
.args(["run", "--bin", "clippy-driver", "--"]) .args(["run", "--bin", "clippy-driver", "--"])
.args(["-L", "./target/debug"]) .args(["-L", "./target/debug"])
.args(["-Z", "no-codegen"]) .args(["-Z", "no-codegen"])
@ -23,7 +23,11 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
.status(), .status(),
); );
} else { } else {
exit_if_err(Command::new("cargo").arg("build").status()); exit_if_err(
Command::new(env::var("CARGO").unwrap_or("cargo".into()))
.arg("build")
.status(),
);
let status = Command::new(cargo_clippy_path()) let status = Command::new(cargo_clippy_path())
.arg("clippy") .arg("clippy")

View file

@ -2,8 +2,8 @@ use std::ffi::OsStr;
use std::num::ParseIntError; use std::num::ParseIntError;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::thread;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use std::{env, thread};
/// # Panics /// # Panics
/// ///
@ -16,7 +16,7 @@ pub fn run(port: u16, lint: Option<&String>) -> ! {
loop { loop {
if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") { if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
Command::new("cargo") Command::new(env::var("CARGO").unwrap_or("cargo".into()))
.arg("collect-metadata") .arg("collect-metadata")
.spawn() .spawn()
.unwrap() .unwrap()

View file

@ -16,7 +16,7 @@ clippy_utils = { path = "../clippy_utils" }
declare_clippy_lint = { path = "../declare_clippy_lint" } declare_clippy_lint = { path = "../declare_clippy_lint" }
itertools = "0.11" itertools = "0.11"
quine-mc_cluskey = "0.2" quine-mc_cluskey = "0.2"
regex-syntax = "0.7" regex-syntax = "0.8"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
tempfile = { version = "3.3.0", optional = true } tempfile = { version = "3.3.0", optional = true }

View file

@ -48,11 +48,10 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for AsConversions { impl<'tcx> LateLintPass<'tcx> for AsConversions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) { if let ExprKind::Cast(_, _) = expr.kind
return; && !in_external_macro(cx.sess(), expr.span)
} && !is_from_proc_macro(cx, expr)
{
if let ExprKind::Cast(_, _) = expr.kind {
span_lint_and_help( span_lint_and_help(
cx, cx,
AS_CONVERSIONS, AS_CONVERSIONS,

View file

@ -0,0 +1,137 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::source::snippet_block_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{get_parent_expr, higher};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Checks for `if` conditions that use blocks containing an
/// expression, statements or conditions that use closures with blocks.
///
/// ### Why is this bad?
/// Style, using blocks in the condition makes it hard to read.
///
/// ### Examples
/// ```no_run
/// # fn somefunc() -> bool { true };
/// if { true } { /* ... */ }
///
/// if { let x = somefunc(); x } { /* ... */ }
/// ```
///
/// Use instead:
/// ```no_run
/// # fn somefunc() -> bool { true };
/// if true { /* ... */ }
///
/// let res = { let x = somefunc(); x };
/// if res { /* ... */ }
/// ```
#[clippy::version = "1.45.0"]
pub BLOCKS_IN_CONDITIONS,
style,
"useless or complex blocks that can be eliminated in conditions"
}
declare_lint_pass!(BlocksInConditions => [BLOCKS_IN_CONDITIONS]);
const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
impl<'tcx> LateLintPass<'tcx> for BlocksInConditions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), expr.span) {
return;
}
let Some((cond, keyword, desc)) = higher::If::hir(expr)
.map(|hif| (hif.cond, "if", "an `if` condition"))
.or(if let ExprKind::Match(match_ex, _, MatchSource::Normal) = expr.kind {
Some((match_ex, "match", "a `match` scrutinee"))
} else {
None
})
else {
return;
};
let complex_block_message = &format!(
"in {desc}, avoid complex blocks or closures with blocks; \
instead, move the block or closure higher and bind it with a `let`",
);
if let ExprKind::Block(block, _) = &cond.kind {
if block.rules == BlockCheckMode::DefaultBlock {
if block.stmts.is_empty() {
if let Some(ex) = &block.expr {
// don't dig into the expression here, just suggest that they remove
// the block
if expr.span.from_expansion() || ex.span.from_expansion() {
return;
}
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BLOCKS_IN_CONDITIONS,
cond.span,
BRACED_EXPR_MESSAGE,
"try",
snippet_block_with_applicability(cx, ex.span, "..", Some(expr.span), &mut applicability)
.to_string(),
applicability,
);
}
} else {
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() {
return;
}
// move block higher
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BLOCKS_IN_CONDITIONS,
expr.span.with_hi(cond.span.hi()),
complex_block_message,
"try",
format!(
"let res = {}; {keyword} res",
snippet_block_with_applicability(cx, block.span, "..", Some(expr.span), &mut applicability),
),
applicability,
);
}
}
} else {
let _: Option<!> = for_each_expr(cond, |e| {
if let ExprKind::Closure(closure) = e.kind {
// do not lint if the closure is called using an iterator (see #1141)
if let Some(parent) = get_parent_expr(cx, e)
&& let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind
&& let caller = cx.typeck_results().expr_ty(self_arg)
&& let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& implements_trait(cx, caller, iter_id, &[])
{
return ControlFlow::Continue(Descend::No);
}
let body = cx.tcx.hir().body(closure.body);
let ex = &body.value;
if let ExprKind::Block(block, _) = ex.kind {
if !body.value.span.from_expansion() && !block.stmts.is_empty() {
span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message);
return ControlFlow::Continue(Descend::No);
}
}
}
ControlFlow::Continue(Descend::Yes)
});
}
}
}

View file

@ -1,139 +0,0 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::source::snippet_block_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{get_parent_expr, higher};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir::{BlockCheckMode, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Checks for `if` conditions that use blocks containing an
/// expression, statements or conditions that use closures with blocks.
///
/// ### Why is this bad?
/// Style, using blocks in the condition makes it hard to read.
///
/// ### Examples
/// ```no_run
/// # fn somefunc() -> bool { true };
/// if { true } { /* ... */ }
///
/// if { let x = somefunc(); x } { /* ... */ }
/// ```
///
/// Use instead:
/// ```no_run
/// # fn somefunc() -> bool { true };
/// if true { /* ... */ }
///
/// let res = { let x = somefunc(); x };
/// if res { /* ... */ }
/// ```
#[clippy::version = "1.45.0"]
pub BLOCKS_IN_IF_CONDITIONS,
style,
"useless or complex blocks that can be eliminated in conditions"
}
declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]);
const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \
instead, move the block or closure higher and bind it with a `let`";
impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), expr.span) {
return;
}
if let Some(higher::If { cond, .. }) = higher::If::hir(expr) {
if let ExprKind::Block(block, _) = &cond.kind {
if block.rules == BlockCheckMode::DefaultBlock {
if block.stmts.is_empty() {
if let Some(ex) = &block.expr {
// don't dig into the expression here, just suggest that they remove
// the block
if expr.span.from_expansion() || ex.span.from_expansion() {
return;
}
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BLOCKS_IN_IF_CONDITIONS,
cond.span,
BRACED_EXPR_MESSAGE,
"try",
format!(
"{}",
snippet_block_with_applicability(
cx,
ex.span,
"..",
Some(expr.span),
&mut applicability
)
),
applicability,
);
}
} else {
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() {
return;
}
// move block higher
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BLOCKS_IN_IF_CONDITIONS,
expr.span.with_hi(cond.span.hi()),
COMPLEX_BLOCK_MESSAGE,
"try",
format!(
"let res = {}; if res",
snippet_block_with_applicability(
cx,
block.span,
"..",
Some(expr.span),
&mut applicability
),
),
applicability,
);
}
}
} else {
let _: Option<!> = for_each_expr(cond, |e| {
if let ExprKind::Closure(closure) = e.kind {
// do not lint if the closure is called using an iterator (see #1141)
if let Some(parent) = get_parent_expr(cx, e)
&& let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind
&& let caller = cx.typeck_results().expr_ty(self_arg)
&& let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& implements_trait(cx, caller, iter_id, &[])
{
return ControlFlow::Continue(Descend::No);
}
let body = cx.tcx.hir().body(closure.body);
let ex = &body.value;
if let ExprKind::Block(block, _) = ex.kind {
if !body.value.span.from_expansion() && !block.stmts.is_empty() {
span_lint(cx, BLOCKS_IN_IF_CONDITIONS, ex.span, COMPLEX_BLOCK_MESSAGE);
return ControlFlow::Continue(Descend::No);
}
}
}
ControlFlow::Continue(Descend::Yes)
});
}
}
}
}

View file

@ -57,7 +57,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
&& !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
&& let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ref_ty = cx.typeck_results().expr_ty(deref_target)
&& let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
&& !is_from_proc_macro(cx, e)
{ {
if let Some(parent_expr) = get_parent_expr(cx, e) { if let Some(parent_expr) = get_parent_expr(cx, e) {
if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..))
@ -75,6 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
return; return;
} }
} }
if is_from_proc_macro(cx, e) {
return;
}
span_lint_and_then( span_lint_and_then(
cx, cx,

View file

@ -9,11 +9,10 @@ use rustc_middle::ty::{self, Ty, TypeAndMut};
use super::AS_PTR_CAST_MUT; use super::AS_PTR_CAST_MUT;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
if let ty::RawPtr( if let ty::RawPtr(TypeAndMut {
TypeAndMut { mutbl: Mutability::Mut,
mutbl: Mutability::Mut, ty: ptrty, ty: ptrty,
}, }) = cast_to.kind()
) = cast_to.kind()
&& let ty::RawPtr(TypeAndMut { && let ty::RawPtr(TypeAndMut {
mutbl: Mutability::Not, .. mutbl: Mutability::Not, ..
}) = cx.typeck_results().node_type(cast_expr.hir_id).kind() }) = cx.typeck_results().node_type(cast_expr.hir_id).kind()

View file

@ -3,12 +3,29 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind};
use rustc_hir_pretty::qpath_to_string;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, TypeAndMut}; use rustc_middle::ty::{self, TypeAndMut};
use rustc_span::sym;
use super::PTR_AS_PTR; use super::PTR_AS_PTR;
enum OmitFollowedCastReason<'a> {
None,
Null(&'a QPath<'a>),
NullMut(&'a QPath<'a>),
}
impl OmitFollowedCastReason<'_> {
fn corresponding_item(&self) -> Option<&QPath<'_>> {
match self {
OmitFollowedCastReason::None => None,
OmitFollowedCastReason::Null(x) | OmitFollowedCastReason::NullMut(x) => Some(*x),
}
}
}
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
if !msrv.meets(msrvs::POINTER_CAST) { if !msrv.meets(msrvs::POINTER_CAST) {
return; return;
@ -25,7 +42,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
&& to_pointee_ty.is_sized(cx.tcx, cx.param_env) && to_pointee_ty.is_sized(cx.tcx, cx.param_env)
{ {
let mut app = Applicability::MachineApplicable; let mut app = Applicability::MachineApplicable;
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
let turbofish = match &cast_to_hir_ty.kind { let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => String::new(), TyKind::Infer => String::new(),
TyKind::Ptr(mut_ty) => { TyKind::Ptr(mut_ty) => {
@ -41,13 +57,44 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
_ => return, _ => return,
}; };
// following `cast` does not compile because it fails to infer what type is expected
// as type argument to `std::ptr::ptr_null` or `std::ptr::ptr_null_mut`, so
// we omit following `cast`:
let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
&& let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
{
let method_defid = path.res.def_id();
if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
OmitFollowedCastReason::Null(qpath)
} else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {
OmitFollowedCastReason::NullMut(qpath)
} else {
OmitFollowedCastReason::None
}
} else {
OmitFollowedCastReason::None
};
let (help, final_suggestion) = if let Some(method) = omit_cast.corresponding_item() {
// don't force absolute path
let method = qpath_to_string(method);
("try call directly", format!("{method}{turbofish}()"))
} else {
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
(
"try `pointer::cast`, a safer alternative",
format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
)
};
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
PTR_AS_PTR, PTR_AS_PTR,
expr.span, expr.span,
"`as` casting between raw pointers without changing its mutability", "`as` casting between raw pointers without changing its mutability",
"try `pointer::cast`, a safer alternative", help,
format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()), final_suggestion,
app, app,
); );
} }

View file

@ -63,7 +63,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO, crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO, crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO, crate::blocks_in_conditions::BLOCKS_IN_CONDITIONS_INFO,
crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO, crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO, crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
crate::booleans::NONMINIMAL_BOOL_INFO, crate::booleans::NONMINIMAL_BOOL_INFO,
@ -215,6 +215,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO, crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::INDEXING_SLICING_INFO,
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO,
crate::infinite_iter::INFINITE_ITER_INFO, crate::infinite_iter::INFINITE_ITER_INFO,
crate::infinite_iter::MAYBE_INFINITE_ITER_INFO, crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO, crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
@ -265,6 +266,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO, crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
crate::loops::EXPLICIT_ITER_LOOP_INFO, crate::loops::EXPLICIT_ITER_LOOP_INFO,
crate::loops::FOR_KV_MAP_INFO, crate::loops::FOR_KV_MAP_INFO,
crate::loops::INFINITE_LOOP_INFO,
crate::loops::ITER_NEXT_LOOP_INFO, crate::loops::ITER_NEXT_LOOP_INFO,
crate::loops::MANUAL_FIND_INFO, crate::loops::MANUAL_FIND_INFO,
crate::loops::MANUAL_FLATTEN_INFO, crate::loops::MANUAL_FLATTEN_INFO,
@ -598,6 +600,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::reference::DEREF_ADDROF_INFO, crate::reference::DEREF_ADDROF_INFO,
crate::regex::INVALID_REGEX_INFO, crate::regex::INVALID_REGEX_INFO,
crate::regex::TRIVIAL_REGEX_INFO, crate::regex::TRIVIAL_REGEX_INFO,
crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO, crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO, crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO, crate::returns::LET_AND_RETURN_INFO,
@ -678,6 +681,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::unicode::INVISIBLE_CHARACTERS_INFO, crate::unicode::INVISIBLE_CHARACTERS_INFO,
crate::unicode::NON_ASCII_LITERAL_INFO, crate::unicode::NON_ASCII_LITERAL_INFO,
crate::unicode::UNICODE_NOT_NFC_INFO, crate::unicode::UNICODE_NOT_NFC_INFO,
crate::uninhabited_references::UNINHABITED_REFERENCES_INFO,
crate::uninit_vec::UNINIT_VEC_INFO, crate::uninit_vec::UNINIT_VEC_INFO,
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO, crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
crate::unit_types::LET_UNIT_VALUE_INFO, crate::unit_types::LET_UNIT_VALUE_INFO,

View file

@ -9,11 +9,21 @@ use url::Url;
use crate::doc::DOC_MARKDOWN; use crate::doc::DOC_MARKDOWN;
pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) { pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
for word in text.split(|c: char| c.is_whitespace() || c == '\'') { for orig_word in text.split(|c: char| c.is_whitespace() || c == '\'') {
// Trim punctuation as in `some comment (see foo::bar).` // Trim punctuation as in `some comment (see foo::bar).`
// ^^ // ^^
// Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); let trim_pattern = |c: char| !c.is_alphanumeric() && c != ':';
let mut word = orig_word.trim_end_matches(trim_pattern);
// If word is immediately followed by `()`, claw it back.
if let Some(tmp_word) = orig_word.get(..word.len() + 2)
&& tmp_word.ends_with("()")
{
word = tmp_word;
}
word = word.trim_start_matches(trim_pattern);
// Remove leading or trailing single `:` which may be part of a sentence. // Remove leading or trailing single `:` which may be part of a sentence.
if word.starts_with(':') && !word.starts_with("::") { if word.starts_with(':') && !word.starts_with("::") {
@ -84,7 +94,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
return; return;
} }
if has_underscore(word) || word.contains("::") || is_camel_case(word) { if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
span_lint_and_then( span_lint_and_then(

View file

@ -15,7 +15,7 @@ declare_clippy_lint! {
/// replaced with `(e)print!()` / `(e)println!()` /// replaced with `(e)print!()` / `(e)println!()`
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// Using `(e)println! is clearer and more concise /// Using `(e)println!` is clearer and more concise
/// ///
/// ### Example /// ### Example
/// ```no_run /// ```no_run

View file

@ -194,7 +194,12 @@ fn is_same_generics<'tcx>(
.enumerate() .enumerate()
.skip(1) // skip `Self` implicit arg .skip(1) // skip `Self` implicit arg
.all(|(arg_index, arg)| { .all(|(arg_index, arg)| {
if [implied_by_generics.host_effect_index, implied_generics.host_effect_index].contains(&Some(arg_index)) { if [
implied_by_generics.host_effect_index,
implied_generics.host_effect_index,
]
.contains(&Some(arg_index))
{
// skip host effect params in determining whether generics are same // skip host effect params in determining whether generics are same
return true; return true;
} }

View file

@ -0,0 +1,95 @@
use crate::methods::method_call;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::peel_blocks;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
/// ### What it does
/// Checks if both `.write(true)` and `.append(true)` methods are called
/// on a same `OpenOptions`.
///
/// ### Why is this bad?
/// `.append(true)` already enables `write(true)`, making this one
/// superflous.
///
/// ### Example
/// ```no_run
/// # use std::fs::OpenOptions;
/// let _ = OpenOptions::new()
/// .write(true)
/// .append(true)
/// .create(true)
/// .open("file.json");
/// ```
/// Use instead:
/// ```no_run
/// # use std::fs::OpenOptions;
/// let _ = OpenOptions::new()
/// .append(true)
/// .create(true)
/// .open("file.json");
/// ```
#[clippy::version = "1.76.0"]
pub INEFFECTIVE_OPEN_OPTIONS,
suspicious,
"usage of both `write(true)` and `append(true)` on same `OpenOptions`"
}
declare_lint_pass!(IneffectiveOpenOptions => [INEFFECTIVE_OPEN_OPTIONS]);
fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> {
if let [arg] = args
&& let ExprKind::Lit(lit) = peel_blocks(arg).kind
&& lit.node == LitKind::Bool(true)
{
// The `.` is not included in the span so we cheat a little bit to include it as well.
Some(call_span.with_lo(call_span.lo() - BytePos(1)))
} else {
None
}
}
impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else {
return;
};
let receiver_ty = cx.typeck_results().expr_ty(receiver);
match receiver_ty.peel_refs().kind() {
ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::FsOpenOptions, adt.did()) => {},
_ => return,
}
let mut append = None;
let mut write = None;
while let Some((name, recv, args, _, span)) = method_call(receiver) {
if name == "append" {
append = index_if_arg_is_boolean(args, span);
} else if name == "write" {
write = index_if_arg_is_boolean(args, span);
}
receiver = recv;
}
if let Some(write_span) = write
&& append.is_some()
{
span_lint_and_sugg(
cx,
INEFFECTIVE_OPEN_OPTIONS,
write_span,
"unnecessary use of `.write(true)` because there is `.append(true)`",
"remove `.write(true)`",
String::new(),
Applicability::MachineApplicable,
);
}
}
}

View file

@ -50,6 +50,8 @@ extern crate clippy_utils;
#[macro_use] #[macro_use]
extern crate declare_clippy_lint; extern crate declare_clippy_lint;
use std::collections::BTreeMap;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{Lint, LintId}; use rustc_lint::{Lint, LintId};
@ -74,7 +76,7 @@ mod assertions_on_result_states;
mod async_yields_async; mod async_yields_async;
mod attrs; mod attrs;
mod await_holding_invalid; mod await_holding_invalid;
mod blocks_in_if_conditions; mod blocks_in_conditions;
mod bool_assert_comparison; mod bool_assert_comparison;
mod bool_to_int_with_if; mod bool_to_int_with_if;
mod booleans; mod booleans;
@ -153,6 +155,7 @@ mod implied_bounds_in_impls;
mod inconsistent_struct_constructor; mod inconsistent_struct_constructor;
mod index_refutable_slice; mod index_refutable_slice;
mod indexing_slicing; mod indexing_slicing;
mod ineffective_open_options;
mod infinite_iter; mod infinite_iter;
mod inherent_impl; mod inherent_impl;
mod inherent_to_string; mod inherent_to_string;
@ -289,6 +292,7 @@ mod ref_option_ref;
mod ref_patterns; mod ref_patterns;
mod reference; mod reference;
mod regex; mod regex;
mod repeat_vec_with_capacity;
mod reserve_after_initialization; mod reserve_after_initialization;
mod return_self_not_must_use; mod return_self_not_must_use;
mod returns; mod returns;
@ -325,6 +329,7 @@ mod tuple_array_conversions;
mod types; mod types;
mod undocumented_unsafe_blocks; mod undocumented_unsafe_blocks;
mod unicode; mod unicode;
mod uninhabited_references;
mod uninit_vec; mod uninit_vec;
mod unit_return_expecting_ord; mod unit_return_expecting_ord;
mod unit_types; mod unit_types;
@ -653,7 +658,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default()); store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
store.register_late_pass(|_| Box::new(len_zero::LenZero)); store.register_late_pass(|_| Box::new(len_zero::LenZero));
store.register_late_pass(|_| Box::new(attrs::Attributes)); store.register_late_pass(|_| Box::new(attrs::Attributes));
store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions));
store.register_late_pass(|_| Box::new(unicode::Unicode)); store.register_late_pass(|_| Box::new(unicode::Unicode));
store.register_late_pass(|_| Box::new(uninit_vec::UninitVec)); store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
@ -722,6 +727,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
Box::new(vec::UselessVec { Box::new(vec::UselessVec {
too_large_for_stack, too_large_for_stack,
msrv: msrv(), msrv: msrv(),
span_to_lint_map: BTreeMap::new(),
}) })
}); });
store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
@ -1069,6 +1075,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType)); store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)); store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
// add lints here, do not remove this comment, it's used in `new_lint` // add lints here, do not remove this comment, it's used in `new_lint`
} }

View file

@ -0,0 +1,125 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{fn_def_id, is_lint_allowed};
use hir::intravisit::{walk_expr, Visitor};
use hir::{Expr, ExprKind, FnRetTy, FnSig, Node};
use rustc_ast::Label;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use super::INFINITE_LOOP;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &Expr<'_>,
loop_block: &'tcx hir::Block<'_>,
label: Option<Label>,
) {
if is_lint_allowed(cx, INFINITE_LOOP, expr.hir_id) {
return;
}
// Skip check if this loop is not in a function/method/closure. (In some weird case)
let Some(parent_fn_ret) = get_parent_fn_ret_ty(cx, expr) else {
return;
};
// Or, its parent function is already returning `Never`
if matches!(
parent_fn_ret,
FnRetTy::Return(hir::Ty {
kind: hir::TyKind::Never,
..
})
) {
return;
}
let mut loop_visitor = LoopVisitor {
cx,
label,
is_finite: false,
loop_depth: 0,
};
loop_visitor.visit_block(loop_block);
let is_finite_loop = loop_visitor.is_finite;
if !is_finite_loop {
span_lint_and_then(cx, INFINITE_LOOP, expr.span, "infinite loop detected", |diag| {
if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret {
diag.span_suggestion(
ret_span,
"if this is intentional, consider specifing `!` as function return",
" -> !",
Applicability::MaybeIncorrect,
);
} else {
diag.help("if this is not intended, try adding a `break` or `return` condition in the loop");
}
});
}
}
fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> {
for (_, parent_node) in cx.tcx.hir().parent_iter(expr.hir_id) {
match parent_node {
Node::Item(hir::Item {
kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _),
..
})
| Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(FnSig { decl, .. }, _),
..
})
| Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(FnSig { decl, .. }, _),
..
})
| Node::Expr(Expr {
kind: ExprKind::Closure(hir::Closure { fn_decl: decl, .. }),
..
}) => return Some(decl.output),
_ => (),
}
}
None
}
struct LoopVisitor<'hir, 'tcx> {
cx: &'hir LateContext<'tcx>,
label: Option<Label>,
loop_depth: usize,
is_finite: bool,
}
impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> {
fn visit_expr(&mut self, ex: &'hir Expr<'_>) {
match &ex.kind {
ExprKind::Break(hir::Destination { label, .. }, ..) => {
// Assuming breaks the loop when `loop_depth` is 0,
// as it could only means this `break` breaks current loop or any of its upper loop.
// Or, the depth is not zero but the label is matched.
if self.loop_depth == 0 || (label.is_some() && *label == self.label) {
self.is_finite = true;
}
},
ExprKind::Ret(..) => self.is_finite = true,
ExprKind::Loop(..) => {
self.loop_depth += 1;
walk_expr(self, ex);
self.loop_depth = self.loop_depth.saturating_sub(1);
},
_ => {
// Calls to a function that never return
if let Some(did) = fn_def_id(self.cx, ex) {
let fn_ret_ty = self.cx.tcx.fn_sig(did).skip_binder().output().skip_binder();
if fn_ret_ty.is_never() {
self.is_finite = true;
return;
}
}
walk_expr(self, ex);
},
}
}
}

View file

@ -3,6 +3,7 @@ mod explicit_counter_loop;
mod explicit_into_iter_loop; mod explicit_into_iter_loop;
mod explicit_iter_loop; mod explicit_iter_loop;
mod for_kv_map; mod for_kv_map;
mod infinite_loop;
mod iter_next_loop; mod iter_next_loop;
mod manual_find; mod manual_find;
mod manual_flatten; mod manual_flatten;
@ -635,6 +636,48 @@ declare_clippy_lint! {
"checking for emptiness of a `Vec` in the loop condition and popping an element in the body" "checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
} }
declare_clippy_lint! {
/// ### What it does
/// Checks for infinite loops in a function where the return type is not `!`
/// and lint accordingly.
///
/// ### Why is this bad?
/// A loop should be gently exited somewhere, or at least mark its parent function as
/// never return (`!`).
///
/// ### Example
/// ```no_run,ignore
/// fn run_forever() {
/// loop {
/// // do something
/// }
/// }
/// ```
/// If infinite loops are as intended:
/// ```no_run,ignore
/// fn run_forever() -> ! {
/// loop {
/// // do something
/// }
/// }
/// ```
/// Otherwise add a `break` or `return` condition:
/// ```no_run,ignore
/// fn run_forever() {
/// loop {
/// // do something
/// if condition {
/// break;
/// }
/// }
/// }
/// ```
#[clippy::version = "1.75.0"]
pub INFINITE_LOOP,
restriction,
"possibly unintended infinite loop"
}
pub struct Loops { pub struct Loops {
msrv: Msrv, msrv: Msrv,
enforce_iter_loop_reborrow: bool, enforce_iter_loop_reborrow: bool,
@ -669,6 +712,7 @@ impl_lint_pass!(Loops => [
MANUAL_FIND, MANUAL_FIND,
MANUAL_WHILE_LET_SOME, MANUAL_WHILE_LET_SOME,
UNUSED_ENUMERATE_INDEX, UNUSED_ENUMERATE_INDEX,
INFINITE_LOOP,
]); ]);
impl<'tcx> LateLintPass<'tcx> for Loops { impl<'tcx> LateLintPass<'tcx> for Loops {
@ -707,10 +751,11 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
// check for `loop { if let {} else break }` that could be `while let` // check for `loop { if let {} else break }` that could be `while let`
// (also matches an explicit "match" instead of "if let") // (also matches an explicit "match" instead of "if let")
// (even if the "match" or "if let" is used for declaration) // (even if the "match" or "if let" is used for declaration)
if let ExprKind::Loop(block, _, LoopSource::Loop, _) = expr.kind { if let ExprKind::Loop(block, label, LoopSource::Loop, _) = expr.kind {
// also check for empty `loop {}` statements, skipping those in #[panic_handler] // also check for empty `loop {}` statements, skipping those in #[panic_handler]
empty_loop::check(cx, expr, block); empty_loop::check(cx, expr, block);
while_let_loop::check(cx, expr, block); while_let_loop::check(cx, expr, block);
infinite_loop::check(cx, expr, block, label);
} }
while_let_on_iterator::check(cx, expr); while_let_on_iterator::check(cx, expr);

View file

@ -13,8 +13,7 @@ use rustc_lint::LateContext;
use rustc_middle::middle::region; use rustc_middle::middle::region;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
use std::iter::{self}; use std::{iter, mem};
use std::mem;
/// Checks for looping over a range and then indexing a sequence with it. /// Checks for looping over a range and then indexing a sequence with it.
/// The iteratee must be a range literal. /// The iteratee must be a range literal.

View file

@ -105,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
// case somebody does that for some reason // case somebody does that for some reason
&& (is_infinity(const_1) && is_neg_infinity(const_2) && (is_infinity(const_1) && is_neg_infinity(const_2)
|| is_neg_infinity(const_1) && is_infinity(const_2)) || is_neg_infinity(const_1) && is_infinity(const_2))
&& !is_from_proc_macro(cx, expr)
&& let Some(local_snippet) = snippet_opt(cx, first.span) && let Some(local_snippet) = snippet_opt(cx, first.span)
{ {
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
@ -113,6 +112,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
(BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite, (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite,
_ => return, _ => return,
}; };
if is_from_proc_macro(cx, expr) {
return;
}
span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| { span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| {
match variant { match variant {

View file

@ -108,18 +108,16 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_
let arg_kind = &args[0].kind; let arg_kind = &args[0].kind;
if let ExprKind::Path(qpath) = &func.kind { if let ExprKind::Path(qpath) = &func.kind {
if let QPath::TypeRelative(_, _) = qpath { // String::from(...) or String::try_from(...)
// String::from(...) or String::try_from(...) if let QPath::TypeRelative(ty, path_seg) = qpath
if let QPath::TypeRelative(ty, path_seg) = qpath && [sym::from, sym::try_from].contains(&path_seg.ident.name)
&& [sym::from, sym::try_from].contains(&path_seg.ident.name) && let TyKind::Path(qpath) = &ty.kind
&& let TyKind::Path(qpath) = &ty.kind && let QPath::Resolved(_, path) = qpath
&& let QPath::Resolved(_, path) = qpath && let [path_seg] = path.segments
&& let [path_seg] = path.segments && path_seg.ident.name == sym::String
&& path_seg.ident.name == sym::String && is_expr_kind_empty_str(arg_kind)
&& is_expr_kind_empty_str(arg_kind) {
{ warn_then_suggest(cx, span);
warn_then_suggest(cx, span);
}
} else if let QPath::Resolved(_, path) = qpath { } else if let QPath::Resolved(_, path) = qpath {
// From::from(...) or TryFrom::try_from(...) // From::from(...) or TryFrom::try_from(...)
if let [path_seg1, path_seg2] = path.segments if let [path_seg1, path_seg2] = path.segments

View file

@ -3906,7 +3906,7 @@ impl_lint_pass!(Methods => [
]); ]);
/// Extracts a method call name, args, and `Span` of the method name. /// Extracts a method call name, args, and `Span` of the method name.
fn method_call<'tcx>( pub fn method_call<'tcx>(
recv: &'tcx hir::Expr<'tcx>, recv: &'tcx hir::Expr<'tcx>,
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> { ) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {

View file

@ -19,10 +19,6 @@ pub(super) fn check<'tcx>(
arg: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>,
simplify_using: &str, simplify_using: &str,
) { ) {
if is_from_proc_macro(cx, expr) {
return;
}
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
@ -32,7 +28,7 @@ pub(super) fn check<'tcx>(
let body = cx.tcx.hir().body(body); let body = cx.tcx.hir().body(body);
let body_expr = &body.value; let body_expr = &body.value;
if usage::BindingUsageFinder::are_params_used(cx, body) { if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
return; return;
} }

View file

@ -15,8 +15,7 @@ use rustc_lint::LateContext;
use rustc_middle::mir::Mutability; use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
TraitPredicate, Ty,
}; };
use rustc_span::{sym, Symbol}; use rustc_span::{sym, Symbol};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@ -359,6 +358,7 @@ fn get_input_traits_and_projections<'tcx>(
(trait_predicates, projection_predicates) (trait_predicates, projection_predicates)
} }
#[expect(clippy::too_many_lines)]
fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool {
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
match node { match node {
@ -387,22 +387,21 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
if let Some((callee_def_id, call_generic_args, recv, call_args)) = if let Some((callee_def_id, call_generic_args, recv, call_args)) =
get_callee_generic_args_and_args(cx, parent_expr) get_callee_generic_args_and_args(cx, parent_expr)
{ {
// FIXME: the `instantiate_identity()` below seems incorrect, since we eventually let bound_fn_sig = cx.tcx.fn_sig(callee_def_id);
// call `tcx.try_instantiate_and_normalize_erasing_regions` further down let fn_sig = bound_fn_sig.skip_binder();
// (i.e., we are explicitly not in the identity context).
let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
&& let Some(param_ty) = fn_sig.inputs().get(arg_index) && let param_ty = fn_sig.input(arg_index).skip_binder()
&& let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind()
// https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021 // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
&& (*param_index as usize) < call_generic_args.len() && (param_index as usize) < call_generic_args.len()
{ {
if fn_sig if fn_sig
.skip_binder()
.inputs() .inputs()
.iter() .iter()
.enumerate() .enumerate()
.filter(|(i, _)| *i != arg_index) .filter(|(i, _)| *i != arg_index)
.any(|(_, ty)| ty.contains(*param_ty)) .any(|(_, ty)| ty.contains(param_ty))
{ {
return false; return false;
} }
@ -414,7 +413,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
.iter() .iter()
.filter(|predicate| { .filter(|predicate| {
if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
&& trait_predicate.trait_ref.self_ty() == *param_ty && trait_predicate.trait_ref.self_ty() == param_ty
{ {
true true
} else { } else {
@ -425,7 +424,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
let new_subst = cx let new_subst = cx
.tcx .tcx
.mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| { .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| {
if i == (*param_index as usize) { if i == param_index as usize {
GenericArg::from(ty) GenericArg::from(ty)
} else { } else {
t t
@ -433,7 +432,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
})); }));
if trait_predicates.any(|predicate| { if trait_predicates.any(|predicate| {
let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst); let predicate = bound_fn_sig.rebind(predicate).instantiate(cx.tcx, new_subst);
let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
!cx.tcx !cx.tcx
.infer_ctxt() .infer_ctxt()
@ -443,12 +442,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
return false; return false;
} }
let output_ty = fn_sig.output(); let output_ty = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output());
if output_ty.contains(*param_ty) { if output_ty.contains(param_ty) {
if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions(
new_subst, new_subst,
cx.param_env, cx.param_env,
EarlyBinder::bind(output_ty), bound_fn_sig.rebind(output_ty),
) { ) {
expr = parent_expr; expr = parent_expr;
ty = new_ty; ty = new_ty;

View file

@ -52,7 +52,7 @@ declare_clippy_lint! {
/// Use instead: /// Use instead:
/// ```no_run /// ```no_run
/// fn sum(v: &[u8]) -> u8 { /// fn sum(v: &[u8]) -> u8 {
/// assert!(v.len() > 4); /// assert!(v.len() > 3);
/// // no bounds checks /// // no bounds checks
/// v[0] + v[1] + v[2] + v[3] /// v[0] + v[1] + v[2] + v[3]
/// } /// }
@ -87,11 +87,14 @@ enum LengthComparison {
LengthLessThanOrEqualInt, LengthLessThanOrEqualInt,
/// `5 <= v.len()` /// `5 <= v.len()`
IntLessThanOrEqualLength, IntLessThanOrEqualLength,
/// `5 == v.len()`
/// `v.len() == 5`
LengthEqualInt,
} }
/// Extracts parts out of a length comparison expression. /// Extracts parts out of a length comparison expression.
/// ///
/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, `v.len()`))` /// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, v.len()))`
fn len_comparison<'hir>( fn len_comparison<'hir>(
bin_op: BinOp, bin_op: BinOp,
left: &'hir Expr<'hir>, left: &'hir Expr<'hir>,
@ -114,6 +117,8 @@ fn len_comparison<'hir>(
(Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, *right as usize, left)), (Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, *right as usize, left)),
(Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, *left as usize, right)), (Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, *left as usize, right)),
(Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, *right as usize, left)), (Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, *right as usize, left)),
(Rel::Eq, int_lit_pat!(left), _) => Some((LengthComparison::LengthEqualInt, *left as usize, right)),
(Rel::Eq, _, int_lit_pat!(right)) => Some((LengthComparison::LengthEqualInt, *right as usize, left)),
_ => None, _ => None,
} }
} }
@ -316,11 +321,11 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
continue; continue;
}; };
match entry { match *entry {
IndexEntry::AssertWithIndex { IndexEntry::AssertWithIndex {
highest_index, highest_index,
asserted_len, asserted_len,
indexes, ref indexes,
comparison, comparison,
assert_span, assert_span,
slice, slice,
@ -343,6 +348,12 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
"assert!({}.len() > {highest_index})", "assert!({}.len() > {highest_index})",
snippet(cx, slice.span, "..") snippet(cx, slice.span, "..")
)), )),
// `highest_index` here is rather a length, so we need to add 1 to it
LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => Some(format!(
"assert!({}.len() == {})",
snippet(cx, slice.span, ".."),
highest_index + 1
)),
_ => None, _ => None,
}; };
@ -354,7 +365,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
indexes, indexes,
|diag| { |diag| {
diag.span_suggestion( diag.span_suggestion(
*assert_span, assert_span,
"provide the highest index that is indexed with", "provide the highest index that is indexed with",
sugg, sugg,
Applicability::MachineApplicable, Applicability::MachineApplicable,
@ -364,7 +375,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
} }
}, },
IndexEntry::IndexWithoutAssert { IndexEntry::IndexWithoutAssert {
indexes, ref indexes,
highest_index, highest_index,
slice, slice,
} if indexes.len() > 1 => { } if indexes.len() > 1 => {

View file

@ -213,7 +213,9 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
if parent_id == cur_id { if parent_id == cur_id {
break; break;
} }
let Some(parent_node) = vis.cx.tcx.opt_hir_node(parent_id) else { break }; let Some(parent_node) = vis.cx.tcx.opt_hir_node(parent_id) else {
break;
};
let stop_early = match parent_node { let stop_early = match parent_node {
Node::Expr(expr) => check_expr(vis, expr), Node::Expr(expr) => check_expr(vis, expr),

View file

@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_copy; use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -169,6 +169,7 @@ fn needless_borrow_count<'tcx>(
) -> usize { ) -> usize {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
let drop_trait_def_id = cx.tcx.lang_items().drop_trait();
let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder(); let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
let predicates = cx.tcx.param_env(fn_id).caller_bounds(); let predicates = cx.tcx.param_env(fn_id).caller_bounds();
@ -223,7 +224,14 @@ fn needless_borrow_count<'tcx>(
// elements are modified each time `check_referent` is called. // elements are modified each time `check_referent` is called.
let mut args_with_referent_ty = callee_args.to_vec(); let mut args_with_referent_ty = callee_args.to_vec();
let mut check_reference_and_referent = |reference, referent| { let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| {
if let ExprKind::Field(base, _) = &referent.kind {
let base_ty = cx.typeck_results().expr_ty(base);
if drop_trait_def_id.map_or(false, |id| implements_trait(cx, base_ty, id, &[])) {
return false;
}
}
let referent_ty = cx.typeck_results().expr_ty(referent); let referent_ty = cx.typeck_results().expr_ty(referent);
if !is_copy(cx, referent_ty) if !is_copy(cx, referent_ty)

View file

@ -44,7 +44,6 @@ impl LateLintPass<'_> for NeedlessIf {
&& block.stmts.is_empty() && block.stmts.is_empty()
&& block.expr.is_none() && block.expr.is_none()
&& !in_external_macro(cx.sess(), expr.span) && !in_external_macro(cx.sess(), expr.span)
&& !is_from_proc_macro(cx, expr)
&& let Some(then_snippet) = snippet_opt(cx, then.span) && let Some(then_snippet) = snippet_opt(cx, then.span)
// Ignore // Ignore
// - empty macro expansions // - empty macro expansions
@ -53,6 +52,7 @@ impl LateLintPass<'_> for NeedlessIf {
// - #[cfg]'d out code // - #[cfg]'d out code
&& then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace())
&& let Some(cond_snippet) = snippet_opt(cx, cond.span) && let Some(cond_snippet) = snippet_opt(cx, cond.span)
&& !is_from_proc_macro(cx, expr)
{ {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,

View file

@ -87,6 +87,17 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
if let StmtKind::Semi(expr) = stmt.kind { if let StmtKind::Semi(expr) = stmt.kind {
// move `expr.span.from_expansion()` ahead
if expr.span.from_expansion() {
return false;
}
let expr = peel_blocks(expr);
if is_operator_overridden(cx, expr) {
// Return `true`, to prevent `check_unnecessary_operation` from
// linting on this statement as well.
return true;
}
if has_no_effect(cx, expr) { if has_no_effect(cx, expr) {
span_lint_hir_and_then( span_lint_hir_and_then(
cx, cx,
@ -153,11 +164,26 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
false false
} }
fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if expr.span.from_expansion() { // It's very hard or impossable to check whether overridden operator have side-effect this lint.
return false; // So, this function assume user-defined operator is overridden with an side-effect.
// The definition of user-defined structure here is ADT-type,
// Althrough this will weaken the ability of this lint, less error lint-fix happen.
match expr.kind {
ExprKind::Binary(..) | ExprKind::Unary(..) => {
// No need to check type of `lhs` and `rhs`
// because if the operator is overridden, at least one operand is ADT type
// reference: rust/compiler/rustc_middle/src/ty/typeck_results.rs: `is_method_call`.
// use this function to check whether operator is overridden in `ExprKind::{Binary, Unary}`.
cx.typeck_results().is_method_call(expr)
},
_ => false,
} }
match peel_blocks(expr).kind { }
fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match expr.kind {
ExprKind::Lit(..) | ExprKind::Closure { .. } => true, ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)), ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),

View file

@ -132,7 +132,11 @@ impl ArithmeticSideEffects {
} }
// Common entry-point to avoid code duplication. // Common entry-point to avoid code duplication.
fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { fn issue_lint<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if is_from_proc_macro(cx, expr) {
return;
}
let msg = "arithmetic operation that can potentially result in unexpected side-effects"; let msg = "arithmetic operation that can potentially result in unexpected side-effects";
span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg); span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
self.expr_span = Some(expr.span); self.expr_span = Some(expr.span);
@ -160,10 +164,10 @@ impl ArithmeticSideEffects {
fn manage_bin_ops<'tcx>( fn manage_bin_ops<'tcx>(
&mut self, &mut self,
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &hir::Expr<'tcx>, expr: &'tcx hir::Expr<'_>,
op: &Spanned<hir::BinOpKind>, op: &Spanned<hir::BinOpKind>,
lhs: &hir::Expr<'tcx>, lhs: &'tcx hir::Expr<'_>,
rhs: &hir::Expr<'tcx>, rhs: &'tcx hir::Expr<'_>,
) { ) {
if constant_simple(cx, cx.typeck_results(), expr).is_some() { if constant_simple(cx, cx.typeck_results(), expr).is_some() {
return; return;
@ -236,10 +240,10 @@ impl ArithmeticSideEffects {
/// provided input. /// provided input.
fn manage_method_call<'tcx>( fn manage_method_call<'tcx>(
&mut self, &mut self,
args: &[hir::Expr<'tcx>], args: &'tcx [hir::Expr<'_>],
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
ps: &hir::PathSegment<'tcx>, ps: &'tcx hir::PathSegment<'_>,
receiver: &hir::Expr<'tcx>, receiver: &'tcx hir::Expr<'_>,
) { ) {
let Some(arg) = args.first() else { let Some(arg) = args.first() else {
return; return;
@ -264,8 +268,8 @@ impl ArithmeticSideEffects {
fn manage_unary_ops<'tcx>( fn manage_unary_ops<'tcx>(
&mut self, &mut self,
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &hir::Expr<'tcx>, expr: &'tcx hir::Expr<'_>,
un_expr: &hir::Expr<'tcx>, un_expr: &'tcx hir::Expr<'_>,
un_op: hir::UnOp, un_op: hir::UnOp,
) { ) {
let hir::UnOp::Neg = un_op else { let hir::UnOp::Neg = un_op else {
@ -287,14 +291,13 @@ impl ArithmeticSideEffects {
fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool {
is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
|| is_from_proc_macro(cx, expr)
|| self.expr_span.is_some() || self.expr_span.is_some()
|| self.const_span.map_or(false, |sp| sp.contains(expr.span)) || self.const_span.map_or(false, |sp| sp.contains(expr.span))
} }
} }
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if self.should_skip_expr(cx, expr) { if self.should_skip_expr(cx, expr) {
return; return;
} }

View file

@ -4,8 +4,9 @@
pub static RENAMED_LINTS: &[(&str, &str)] = &[ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::almost_complete_letter_range", "clippy::almost_complete_range"), ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
("clippy::blacklisted_name", "clippy::disallowed_names"), ("clippy::blacklisted_name", "clippy::disallowed_names"),
("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"),
("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"),
("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"),
("clippy::box_vec", "clippy::box_collection"), ("clippy::box_vec", "clippy::box_collection"),
("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),

View file

@ -0,0 +1,114 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
use clippy_utils::macros::root_macro_call;
use clippy_utils::source::snippet;
use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
/// Looks for patterns such as `vec![Vec::with_capacity(x); n]` or `iter::repeat(Vec::with_capacity(x))`.
///
/// ### Why is this bad?
/// These constructs work by cloning the element, but cloning a `Vec<_>` does not
/// respect the old vector's capacity and effectively discards it.
///
/// This makes `iter::repeat(Vec::with_capacity(x))` especially suspicious because the user most certainly
/// expected that the yielded `Vec<_>` will have the requested capacity, otherwise one can simply write
/// `iter::repeat(Vec::new())` instead and it will have the same effect.
///
/// Similarly for `vec![x; n]`, the element `x` is cloned to fill the vec.
/// Unlike `iter::repeat` however, the vec repeat macro does not have to clone the value `n` times
/// but just `n - 1` times, because it can reuse the passed value for the last slot.
/// That means that the last `Vec<_>` gets the requested capacity but all other ones do not.
///
/// ### Example
/// ```rust
/// # use std::iter;
///
/// let _: Vec<Vec<u8>> = vec![Vec::with_capacity(42); 123];
/// let _: Vec<Vec<u8>> = iter::repeat(Vec::with_capacity(42)).take(123).collect();
/// ```
/// Use instead:
/// ```rust
/// # use std::iter;
///
/// let _: Vec<Vec<u8>> = iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect();
/// // ^^^ this closure executes 123 times
/// // and the vecs will have the expected capacity
/// ```
#[clippy::version = "1.74.0"]
pub REPEAT_VEC_WITH_CAPACITY,
suspicious,
"repeating a `Vec::with_capacity` expression which does not retain capacity"
}
declare_lint_pass!(RepeatVecWithCapacity => [REPEAT_VEC_WITH_CAPACITY]);
fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, sugg_msg: &'static str, sugg: String) {
span_lint_and_then(
cx,
REPEAT_VEC_WITH_CAPACITY,
span,
&format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"),
|diag| {
diag.note(note);
diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect);
},
);
}
/// Checks `vec![Vec::with_capacity(x); n]`
fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let Some(mac_call) = root_macro_call(expr.span)
&& cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id)
&& let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
&& fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
&& !len_expr.span.from_expansion()
&& let Some(Constant::Int(2..)) = constant(cx, cx.typeck_results(), expr_or_init(cx, len_expr))
{
emit_lint(
cx,
expr.span.source_callsite(),
"vec![x; n]",
"only the last `Vec` will have the capacity",
"if you intended to initialize multiple `Vec`s with an initial capacity, try",
format!(
"(0..{}).map(|_| {}).collect::<Vec<_>>()",
snippet(cx, len_expr.span, ""),
snippet(cx, repeat_expr.span, "..")
),
);
}
}
/// Checks `iter::repeat(Vec::with_capacity(x))`
fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) {
if !expr.span.from_expansion()
&& fn_def_id(cx, expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::iter_repeat, did))
&& let ExprKind::Call(_, [repeat_expr]) = expr.kind
&& fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
&& !repeat_expr.span.from_expansion()
{
emit_lint(
cx,
expr.span,
"iter::repeat",
"none of the yielded `Vec`s will have the requested capacity",
"if you intended to create an iterator that yields `Vec`s with an initial capacity, try",
format!("std::iter::repeat_with(|| {})", snippet(cx, repeat_expr.span, "..")),
);
}
}
impl LateLintPass<'_> for RepeatVecWithCapacity {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
check_vec_macro(cx, expr);
check_repeat_fn(cx, expr);
}
}

View file

@ -55,11 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. }) if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
&& let item = cx.tcx.hir().item(id) && let item = cx.tcx.hir().item(id)
&& let ItemKind::Impl(Impl { && let ItemKind::Impl(Impl {
items, items,
of_trait, of_trait,
self_ty, self_ty,
.. ..
}) = &item.kind }) = &item.kind
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
{ {
if !map.contains_key(res) { if !map.contains_key(res) {
@ -75,24 +75,24 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
match of_trait { match of_trait {
Some(trait_ref) => { Some(trait_ref) => {
let mut methods_in_trait: BTreeSet<Symbol> = if let Some(Node::TraitRef(TraitRef { let mut methods_in_trait: BTreeSet<Symbol> =
path, .. if let Some(Node::TraitRef(TraitRef { path, .. })) =
})) = cx.tcx.opt_hir_node(trait_ref.hir_ref_id) cx.tcx.opt_hir_node(trait_ref.hir_ref_id)
&& let Res::Def(DefKind::Trait, did) = path.res && let Res::Def(DefKind::Trait, did) = path.res
{ {
// FIXME: if // FIXME: if
// `rustc_middle::ty::assoc::AssocItems::items` is public, // `rustc_middle::ty::assoc::AssocItems::items` is public,
// we can iterate its keys instead of `in_definition_order`, // we can iterate its keys instead of `in_definition_order`,
// which's more efficient // which's more efficient
cx.tcx cx.tcx
.associated_items(did) .associated_items(did)
.in_definition_order() .in_definition_order()
.filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn))
.map(|assoc_item| assoc_item.name) .map(|assoc_item| assoc_item.name)
.collect() .collect()
} else { } else {
BTreeSet::new() BTreeSet::new()
}; };
let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| { let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
if let Some((impl_span, hir_id)) = existing_name.impl_methods.get(&method_name) { if let Some((impl_span, hir_id)) = existing_name.impl_methods.get(&method_name) {

View file

@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn {
) { ) {
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id)
|| in_external_macro(cx.sess(), span) || in_external_macro(cx.sess(), span)
|| is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span))
|| is_in_test_function(cx.tcx, body.value.hir_id) || is_in_test_function(cx.tcx, body.value.hir_id)
|| is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span))
{ {
return; return;
} }

View file

@ -0,0 +1,84 @@
use clippy_utils::diagnostics::span_lint;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
/// It detects references to uninhabited types, such as `!` and
/// warns when those are either dereferenced or returned from a function.
///
/// ### Why is this bad?
/// Dereferencing a reference to an uninhabited type would create
/// an instance of such a type, which cannot exist. This constitutes
/// undefined behaviour. Such a reference could have been created
/// by `unsafe` code.
///
/// ### Example
/// The following function can return a reference to an uninhabited type
/// (`Infallible`) because it uses `unsafe` code to create it. However,
/// the user of such a function could dereference the return value and
/// trigger an undefined behavior from safe code.
///
/// ```no_run
/// fn create_ref() -> &'static std::convert::Infallible {
/// unsafe { std::mem::transmute(&()) }
/// }
/// ```
#[clippy::version = "1.76.0"]
pub UNINHABITED_REFERENCES,
suspicious,
"reference to uninhabited type"
}
declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]);
impl LateLintPass<'_> for UninhabitedReferences {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if in_external_macro(cx.tcx.sess, expr.span) {
return;
}
if let ExprKind::Unary(UnOp::Deref, _) = expr.kind {
let ty = cx.typeck_results().expr_ty_adjusted(expr);
if ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
span_lint(
cx,
UNINHABITED_REFERENCES,
expr.span,
"dereferencing a reference to an uninhabited type is undefined behavior",
);
}
}
}
fn check_fn(
&mut self,
cx: &LateContext<'_>,
kind: FnKind<'_>,
fndecl: &'_ FnDecl<'_>,
_: &'_ Body<'_>,
span: Span,
_: LocalDefId,
) {
if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) {
return;
}
if let FnRetTy::Return(hir_ty) = fndecl.output
&& let TyKind::Ref(_, mut_ty) = hir_ty.kind
&& hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
{
span_lint(
cx,
UNINHABITED_REFERENCES,
hir_ty.span,
"dereferencing a reference to an uninhabited type would be undefined behavior",
);
}
}
}

View file

@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
}; };
match constructor_symbol { match constructor_symbol {
sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (), sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (),
sym::Err if path.ident.name == sym!(map_err) => (), sym::Err if path.ident.name == sym::map_err => (),
_ => return, _ => return,
} }

View file

@ -28,12 +28,12 @@ use rustc_span::{sym, Loc, Span, Symbol};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use std::collections::{BTreeSet, BinaryHeap}; use std::collections::{BTreeSet, BinaryHeap};
use std::fmt;
use std::fmt::Write as _; use std::fmt::Write as _;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::prelude::*; use std::io::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::{env, fmt};
/// This is the json output file of the lint collector. /// This is the json output file of the lint collector.
const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
@ -415,7 +415,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root
let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}"); let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}");
let mut cmd = Command::new("cargo"); let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
cmd.current_dir(clippy_project_root) cmd.current_dir(clippy_project_root)
.env("CARGO_INCREMENTAL", "0") .env("CARGO_INCREMENTAL", "0")

View file

@ -218,7 +218,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => { Res::Local(hir_id) => {
let parent_id = cx.tcx.hir().parent_id(hir_id); let parent_id = cx.tcx.hir().parent_id(hir_id);
if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir_node(parent_id) { if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.hir_node(parent_id) {
path_to_matched_type(cx, init) path_to_matched_type(cx, init)
} else { } else {
None None
@ -246,7 +246,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> { fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
let &alloc = alloc.provenance().ptrs().values().next()?; let &alloc = alloc.provenance().ptrs().values().next()?;
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) {
(alloc.inner(), ty) (alloc.inner(), ty)
} else { } else {
return None; return None;
@ -264,7 +264,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation
.ptrs() .ptrs()
.values() .values()
.map(|&alloc| { .map(|&alloc| {
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) {
let alloc = alloc.inner(); let alloc = alloc.inner();
str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
.ok() .ok()

View file

@ -1,25 +1,27 @@
use std::collections::BTreeMap;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use clippy_config::msrvs::{self, Msrv}; use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy; use clippy_utils::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, higher, is_trait_method}; use clippy_utils::{get_parent_expr, higher, is_trait_method};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span}; use rustc_span::{sym, DesugaringKind, Span};
#[expect(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
#[derive(Clone)] #[derive(Clone)]
pub struct UselessVec { pub struct UselessVec {
pub too_large_for_stack: u64, pub too_large_for_stack: u64,
pub msrv: Msrv, pub msrv: Msrv,
pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
} }
declare_clippy_lint! { declare_clippy_lint! {
@ -69,64 +71,88 @@ pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
impl<'tcx> LateLintPass<'tcx> for UselessVec { impl<'tcx> LateLintPass<'tcx> for UselessVec {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]` if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
if adjusts_to_slice(cx, expr) // search for `let foo = vec![_]` expressions where all uses of `foo`
&& let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) // adjust to slices or call a method that exist on slices (e.g. len)
{ if let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { // for now ignore locals with type annotations.
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
(SuggestedType::SliceRef(mutability), expr.span) && local.ty.is_none()
} else { && let PatKind::Binding(_, id, ..) = local.pat.kind
// `expr` is the `vec![_]` expansion, so suggest `[_]` && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr.peel_borrows())))
// and also use the span of the actual `vec![_]` expression {
(SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site) let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
}; // allow indexing into a vec and some set of allowed method calls that exist on slices, too
if let Some(parent) = get_parent_expr(cx, expr)
&& (adjusts_to_slice(cx, expr)
|| matches!(parent.kind, ExprKind::Index(..))
|| is_allowed_vec_method(cx, parent))
{
ControlFlow::Continue(())
} else {
ControlFlow::Break(())
}
})
.is_continue();
self.check_vec_macro(cx, &vec_args, span, suggest_slice); let span = expr.span.ctxt().outer_expn_data().call_site;
} if only_slice_uses {
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array);
// search for `let foo = vec![_]` expressions where all uses of `foo`
// adjust to slices or call a method that exist on slices (e.g. len)
if let Some(vec_args) = higher::VecArgs::hir(cx, expr)
&& let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
// for now ignore locals with type annotations.
// this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
&& local.ty.is_none()
&& let PatKind::Binding(_, id, ..) = local.pat.kind
&& is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr)))
{
let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
// allow indexing into a vec and some set of allowed method calls that exist on slices, too
if let Some(parent) = get_parent_expr(cx, expr)
&& (adjusts_to_slice(cx, expr)
|| matches!(parent.kind, ExprKind::Index(..))
|| is_allowed_vec_method(cx, parent))
{
ControlFlow::Continue(())
} else { } else {
ControlFlow::Break(()) self.span_to_lint_map.insert(span, None);
} }
}) }
.is_continue(); // if the local pattern has a specified type, do not lint.
else if let Some(_) = higher::VecArgs::hir(cx, expr)
&& let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
&& local.ty.is_some()
{
let span = expr.span.ctxt().outer_expn_data().call_site;
self.span_to_lint_map.insert(span, None);
}
// search for `for _ in vec![...]`
else if let Some(parent) = get_parent_expr(cx, expr)
&& parent.span.is_desugaring(DesugaringKind::ForLoop)
&& self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
{
// report the error around the `vec!` not inside `<std macros>:`
let span = expr.span.ctxt().outer_expn_data().call_site;
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array);
}
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
else {
let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
(SuggestedType::SliceRef(mutability), expr.span)
} else {
// `expr` is the `vec![_]` expansion, so suggest `[_]`
// and also use the span of the actual `vec![_]` expression
(SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site)
};
if only_slice_uses { if adjusts_to_slice(cx, expr) {
self.check_vec_macro( self.check_vec_macro(cx, &vec_args, span, expr.hir_id, suggest_slice);
cx, } else {
&vec_args, self.span_to_lint_map.insert(span, None);
expr.span.ctxt().outer_expn_data().call_site, }
SuggestedType::Array,
);
} }
} }
}
// search for `for _ in vec![…]` fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) for (span, lint_opt) in &self.span_to_lint_map {
&& let Some(vec_args) = higher::VecArgs::hir(cx, arg) if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
&& self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR) let help_msg = format!(
{ "you can use {} directly",
// report the error around the `vec!` not inside `<std macros>:` match suggest_slice {
let span = arg.span.ctxt().outer_expn_data().call_site; SuggestedType::SliceRef(_) => "a slice",
self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array); SuggestedType::Array => "an array",
}
);
span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
diag.span_suggestion(*span, help_msg, snippet, *applicability);
});
}
} }
} }
@ -134,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum SuggestedType { pub(crate) enum SuggestedType {
/// Suggest using a slice `&[..]` / `&mut [..]` /// Suggest using a slice `&[..]` / `&mut [..]`
SliceRef(Mutability), SliceRef(Mutability),
/// Suggest using an array: `[..]` /// Suggest using an array: `[..]`
@ -147,6 +173,7 @@ impl UselessVec {
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
vec_args: &higher::VecArgs<'tcx>, vec_args: &higher::VecArgs<'tcx>,
span: Span, span: Span,
hir_id: HirId,
suggest_slice: SuggestedType, suggest_slice: SuggestedType,
) { ) {
if span.from_expansion() { if span.from_expansion() {
@ -204,21 +231,9 @@ impl UselessVec {
}, },
}; };
span_lint_and_sugg( self.span_to_lint_map
cx, .entry(span)
USELESS_VEC, .or_insert(Some((hir_id, suggest_slice, snippet, applicability)));
span,
"useless use of `vec!`",
&format!(
"you can use {} directly",
match suggest_slice {
SuggestedType::SliceRef(_) => "a slice",
SuggestedType::Array => "an array",
}
),
snippet,
applicability,
);
} }
} }

View file

@ -206,7 +206,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
) => { ) => {
eq_closure_binder(lb, rb) eq_closure_binder(lb, rb)
&& lc == rc && lc == rc
&& la.map_or(false, |la| la.is_async()) == ra.map_or(false, |ra| ra.is_async()) && la.map_or(false, CoroutineKind::is_async) == ra.map_or(false, CoroutineKind::is_async)
&& lm == rm && lm == rm
&& eq_fn_decl(lf, rf) && eq_fn_decl(lf, rf)
&& eq_expr(le, re) && eq_expr(le, re)
@ -564,13 +564,16 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
} }
fn eq_opt_coroutine_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool { fn eq_opt_coroutine_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool {
match (l, r) { matches!(
(l, r),
(Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. })) (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. }))
| (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. }))
| (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) => true, | (
(None, None) => true, Some(CoroutineKind::AsyncGen { .. }),
_ => false, Some(CoroutineKind::AsyncGen { .. })
} )
| (None, None)
)
} }
pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {

View file

@ -12,14 +12,14 @@
//! code was written, and check if the span contains that text. Note this will only work correctly //! code was written, and check if the span contains that text. Note this will only work correctly
//! if the span is not from a `macro_rules` based macro. //! if the span is not from a `macro_rules` based macro.
use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy}; use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy};
use rustc_ast::token::CommentKind; use rustc_ast::token::CommentKind;
use rustc_ast::AttrStyle; use rustc_ast::AttrStyle;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{ use rustc_hir::{
Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, Impl, ImplItem, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, TraitItemKind, Ty, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem,
TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
}; };
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
@ -33,8 +33,6 @@ use rustc_target::spec::abi::Abi;
pub enum Pat { pub enum Pat {
/// A single string. /// A single string.
Str(&'static str), Str(&'static str),
/// A single string.
OwnedStr(String),
/// Any of the given strings. /// Any of the given strings.
MultiStr(&'static [&'static str]), MultiStr(&'static [&'static str]),
/// Any of the given strings. /// Any of the given strings.
@ -59,14 +57,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
(match start_pat { (match start_pat {
Pat::Str(text) => start_str.starts_with(text), Pat::Str(text) => start_str.starts_with(text),
Pat::OwnedStr(text) => start_str.starts_with(&text),
Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::Sym(sym) => start_str.starts_with(sym.as_str()), Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
} && match end_pat { } && match end_pat {
Pat::Str(text) => end_str.ends_with(text), Pat::Str(text) => end_str.ends_with(text),
Pat::OwnedStr(text) => end_str.starts_with(&text),
Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)), Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::Sym(sym) => end_str.ends_with(sym.as_str()), Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
@ -125,6 +121,8 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
match e.kind { match e.kind {
ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
// Parenthesis are trimmed from the text before the search patterns are matched.
// See: `span_matches_pat`
ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
@ -286,23 +284,17 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
match attr.kind { match attr.kind {
AttrKind::Normal(..) => { AttrKind::Normal(..) => {
let mut pat = if matches!(attr.style, AttrStyle::Outer) { if let Some(ident) = attr.ident() {
(Pat::Str("#["), Pat::Str("]"))
} else {
(Pat::Str("#!["), Pat::Str("]"))
};
if let Some(ident) = attr.ident()
&& let Pat::Str(old_pat) = pat.0
{
// TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of // TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of
// refactoring // refactoring
// NOTE: This will likely have false positives, like `allow = 1` // NOTE: This will likely have false positives, like `allow = 1`
pat.0 = Pat::OwnedMultiStr(vec![ident.to_string(), old_pat.to_owned()]); (
pat.1 = Pat::Str(""); Pat::OwnedMultiStr(vec![ident.to_string(), "#".to_owned()]),
Pat::Str(""),
)
} else {
(Pat::Str("#"), Pat::Str("]"))
} }
pat
}, },
AttrKind::DocComment(_kind @ CommentKind::Line, ..) => { AttrKind::DocComment(_kind @ CommentKind::Line, ..) => {
if matches!(attr.style, AttrStyle::Outer) { if matches!(attr.style, AttrStyle::Outer) {
@ -324,32 +316,42 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
match ty.kind { match ty.kind {
TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")), TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
TyKind::Ptr(MutTy { mutbl, ty }) => ( TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
if mutbl.is_mut() {
Pat::Str("*const")
} else {
Pat::Str("*mut")
},
ty_search_pat(ty).1,
),
TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1), TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
TyKind::BareFn(bare_fn) => ( TyKind::BareFn(bare_fn) => (
Pat::OwnedStr(format!("{}{} fn", bare_fn.unsafety.prefix_str(), bare_fn.abi.name())), if bare_fn.unsafety == Unsafety::Unsafe {
ty_search_pat(ty).1, Pat::Str("unsafe")
} else if bare_fn.abi != Abi::Rust {
Pat::Str("extern")
} else {
Pat::MultiStr(&["fn", "extern"])
},
match bare_fn.decl.output {
FnRetTy::DefaultReturn(_) => {
if let [.., ty] = bare_fn.decl.inputs {
ty_search_pat(ty).1
} else {
Pat::Str("(")
}
},
FnRetTy::Return(ty) => ty_search_pat(ty).1,
},
), ),
TyKind::Never => (Pat::Str("!"), Pat::Str("")), TyKind::Never => (Pat::Str("!"), Pat::Str("!")),
TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")), // Parenthesis are trimmed from the text before the search patterns are matched.
// See: `span_matches_pat`
TyKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
TyKind::Tup([ty]) => ty_search_pat(ty),
TyKind::Tup([head, .., tail]) => (ty_search_pat(head).0, ty_search_pat(tail).1),
TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
TyKind::Path(qpath) => qpath_search_pat(&qpath), TyKind::Path(qpath) => qpath_search_pat(&qpath),
// NOTE: This is missing `TraitObject`. It will always return true then. TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
TyKind::TraitObject(_, _, TraitObjectSyntax::Dyn) => (Pat::Str("dyn"), Pat::Str("")),
// NOTE: `TraitObject` is incomplete. It will always return true then.
_ => (Pat::Str(""), Pat::Str("")), _ => (Pat::Str(""), Pat::Str("")),
} }
} }
fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
(Pat::OwnedStr(ident.name.as_str().to_owned()), Pat::Str(""))
}
pub trait WithSearchPat<'cx> { pub trait WithSearchPat<'cx> {
type Context: LintContext; type Context: LintContext;
fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
@ -408,7 +410,7 @@ impl<'cx> WithSearchPat<'cx> for Ident {
type Context = LateContext<'cx>; type Context = LateContext<'cx>;
fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) {
ident_search_pat(*self) (Pat::Sym(self.name), Pat::Sym(self.name))
} }
fn span(&self) -> Span { fn span(&self) -> Span {

View file

@ -214,8 +214,17 @@ pub fn implements_trait<'tcx>(
trait_id: DefId, trait_id: DefId,
args: &[GenericArg<'tcx>], args: &[GenericArg<'tcx>],
) -> bool { ) -> bool {
let callee_id = cx.enclosing_body.map(|body| cx.tcx.hir().body_owner(body).owner.to_def_id()); let callee_id = cx
implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) .enclosing_body
.map(|body| cx.tcx.hir().body_owner(body).owner.to_def_id());
implements_trait_with_env_from_iter(
cx.tcx,
cx.param_env,
ty,
trait_id,
callee_id,
args.iter().map(|&x| Some(x)),
)
} }
/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@ -227,7 +236,14 @@ pub fn implements_trait_with_env<'tcx>(
callee_id: DefId, callee_id: DefId,
args: &[GenericArg<'tcx>], args: &[GenericArg<'tcx>],
) -> bool { ) -> bool {
implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, Some(callee_id), args.iter().map(|&x| Some(x))) implements_trait_with_env_from_iter(
tcx,
param_env,
ty,
trait_id,
Some(callee_id),
args.iter().map(|&x| Some(x)),
)
} }
/// Same as `implements_trait_from_env` but takes the arguments as an iterator. /// Same as `implements_trait_from_env` but takes the arguments as an iterator.
@ -248,19 +264,28 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
} }
let infcx = tcx.infer_ctxt().build(); let infcx = tcx.infer_ctxt().build();
let args = args.into_iter().map(|arg| { let args = args
arg.into().unwrap_or_else(|| { .into_iter()
let orig = TypeVariableOrigin { .map(|arg| {
kind: TypeVariableOriginKind::MiscVariable, arg.into().unwrap_or_else(|| {
span: DUMMY_SP, let orig = TypeVariableOrigin {
}; kind: TypeVariableOriginKind::MiscVariable,
infcx.next_ty_var(orig).into() span: DUMMY_SP,
};
infcx.next_ty_var(orig).into()
})
}) })
}).collect::<Vec<_>>(); .collect::<Vec<_>>();
// If an effect arg was not specified, we need to specify it. // If an effect arg was not specified, we need to specify it.
let effect_arg = if tcx.generics_of(trait_id).host_effect_index.is_some_and(|x| args.get(x - 1).is_none()) { let effect_arg = if tcx
Some(GenericArg::from(callee_id.map(|def_id| tcx.expected_host_effect_param_for_body(def_id)).unwrap_or(tcx.consts.true_))) .generics_of(trait_id)
.host_effect_index
.is_some_and(|x| args.get(x - 1).is_none())
{
Some(GenericArg::from(callee_id.map_or(tcx.consts.true_, |def_id| {
tcx.expected_host_effect_param_for_body(def_id)
})))
} else { } else {
None None
}; };
@ -268,9 +293,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
let trait_ref = TraitRef::new( let trait_ref = TraitRef::new(
tcx, tcx,
trait_id, trait_id,
Some(GenericArg::from(ty)) Some(GenericArg::from(ty)).into_iter().chain(args).chain(effect_arg),
.into_iter()
.chain(args).chain(effect_arg),
); );
debug_assert_matches!( debug_assert_matches!(

View file

@ -367,7 +367,7 @@ impl Crate {
// //
// The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates
// (see `crate::driver`) // (see `crate::driver`)
let status = Command::new("cargo") let status = Command::new(env::var("CARGO").unwrap_or("cargo".into()))
.arg("check") .arg("check")
.arg("--quiet") .arg("--quiet")
.current_dir(&self.path) .current_dir(&self.path)
@ -441,7 +441,7 @@ impl Crate {
/// Builds clippy inside the repo to make sure we have a clippy executable we can use. /// Builds clippy inside the repo to make sure we have a clippy executable we can use.
fn build_clippy() { fn build_clippy() {
let status = Command::new("cargo") let status = Command::new(env::var("CARGO").unwrap_or("cargo".into()))
.arg("build") .arg("build")
.status() .status()
.expect("Failed to build clippy!"); .expect("Failed to build clippy!");
@ -816,7 +816,7 @@ fn lintcheck_test() {
"--crates-toml", "--crates-toml",
"lintcheck/test_sources.toml", "lintcheck/test_sources.toml",
]; ];
let status = std::process::Command::new("cargo") let status = std::process::Command::new(env::var("CARGO").unwrap_or("cargo".into()))
.args(args) .args(args)
.current_dir("..") // repo root .current_dir("..") // repo root
.status(); .status();

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2023-12-01" channel = "nightly-2023-12-16"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View file

@ -105,7 +105,7 @@ impl ClippyCmd {
} }
fn into_std_cmd(self) -> Command { fn into_std_cmd(self) -> Command {
let mut cmd = Command::new("cargo"); let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
let clippy_args: String = self let clippy_args: String = self
.clippy_args .clippy_args
.iter() .iter()

View file

@ -12,7 +12,12 @@ fn old_test_headers() {
for entry in WalkDir::new("tests") { for entry in WalkDir::new("tests") {
let entry = entry.unwrap(); let entry = entry.unwrap();
if !entry.file_type().is_file() { let is_hidden_file = entry
.file_name()
.to_str()
.expect("non-UTF-8 file name")
.starts_with('.');
if is_hidden_file || !entry.file_type().is_file() {
continue; continue;
} }

View file

@ -8,4 +8,4 @@ error: `mod.rs` files are required, found `src/bad.rs`
= note: `-D clippy::self-named-module-files` implied by `-D warnings` = note: `-D clippy::self-named-module-files` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]` = help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]`
error: could not compile `fail-mod-remap` (bin "fail-mod-remap") due to previous error error: could not compile `fail-mod-remap` (bin "fail-mod-remap") due to 1 previous error

View file

@ -8,4 +8,4 @@ error: `mod.rs` files are not allowed, found `src/bad/mod.rs`
= note: `-D clippy::mod-module-files` implied by `-D warnings` = note: `-D clippy::mod-module-files` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::mod_module_files)]` = help: to override `-D warnings` add `#[allow(clippy::mod_module_files)]`
error: could not compile `fail-no-mod` (bin "fail-no-mod") due to previous error error: could not compile `fail-no-mod` (bin "fail-no-mod") due to 1 previous error

View file

@ -3,4 +3,4 @@ error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9
= note: `-D clippy::multiple-crate-versions` implied by `-D warnings` = note: `-D clippy::multiple-crate-versions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::multiple_crate_versions)]` = help: to override `-D warnings` add `#[allow(clippy::multiple_crate_versions)]`
error: could not compile `multiple_crate_versions` (bin "multiple_crate_versions") due to previous error error: could not compile `multiple_crate_versions` (bin "multiple_crate_versions") due to 1 previous error

View file

@ -3,4 +3,4 @@ error: wildcard dependency for `regex`
= note: `-D clippy::wildcard-dependencies` implied by `-D warnings` = note: `-D clippy::wildcard-dependencies` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::wildcard_dependencies)]` = help: to override `-D warnings` add `#[allow(clippy::wildcard_dependencies)]`
error: could not compile `wildcard_dependencies` (bin "wildcard_dependencies") due to previous error error: could not compile `wildcard_dependencies` (bin "wildcard_dependencies") due to 1 previous error

View file

@ -9,7 +9,7 @@
#![allow(clippy::never_loop)] #![allow(clippy::never_loop)]
#![allow(clippy::needless_if)] #![allow(clippy::needless_if)]
#![warn(clippy::excessive_nesting)] #![warn(clippy::excessive_nesting)]
#![allow(clippy::collapsible_if)] #![allow(clippy::collapsible_if, clippy::blocks_in_conditions)]
#[macro_use] #[macro_use]
extern crate proc_macros; extern crate proc_macros;

View file

@ -1,5 +1,5 @@
#![deny(clippy::bind_instead_of_map)] #![deny(clippy::bind_instead_of_map)]
#![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::blocks_in_conditions)]
pub fn main() { pub fn main() {
let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() });

View file

@ -1,5 +1,5 @@
#![deny(clippy::bind_instead_of_map)] #![deny(clippy::bind_instead_of_map)]
#![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::blocks_in_conditions)]
pub fn main() { pub fn main() {
let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) }); let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) });

View file

@ -1,4 +1,4 @@
#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_conditions)]
#![allow(unused, clippy::let_and_return, clippy::needless_if)] #![allow(unused, clippy::let_and_return, clippy::needless_if)]
#![warn(clippy::nonminimal_bool)] #![warn(clippy::nonminimal_bool)]
@ -21,6 +21,7 @@ fn macro_if() {
fn condition_has_block() -> i32 { fn condition_has_block() -> i32 {
let res = { let res = {
//~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
let x = 3; let x = 3;
x == 3 x == 3
}; if res { }; if res {
@ -32,6 +33,7 @@ fn condition_has_block() -> i32 {
fn condition_has_block_with_single_expression() -> i32 { fn condition_has_block_with_single_expression() -> i32 {
if true { 6 } else { 10 } if true { 6 } else { 10 }
//~^ ERROR: omit braces around single expression condition
} }
fn condition_is_normal() -> i32 { fn condition_is_normal() -> i32 {
@ -61,4 +63,26 @@ fn block_in_assert() {
); );
} }
// issue #11814
fn block_in_match_expr(num: i32) -> i32 {
let res = {
//~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
let opt = Some(2);
opt
}; match res {
Some(0) => 1,
Some(n) => num * 2,
None => 0,
};
match unsafe {
let hearty_hearty_hearty = vec![240, 159, 146, 150];
String::from_utf8_unchecked(hearty_hearty_hearty).as_str()
} {
"💖" => 1,
"what" => 2,
_ => 3,
}
}
fn main() {} fn main() {}

View file

@ -1,4 +1,4 @@
#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_conditions)]
#![allow(unused, clippy::let_and_return, clippy::needless_if)] #![allow(unused, clippy::let_and_return, clippy::needless_if)]
#![warn(clippy::nonminimal_bool)] #![warn(clippy::nonminimal_bool)]
@ -21,6 +21,7 @@ fn macro_if() {
fn condition_has_block() -> i32 { fn condition_has_block() -> i32 {
if { if {
//~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
let x = 3; let x = 3;
x == 3 x == 3
} { } {
@ -32,6 +33,7 @@ fn condition_has_block() -> i32 {
fn condition_has_block_with_single_expression() -> i32 { fn condition_has_block_with_single_expression() -> i32 {
if { true } { 6 } else { 10 } if { true } { 6 } else { 10 }
//~^ ERROR: omit braces around single expression condition
} }
fn condition_is_normal() -> i32 { fn condition_is_normal() -> i32 {
@ -61,4 +63,26 @@ fn block_in_assert() {
); );
} }
// issue #11814
fn block_in_match_expr(num: i32) -> i32 {
match {
//~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
let opt = Some(2);
opt
} {
Some(0) => 1,
Some(n) => num * 2,
None => 0,
};
match unsafe {
let hearty_hearty_hearty = vec![240, 159, 146, 150];
String::from_utf8_unchecked(hearty_hearty_hearty).as_str()
} {
"💖" => 1,
"what" => 2,
_ => 3,
}
}
fn main() {} fn main() {}

View file

@ -1,30 +1,32 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/blocks_in_if_conditions.rs:23:5 --> $DIR/blocks_in_conditions.rs:23:5
| |
LL | / if { LL | / if {
LL | |
LL | | let x = 3; LL | | let x = 3;
LL | | x == 3 LL | | x == 3
LL | | } { LL | | } {
| |_____^ | |_____^
| |
= note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` = note: `-D clippy::blocks-in-conditions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]` = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]`
help: try help: try
| |
LL ~ let res = { LL ~ let res = {
LL +
LL + let x = 3; LL + let x = 3;
LL + x == 3 LL + x == 3
LL ~ }; if res { LL ~ }; if res {
| |
error: omit braces around single expression condition error: omit braces around single expression condition
--> $DIR/blocks_in_if_conditions.rs:34:8 --> $DIR/blocks_in_conditions.rs:35:8
| |
LL | if { true } { 6 } else { 10 } LL | if { true } { 6 } else { 10 }
| ^^^^^^^^ help: try: `true` | ^^^^^^^^ help: try: `true`
error: this boolean expression can be simplified error: this boolean expression can be simplified
--> $DIR/blocks_in_if_conditions.rs:39:8 --> $DIR/blocks_in_conditions.rs:41:8
| |
LL | if true && x == 3 { 6 } else { 10 } LL | if true && x == 3 { 6 } else { 10 }
| ^^^^^^^^^^^^^^ help: try: `x == 3` | ^^^^^^^^^^^^^^ help: try: `x == 3`
@ -32,5 +34,24 @@ LL | if true && x == 3 { 6 } else { 10 }
= note: `-D clippy::nonminimal-bool` implied by `-D warnings` = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
error: aborting due to 3 previous errors error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/blocks_in_conditions.rs:68:5
|
LL | / match {
LL | |
LL | | let opt = Some(2);
LL | | opt
LL | | } {
| |_____^
|
help: try
|
LL ~ let res = {
LL +
LL + let opt = Some(2);
LL + opt
LL ~ }; match res {
|
error: aborting due to 4 previous errors

View file

@ -1,4 +1,4 @@
#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_conditions)]
#![allow( #![allow(
unused, unused,
clippy::let_and_return, clippy::let_and_return,
@ -22,7 +22,7 @@ fn pred_test() {
&& predicate( && predicate(
|x| { |x| {
//~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks
//~| NOTE: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` //~| NOTE: `-D clippy::blocks-in-conditions` implied by `-D warnings`
let target = 3; let target = 3;
x == target x == target
}, },
@ -60,6 +60,23 @@ fn function_with_empty_closure() {
if closure(|| {}) {} if closure(|| {}) {}
} }
// issue #11814
fn match_with_pred() {
let v = 3;
match Some(predicate(
|x| {
//~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks
let target = 3;
x == target
},
v,
)) {
Some(true) => 1,
Some(false) => 2,
None => 3,
};
}
#[rustfmt::skip] #[rustfmt::skip]
fn main() { fn main() {
let mut range = 0..10; let mut range = 0..10;

View file

@ -1,5 +1,5 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/blocks_in_if_conditions_closure.rs:23:17 --> $DIR/blocks_in_conditions_closure.rs:23:17
| |
LL | |x| { LL | |x| {
| _________________^ | _________________^
@ -10,11 +10,11 @@ LL | | x == target
LL | | }, LL | | },
| |_____________^ | |_____________^
| |
= note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` = note: `-D clippy::blocks-in-conditions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]` = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]`
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/blocks_in_if_conditions_closure.rs:34:13 --> $DIR/blocks_in_conditions_closure.rs:34:13
| |
LL | |x| { LL | |x| {
| _____________^ | _____________^
@ -24,5 +24,16 @@ LL | | x == target
LL | | }, LL | | },
| |_________^ | |_________^
error: aborting due to 2 previous errors error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> $DIR/blocks_in_conditions_closure.rs:67:13
|
LL | |x| {
| _____________^
LL | |
LL | | let target = 3;
LL | | x == target
LL | | },
| |_________^
error: aborting due to 3 previous errors

View file

@ -227,3 +227,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: {
/// this checks if the lowerCamelCase issue is fixed /// this checks if the lowerCamelCase issue is fixed
fn issue_11568() {} fn issue_11568() {}
/// There is no try (`do()` or `do_not()`).
fn parenthesized_word() {}

View file

@ -227,3 +227,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: {
/// this checks if the lowerCamelCase issue is fixed /// this checks if the lowerCamelCase issue is fixed
fn issue_11568() {} fn issue_11568() {}
/// There is no try (do() or do_not()).
fn parenthesized_word() {}

View file

@ -319,5 +319,27 @@ help: try
LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint`
| ~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~
error: aborting due to 29 previous errors error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:231:22
|
LL | /// There is no try (do() or do_not()).
| ^^^^
|
help: try
|
LL | /// There is no try (`do()` or do_not()).
| ~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:231:30
|
LL | /// There is no try (do() or do_not()).
| ^^^^^^^^
|
help: try
|
LL | /// There is no try (do() or `do_not()`).
| ~~~~~~~~~~
error: aborting due to 31 previous errors

View file

@ -1,6 +1,6 @@
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
#![allow(clippy::let_unit_value)] #![allow(clippy::let_unit_value, clippy::needless_pass_by_ref_mut)]
extern crate proc_macros; extern crate proc_macros;
use proc_macros::external; use proc_macros::external;

View file

@ -0,0 +1,41 @@
#![warn(clippy::ineffective_open_options)]
use std::fs::OpenOptions;
fn main() {
let file = OpenOptions::new()
.create(true)
//~ ERROR: unnecessary use of `.write(true)`
.append(true)
.open("dump.json")
.unwrap();
let file = OpenOptions::new()
.create(true)
.append(true)
//~ ERROR: unnecessary use of `.write(true)`
.open("dump.json")
.unwrap();
// All the next calls are ok.
let file = OpenOptions::new()
.create(true)
.write(false)
.append(true)
.open("dump.json")
.unwrap();
let file = OpenOptions::new()
.create(true)
.write(true)
.append(false)
.open("dump.json")
.unwrap();
let file = OpenOptions::new()
.create(true)
.write(false)
.append(false)
.open("dump.json")
.unwrap();
let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap();
let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap();
}

View file

@ -0,0 +1,41 @@
#![warn(clippy::ineffective_open_options)]
use std::fs::OpenOptions;
fn main() {
let file = OpenOptions::new()
.create(true)
.write(true) //~ ERROR: unnecessary use of `.write(true)`
.append(true)
.open("dump.json")
.unwrap();
let file = OpenOptions::new()
.create(true)
.append(true)
.write(true) //~ ERROR: unnecessary use of `.write(true)`
.open("dump.json")
.unwrap();
// All the next calls are ok.
let file = OpenOptions::new()
.create(true)
.write(false)
.append(true)
.open("dump.json")
.unwrap();
let file = OpenOptions::new()
.create(true)
.write(true)
.append(false)
.open("dump.json")
.unwrap();
let file = OpenOptions::new()
.create(true)
.write(false)
.append(false)
.open("dump.json")
.unwrap();
let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap();
let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap();
}

View file

@ -0,0 +1,17 @@
error: unnecessary use of `.write(true)` because there is `.append(true)`
--> $DIR/ineffective_open_options.rs:8:9
|
LL | .write(true)
| ^^^^^^^^^^^^ help: remove `.write(true)`
|
= note: `-D clippy::ineffective-open-options` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::ineffective_open_options)]`
error: unnecessary use of `.write(true)` because there is `.append(true)`
--> $DIR/ineffective_open_options.rs:16:9
|
LL | .write(true)
| ^^^^^^^^^^^^ help: remove `.write(true)`
error: aborting due to 2 previous errors

View file

@ -1,6 +1,6 @@
#![feature(exhaustive_patterns, never_type)] #![feature(exhaustive_patterns, never_type)]
#![allow(dead_code, unreachable_code, unused_variables)] #![allow(dead_code, unreachable_code, unused_variables)]
#![allow(clippy::let_and_return)] #![allow(clippy::let_and_return, clippy::uninhabited_references)]
enum SingleVariantEnum { enum SingleVariantEnum {
Variant(i32), Variant(i32),

View file

@ -1,6 +1,6 @@
#![feature(exhaustive_patterns, never_type)] #![feature(exhaustive_patterns, never_type)]
#![allow(dead_code, unreachable_code, unused_variables)] #![allow(dead_code, unreachable_code, unused_variables)]
#![allow(clippy::let_and_return)] #![allow(clippy::let_and_return, clippy::uninhabited_references)]
enum SingleVariantEnum { enum SingleVariantEnum {
Variant(i32), Variant(i32),

366
tests/ui/infinite_loops.rs Normal file
View file

@ -0,0 +1,366 @@
//@no-rustfix
#![allow(clippy::never_loop)]
#![warn(clippy::infinite_loop)]
fn do_something() {}
fn no_break() {
loop {
//~^ ERROR: infinite loop detected
do_something();
}
}
fn all_inf() {
loop {
//~^ ERROR: infinite loop detected
loop {
//~^ ERROR: infinite loop detected
loop {
//~^ ERROR: infinite loop detected
do_something();
}
}
do_something();
}
}
fn no_break_return_some_ty() -> Option<u8> {
loop {
do_something();
return None;
}
loop {
//~^ ERROR: infinite loop detected
do_something();
}
}
fn no_break_never_ret() -> ! {
loop {
do_something();
}
}
fn no_break_never_ret_noise() {
loop {
fn inner_fn() -> ! {
std::process::exit(0);
}
do_something();
}
}
fn has_direct_break_1() {
loop {
do_something();
break;
}
}
fn has_direct_break_2() {
'outer: loop {
do_something();
break 'outer;
}
}
fn has_indirect_break_1(cond: bool) {
'outer: loop {
loop {
if cond {
break 'outer;
}
}
}
}
fn has_indirect_break_2(stop_num: i32) {
'outer: loop {
for x in 0..5 {
if x == stop_num {
break 'outer;
}
}
}
}
fn break_inner_but_not_outer_1(cond: bool) {
loop {
//~^ ERROR: infinite loop detected
loop {
if cond {
break;
}
}
}
}
fn break_inner_but_not_outer_2(cond: bool) {
loop {
//~^ ERROR: infinite loop detected
'inner: loop {
loop {
if cond {
break 'inner;
}
}
}
}
}
fn break_outer_but_not_inner() {
loop {
loop {
//~^ ERROR: infinite loop detected
do_something();
}
break;
}
}
fn can_break_both_inner_and_outer(cond: bool) {
'outer: loop {
loop {
if cond {
break 'outer;
} else {
break;
}
}
}
}
fn break_wrong_loop(cond: bool) {
// 'inner has statement to break 'outer loop, but it was breaked early by a labeled child loop
'outer: loop {
loop {
//~^ ERROR: infinite loop detected
'inner: loop {
loop {
loop {
break 'inner;
}
break 'outer;
}
}
}
}
}
fn has_direct_return(cond: bool) {
loop {
if cond {
return;
}
}
}
fn ret_in_inner(cond: bool) {
loop {
loop {
if cond {
return;
}
}
}
}
enum Foo {
A,
B,
C,
}
fn match_like() {
let opt: Option<u8> = Some(1);
loop {
//~^ ERROR: infinite loop detected
match opt {
Some(v) => {
println!("{v}");
},
None => {
do_something();
},
}
}
loop {
match opt {
Some(v) => {
println!("{v}");
},
None => {
do_something();
break;
},
}
}
let result: Result<u8, u16> = Ok(1);
loop {
let _val = match result {
Ok(1) => 1 + 1,
Ok(v) => v / 2,
Err(_) => return,
};
}
loop {
let Ok(_val) = result else { return };
}
loop {
let Ok(_val) = result.map(|v| 10) else { break };
}
loop {
//~^ ERROR: infinite loop detected
let _x = matches!(result, Ok(v) if v != 0).then_some(0);
}
loop {
//~^ ERROR: infinite loop detected
// This `return` does not return the function, so it doesn't count
let _x = matches!(result, Ok(v) if v != 0).then(|| {
if true {
return;
}
do_something();
});
}
let mut val = 0;
let mut fooc = Foo::C;
loop {
val = match fooc {
Foo::A => 0,
Foo::B => {
fooc = Foo::C;
1
},
Foo::C => break,
};
}
loop {
val = match fooc {
Foo::A => 0,
Foo::B => 1,
Foo::C => {
break;
},
};
}
}
macro_rules! set_or_ret {
($opt:expr, $a:expr) => {{
match $opt {
Some(val) => $a = val,
None => return,
}
}};
}
fn ret_in_macro(opt: Option<u8>) {
let opt: Option<u8> = Some(1);
let mut a: u8 = 0;
loop {
set_or_ret!(opt, a);
}
let res: Result<bool, u8> = Ok(true);
loop {
match res {
Ok(true) => set_or_ret!(opt, a),
_ => do_something(),
}
}
}
fn panic_like_macros_1() {
loop {
do_something();
panic!();
}
}
fn panic_like_macros_2() {
let mut x = 0;
loop {
do_something();
if true {
todo!();
}
}
loop {
do_something();
x += 1;
assert_eq!(x, 0);
}
loop {
do_something();
assert!(x % 2 == 0);
}
loop {
do_something();
match Some(1) {
Some(n) => println!("{n}"),
None => unreachable!("It won't happen"),
}
}
}
fn exit_directly(cond: bool) {
loop {
if cond {
std::process::exit(0);
}
}
}
trait MyTrait {
fn problematic_trait_method() {
loop {
//~^ ERROR: infinite loop detected
do_something();
}
}
fn could_be_problematic();
}
impl MyTrait for String {
fn could_be_problematic() {
loop {
//~^ ERROR: infinite loop detected
do_something();
}
}
}
fn inf_loop_in_closure() {
let _loop_forever = || {
loop {
//~^ ERROR: infinite loop detected
do_something();
}
};
let _somehow_ok = || -> ! {
loop {
do_something();
}
};
}
fn inf_loop_in_res() -> Result<(), i32> {
Ok(loop {
do_something()
})
}
fn main() {}

View file

@ -0,0 +1,259 @@
error: infinite loop detected
--> $DIR/infinite_loops.rs:8:5
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_____^
|
= note: `-D clippy::infinite-loop` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::infinite_loop)]`
help: if this is intentional, consider specifing `!` as function return
|
LL | fn no_break() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:15:5
|
LL | / loop {
LL | |
LL | | loop {
LL | |
... |
LL | | do_something();
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn all_inf() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:17:9
|
LL | / loop {
LL | |
LL | | loop {
LL | |
LL | | do_something();
LL | | }
LL | | }
| |_________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn all_inf() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:19:13
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_____________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn all_inf() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:33:5
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_____^
|
= help: if this is not intended, try adding a `break` or `return` condition in the loop
error: infinite loop detected
--> $DIR/infinite_loops.rs:46:5
|
LL | / loop {
LL | | fn inner_fn() -> ! {
LL | | std::process::exit(0);
LL | | }
LL | | do_something();
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn no_break_never_ret_noise() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:89:5
|
LL | / loop {
LL | |
LL | | loop {
LL | | if cond {
... |
LL | | }
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:100:5
|
LL | / loop {
LL | |
LL | | 'inner: loop {
LL | | loop {
... |
LL | | }
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:114:9
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn break_outer_but_not_inner() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:137:9
|
LL | / loop {
LL | |
LL | | 'inner: loop {
LL | | loop {
... |
LL | | }
LL | | }
| |_________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn break_wrong_loop(cond: bool) -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:177:5
|
LL | / loop {
LL | |
LL | | match opt {
LL | | Some(v) => {
... |
LL | | }
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn match_like() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:218:5
|
LL | / loop {
LL | |
LL | | let _x = matches!(result, Ok(v) if v != 0).then_some(0);
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn match_like() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:223:5
|
LL | / loop {
LL | |
LL | | // This `return` does not return the function, so it doesn't count
LL | | let _x = matches!(result, Ok(v) if v != 0).then(|| {
... |
LL | | });
LL | | }
| |_____^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn match_like() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:328:9
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn problematic_trait_method() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:338:9
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | fn could_be_problematic() -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:347:9
|
LL | / loop {
LL | |
LL | | do_something();
LL | | }
| |_________^
|
help: if this is intentional, consider specifing `!` as function return
|
LL | let _loop_forever = || -> ! {
| ++++
error: infinite loop detected
--> $DIR/infinite_loops.rs:361:8
|
LL | Ok(loop {
| ________^
LL | | do_something()
LL | | })
| |_____^
|
= help: if this is not intended, try adding a `break` or `return` condition in the loop
error: aborting due to 17 previous errors

View file

@ -40,7 +40,7 @@ fn main() {
}; };
} }
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_conditions)]
Some(11).filter(|&x| { Some(11).filter(|&x| {
println!("foo"); println!("foo");
x > 10 && x < 100 x > 10 && x < 100

View file

@ -135,7 +135,7 @@ fn main() {
}; };
} }
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_conditions)]
match Some(11) { match Some(11) {
// Lint, statement is preserved by `.filter` // Lint, statement is preserved by `.filter`
Some(x) => { Some(x) => {

View file

@ -118,4 +118,19 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) {
let _ = v1[0] + v2[1]; let _ = v1[0] + v2[1];
} }
fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
assert!(v1.len() == 3);
assert!(v2.len() == 4);
assert!(v3.len() == 3);
assert!(4 == v4.len());
let _ = v1[0] + v1[1] + v1[2];
//~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
let _ = v2[0] + v2[1] + v2[2];
let _ = v3[0] + v3[1] + v3[2];
//~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
let _ = v4[0] + v4[1] + v4[2];
}
fn main() {} fn main() {}

View file

@ -118,4 +118,19 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) {
let _ = v1[0] + v2[1]; let _ = v1[0] + v2[1];
} }
fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
assert!(v1.len() == 2);
assert!(v2.len() == 4);
assert!(2 == v3.len());
assert!(4 == v4.len());
let _ = v1[0] + v1[1] + v1[2];
//~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
let _ = v2[0] + v2[1] + v2[2];
let _ = v3[0] + v3[1] + v3[2];
//~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the
let _ = v4[0] + v4[1] + v4[2];
}
fn main() {} fn main() {}

View file

@ -249,5 +249,57 @@ LL | let _ = v1[0] + v1[12];
| ^^^^^^ | ^^^^^^
= note: asserting the length before indexing will elide bounds checks = note: asserting the length before indexing will elide bounds checks
error: aborting due to 9 previous errors error: indexing into a slice multiple times with an `assert` that does not cover the highest index
--> $DIR/missing_asserts_for_indexing.rs:127:13
|
LL | assert!(v1.len() == 2);
| ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)`
...
LL | let _ = v1[0] + v1[1] + v1[2];
| ^^^^^^^^^^^^^^^^^^^^^
|
note: slice indexed here
--> $DIR/missing_asserts_for_indexing.rs:127:13
|
LL | let _ = v1[0] + v1[1] + v1[2];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing.rs:127:21
|
LL | let _ = v1[0] + v1[1] + v1[2];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing.rs:127:29
|
LL | let _ = v1[0] + v1[1] + v1[2];
| ^^^^^
= note: asserting the length before indexing will elide bounds checks
error: indexing into a slice multiple times with an `assert` that does not cover the highest index
--> $DIR/missing_asserts_for_indexing.rs:131:13
|
LL | assert!(2 == v3.len());
| ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)`
...
LL | let _ = v3[0] + v3[1] + v3[2];
| ^^^^^^^^^^^^^^^^^^^^^
|
note: slice indexed here
--> $DIR/missing_asserts_for_indexing.rs:131:13
|
LL | let _ = v3[0] + v3[1] + v3[2];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing.rs:131:21
|
LL | let _ = v3[0] + v3[1] + v3[2];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing.rs:131:29
|
LL | let _ = v3[0] + v3[1] + v3[2];
| ^^^^^
= note: asserting the length before indexing will elide bounds checks
error: aborting due to 11 previous errors

View file

@ -284,4 +284,19 @@ fn main() {
{ {
} }
} }
// address of field when operand impl Drop
{
struct CustomDrop(String);
impl Drop for CustomDrop {
fn drop(&mut self) {}
}
fn check_str<P: AsRef<str>>(_to: P) {}
fn test() {
let owner = CustomDrop(String::default());
check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop
}
}
} }

View file

@ -284,4 +284,19 @@ fn main() {
{ {
} }
} }
// address of field when operand impl Drop
{
struct CustomDrop(String);
impl Drop for CustomDrop {
fn drop(&mut self) {}
}
fn check_str<P: AsRef<str>>(_to: P) {}
fn test() {
let owner = CustomDrop(String::default());
check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop
}
}
} }

View file

@ -1,7 +1,7 @@
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
#![feature(let_chains)] #![feature(let_chains)]
#![allow( #![allow(
clippy::blocks_in_if_conditions, clippy::blocks_in_conditions,
clippy::if_same_then_else, clippy::if_same_then_else,
clippy::ifs_same_cond, clippy::ifs_same_cond,
clippy::let_unit_value, clippy::let_unit_value,

View file

@ -1,7 +1,7 @@
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
#![feature(let_chains)] #![feature(let_chains)]
#![allow( #![allow(
clippy::blocks_in_if_conditions, clippy::blocks_in_conditions,
clippy::if_same_then_else, clippy::if_same_then_else,
clippy::ifs_same_cond, clippy::ifs_same_cond,
clippy::let_unit_value, clippy::let_unit_value,

View file

@ -3,7 +3,7 @@
#![allow(unused)] #![allow(unused)]
#![allow( #![allow(
clippy::assign_op_pattern, clippy::assign_op_pattern,
clippy::blocks_in_if_conditions, clippy::blocks_in_conditions,
clippy::let_and_return, clippy::let_and_return,
clippy::let_unit_value, clippy::let_unit_value,
clippy::nonminimal_bool, clippy::nonminimal_bool,

View file

@ -3,7 +3,7 @@
#![allow(unused)] #![allow(unused)]
#![allow( #![allow(
clippy::assign_op_pattern, clippy::assign_op_pattern,
clippy::blocks_in_if_conditions, clippy::blocks_in_conditions,
clippy::let_and_return, clippy::let_and_return,
clippy::let_unit_value, clippy::let_unit_value,
clippy::nonminimal_bool, clippy::nonminimal_bool,

View file

@ -307,6 +307,19 @@ fn filter_copy<T: Copy>(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T)
move |&item| predicate(item) move |&item| predicate(item)
} }
// `is_from_proc_macro` stress tests
fn _empty_tup(x: &mut (())) {}
fn _single_tup(x: &mut ((i32,))) {}
fn _multi_tup(x: &mut ((i32, u32))) {}
fn _fn(x: &mut (fn())) {}
#[rustfmt::skip]
fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
fn _extern_c_fn(x: &mut extern "C" fn()) {}
fn _unsafe_fn(x: &mut unsafe fn()) {}
fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
fn main() { fn main() {
let mut u = 0; let mut u = 0;
let mut v = vec![0]; let mut v = vec![0];

View file

@ -139,5 +139,65 @@ LL | pub async fn closure4(n: &mut usize) {
| |
= warning: changing this function will impact semver compatibility = warning: changing this function will impact semver compatibility
error: aborting due to 21 previous errors error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:311:18
|
LL | fn _empty_tup(x: &mut (())) {}
| ^^^^^^^^^ help: consider changing to: `&()`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:312:19
|
LL | fn _single_tup(x: &mut ((i32,))) {}
| ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:313:18
|
LL | fn _multi_tup(x: &mut ((i32, u32))) {}
| ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:314:11
|
LL | fn _fn(x: &mut (fn())) {}
| ^^^^^^^^^^^ help: consider changing to: `&fn()`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:316:23
|
LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:317:20
|
LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
| ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:318:18
|
LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:319:25
|
LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:320:20
|
LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:321:20
|
LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
error: aborting due to 31 previous errors

View file

@ -9,6 +9,30 @@
clippy::useless_vec clippy::useless_vec
)] )]
use std::fmt::Display;
use std::ops::{Neg, Shl};
struct Cout;
impl<T> Shl<T> for Cout
where
T: Display,
{
type Output = Self;
fn shl(self, rhs: T) -> Self::Output {
println!("{}", rhs);
self
}
}
impl Neg for Cout {
type Output = Self;
fn neg(self) -> Self::Output {
println!("hello world");
self
}
}
struct Unit; struct Unit;
struct Tuple(i32); struct Tuple(i32);
struct Struct { struct Struct {
@ -174,4 +198,11 @@ fn main() {
GreetStruct1("world"); GreetStruct1("world");
GreetStruct2()("world"); GreetStruct2()("world");
GreetStruct3 {}("world"); GreetStruct3 {}("world");
fn n() -> i32 {
42
}
Cout << 142;
-Cout;
} }

View file

@ -1,5 +1,5 @@
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:98:5 --> $DIR/no_effect.rs:122:5
| |
LL | 0; LL | 0;
| ^^ | ^^
@ -8,151 +8,151 @@ LL | 0;
= help: to override `-D warnings` add `#[allow(clippy::no_effect)]` = help: to override `-D warnings` add `#[allow(clippy::no_effect)]`
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:101:5 --> $DIR/no_effect.rs:125:5
| |
LL | s2; LL | s2;
| ^^^ | ^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:103:5 --> $DIR/no_effect.rs:127:5
| |
LL | Unit; LL | Unit;
| ^^^^^ | ^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:105:5 --> $DIR/no_effect.rs:129:5
| |
LL | Tuple(0); LL | Tuple(0);
| ^^^^^^^^^ | ^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:107:5 --> $DIR/no_effect.rs:131:5
| |
LL | Struct { field: 0 }; LL | Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:109:5 --> $DIR/no_effect.rs:133:5
| |
LL | Struct { ..s }; LL | Struct { ..s };
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:111:5 --> $DIR/no_effect.rs:135:5
| |
LL | Union { a: 0 }; LL | Union { a: 0 };
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:113:5 --> $DIR/no_effect.rs:137:5
| |
LL | Enum::Tuple(0); LL | Enum::Tuple(0);
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:115:5 --> $DIR/no_effect.rs:139:5
| |
LL | Enum::Struct { field: 0 }; LL | Enum::Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:117:5 --> $DIR/no_effect.rs:141:5
| |
LL | 5 + 6; LL | 5 + 6;
| ^^^^^^ | ^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:119:5 --> $DIR/no_effect.rs:143:5
| |
LL | *&42; LL | *&42;
| ^^^^^ | ^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:121:5 --> $DIR/no_effect.rs:145:5
| |
LL | &6; LL | &6;
| ^^^ | ^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:123:5 --> $DIR/no_effect.rs:147:5
| |
LL | (5, 6, 7); LL | (5, 6, 7);
| ^^^^^^^^^^ | ^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:125:5 --> $DIR/no_effect.rs:149:5
| |
LL | ..; LL | ..;
| ^^^ | ^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:127:5 --> $DIR/no_effect.rs:151:5
| |
LL | 5..; LL | 5..;
| ^^^^ | ^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:129:5 --> $DIR/no_effect.rs:153:5
| |
LL | ..5; LL | ..5;
| ^^^^ | ^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:131:5 --> $DIR/no_effect.rs:155:5
| |
LL | 5..6; LL | 5..6;
| ^^^^^ | ^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:133:5 --> $DIR/no_effect.rs:157:5
| |
LL | 5..=6; LL | 5..=6;
| ^^^^^^ | ^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:135:5 --> $DIR/no_effect.rs:159:5
| |
LL | [42, 55]; LL | [42, 55];
| ^^^^^^^^^ | ^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:137:5 --> $DIR/no_effect.rs:161:5
| |
LL | [42, 55][1]; LL | [42, 55][1];
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:139:5 --> $DIR/no_effect.rs:163:5
| |
LL | (42, 55).1; LL | (42, 55).1;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:141:5 --> $DIR/no_effect.rs:165:5
| |
LL | [42; 55]; LL | [42; 55];
| ^^^^^^^^^ | ^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:143:5 --> $DIR/no_effect.rs:167:5
| |
LL | [42; 55][13]; LL | [42; 55][13];
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:146:5 --> $DIR/no_effect.rs:170:5
| |
LL | || x += 5; LL | || x += 5;
| ^^^^^^^^^^ | ^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:149:5 --> $DIR/no_effect.rs:173:5
| |
LL | FooString { s: s }; LL | FooString { s: s };
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect error: binding to `_` prefixed variable with no side-effect
--> $DIR/no_effect.rs:151:5 --> $DIR/no_effect.rs:175:5
| |
LL | let _unused = 1; LL | let _unused = 1;
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -161,19 +161,19 @@ LL | let _unused = 1;
= help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]`
error: binding to `_` prefixed variable with no side-effect error: binding to `_` prefixed variable with no side-effect
--> $DIR/no_effect.rs:154:5 --> $DIR/no_effect.rs:178:5
| |
LL | let _penguin = || println!("Some helpful closure"); LL | let _penguin = || println!("Some helpful closure");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect error: binding to `_` prefixed variable with no side-effect
--> $DIR/no_effect.rs:156:5 --> $DIR/no_effect.rs:180:5
| |
LL | let _duck = Struct { field: 0 }; LL | let _duck = Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect error: binding to `_` prefixed variable with no side-effect
--> $DIR/no_effect.rs:158:5 --> $DIR/no_effect.rs:182:5
| |
LL | let _cat = [2, 4, 6, 8][2]; LL | let _cat = [2, 4, 6, 8][2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -71,3 +71,118 @@ fn _msrv_1_38() {
let _ = ptr.cast::<i32>(); let _ = ptr.cast::<i32>();
let _ = mut_ptr.cast::<i32>(); let _ = mut_ptr.cast::<i32>();
} }
#[allow(clippy::unnecessary_cast)]
mod null {
fn use_path_mut() -> *mut u32 {
use std::ptr;
ptr::null_mut::<u32>()
}
fn full_path_mut() -> *mut u32 {
std::ptr::null_mut::<u32>()
}
fn core_path_mut() -> *mut u32 {
use core::ptr;
ptr::null_mut::<u32>()
}
fn full_core_path_mut() -> *mut u32 {
core::ptr::null_mut::<u32>()
}
fn use_path() -> *const u32 {
use std::ptr;
ptr::null::<u32>()
}
fn full_path() -> *const u32 {
std::ptr::null::<u32>()
}
fn core_path() -> *const u32 {
use core::ptr;
ptr::null::<u32>()
}
fn full_core_path() -> *const u32 {
core::ptr::null::<u32>()
}
}
mod null_ptr_infer {
fn use_path_mut() -> *mut u32 {
use std::ptr;
ptr::null_mut()
}
fn full_path_mut() -> *mut u32 {
std::ptr::null_mut()
}
fn core_path_mut() -> *mut u32 {
use core::ptr;
ptr::null_mut()
}
fn full_core_path_mut() -> *mut u32 {
core::ptr::null_mut()
}
fn use_path() -> *const u32 {
use std::ptr;
ptr::null()
}
fn full_path() -> *const u32 {
std::ptr::null()
}
fn core_path() -> *const u32 {
use core::ptr;
ptr::null()
}
fn full_core_path() -> *const u32 {
core::ptr::null()
}
}
mod null_entire_infer {
fn use_path_mut() -> *mut u32 {
use std::ptr;
ptr::null_mut()
}
fn full_path_mut() -> *mut u32 {
std::ptr::null_mut()
}
fn core_path_mut() -> *mut u32 {
use core::ptr;
ptr::null_mut()
}
fn full_core_path_mut() -> *mut u32 {
core::ptr::null_mut()
}
fn use_path() -> *const u32 {
use std::ptr;
ptr::null()
}
fn full_path() -> *const u32 {
std::ptr::null()
}
fn core_path() -> *const u32 {
use core::ptr;
ptr::null()
}
fn full_core_path() -> *const u32 {
core::ptr::null()
}
}

View file

@ -71,3 +71,118 @@ fn _msrv_1_38() {
let _ = ptr as *const i32; let _ = ptr as *const i32;
let _ = mut_ptr as *mut i32; let _ = mut_ptr as *mut i32;
} }
#[allow(clippy::unnecessary_cast)]
mod null {
fn use_path_mut() -> *mut u32 {
use std::ptr;
ptr::null_mut() as *mut u32
}
fn full_path_mut() -> *mut u32 {
std::ptr::null_mut() as *mut u32
}
fn core_path_mut() -> *mut u32 {
use core::ptr;
ptr::null_mut() as *mut u32
}
fn full_core_path_mut() -> *mut u32 {
core::ptr::null_mut() as *mut u32
}
fn use_path() -> *const u32 {
use std::ptr;
ptr::null() as *const u32
}
fn full_path() -> *const u32 {
std::ptr::null() as *const u32
}
fn core_path() -> *const u32 {
use core::ptr;
ptr::null() as *const u32
}
fn full_core_path() -> *const u32 {
core::ptr::null() as *const u32
}
}
mod null_ptr_infer {
fn use_path_mut() -> *mut u32 {
use std::ptr;
ptr::null_mut() as *mut _
}
fn full_path_mut() -> *mut u32 {
std::ptr::null_mut() as *mut _
}
fn core_path_mut() -> *mut u32 {
use core::ptr;
ptr::null_mut() as *mut _
}
fn full_core_path_mut() -> *mut u32 {
core::ptr::null_mut() as *mut _
}
fn use_path() -> *const u32 {
use std::ptr;
ptr::null() as *const _
}
fn full_path() -> *const u32 {
std::ptr::null() as *const _
}
fn core_path() -> *const u32 {
use core::ptr;
ptr::null() as *const _
}
fn full_core_path() -> *const u32 {
core::ptr::null() as *const _
}
}
mod null_entire_infer {
fn use_path_mut() -> *mut u32 {
use std::ptr;
ptr::null_mut() as _
}
fn full_path_mut() -> *mut u32 {
std::ptr::null_mut() as _
}
fn core_path_mut() -> *mut u32 {
use core::ptr;
ptr::null_mut() as _
}
fn full_core_path_mut() -> *mut u32 {
core::ptr::null_mut() as _
}
fn use_path() -> *const u32 {
use std::ptr;
ptr::null() as _
}
fn full_path() -> *const u32 {
std::ptr::null() as _
}
fn core_path() -> *const u32 {
use core::ptr;
ptr::null() as _
}
fn full_core_path() -> *const u32 {
core::ptr::null() as _
}
}

View file

@ -57,5 +57,149 @@ error: `as` casting between raw pointers without changing its mutability
LL | let _ = mut_ptr as *mut i32; LL | let _ = mut_ptr as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
error: aborting due to 9 previous errors error: `as` casting between raw pointers without changing its mutability
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/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
--> $DIR/ptr_as_ptr.rs:186:9
|
LL | core::ptr::null() as _
| ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
error: aborting due to 33 previous errors

View file

@ -112,6 +112,10 @@ fn trivial_regex() {
// #6005: unicode classes in bytes::Regex // #6005: unicode classes in bytes::Regex
let a_byte_of_unicode = BRegex::new(r"\p{C}"); let a_byte_of_unicode = BRegex::new(r"\p{C}");
// start and end word boundry, introduced in regex 0.10
let _ = BRegex::new(r"\<word\>");
let _ = BRegex::new(r"\b{start}word\b{end}");
} }
fn main() { fn main() {

View file

@ -4,7 +4,7 @@
#![allow(clippy::almost_complete_range)] #![allow(clippy::almost_complete_range)]
#![allow(clippy::disallowed_names)] #![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::blocks_in_conditions)]
#![allow(clippy::box_collection)] #![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::cognitive_complexity)] #![allow(clippy::cognitive_complexity)]
@ -54,8 +54,9 @@
#![allow(ambiguous_wide_pointer_comparisons)] #![allow(ambiguous_wide_pointer_comparisons)]
#![warn(clippy::almost_complete_range)] #![warn(clippy::almost_complete_range)]
#![warn(clippy::disallowed_names)] #![warn(clippy::disallowed_names)]
#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_conditions)]
#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_conditions)]
#![warn(clippy::blocks_in_conditions)]
#![warn(clippy::box_collection)] #![warn(clippy::box_collection)]
#![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::redundant_static_lifetimes)]
#![warn(clippy::cognitive_complexity)] #![warn(clippy::cognitive_complexity)]

View file

@ -4,7 +4,7 @@
#![allow(clippy::almost_complete_range)] #![allow(clippy::almost_complete_range)]
#![allow(clippy::disallowed_names)] #![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::blocks_in_conditions)]
#![allow(clippy::box_collection)] #![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::cognitive_complexity)] #![allow(clippy::cognitive_complexity)]
@ -56,6 +56,7 @@
#![warn(clippy::blacklisted_name)] #![warn(clippy::blacklisted_name)]
#![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::block_in_if_condition_stmt)]
#![warn(clippy::blocks_in_if_conditions)]
#![warn(clippy::box_vec)] #![warn(clippy::box_vec)]
#![warn(clippy::const_static_lifetime)] #![warn(clippy::const_static_lifetime)]
#![warn(clippy::cyclomatic_complexity)] #![warn(clippy::cyclomatic_complexity)]

View file

@ -13,335 +13,341 @@ error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_n
LL | #![warn(clippy::blacklisted_name)] LL | #![warn(clippy::blacklisted_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
--> $DIR/rename.rs:57:9 --> $DIR/rename.rs:57:9
| |
LL | #![warn(clippy::block_in_if_condition_expr)] LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
--> $DIR/rename.rs:58:9 --> $DIR/rename.rs:58:9
| |
LL | #![warn(clippy::block_in_if_condition_stmt)] LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
--> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::blocks_in_if_conditions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
--> $DIR/rename.rs:59:9 --> $DIR/rename.rs:60:9
| |
LL | #![warn(clippy::box_vec)] LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
--> $DIR/rename.rs:60:9 --> $DIR/rename.rs:61:9
| |
LL | #![warn(clippy::const_static_lifetime)] LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
--> $DIR/rename.rs:61:9 --> $DIR/rename.rs:62:9
| |
LL | #![warn(clippy::cyclomatic_complexity)] LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
--> $DIR/rename.rs:62:9 --> $DIR/rename.rs:63:9
| |
LL | #![warn(clippy::derive_hash_xor_eq)] LL | #![warn(clippy::derive_hash_xor_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
--> $DIR/rename.rs:63:9 --> $DIR/rename.rs:64:9
| |
LL | #![warn(clippy::disallowed_method)] LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
--> $DIR/rename.rs:64:9 --> $DIR/rename.rs:65:9
| |
LL | #![warn(clippy::disallowed_type)] LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
--> $DIR/rename.rs:65:9 --> $DIR/rename.rs:66:9
| |
LL | #![warn(clippy::eval_order_dependence)] LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
--> $DIR/rename.rs:66:9 --> $DIR/rename.rs:67:9
| |
LL | #![warn(clippy::identity_conversion)] LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
--> $DIR/rename.rs:67:9 --> $DIR/rename.rs:68:9
| |
LL | #![warn(clippy::if_let_some_result)] LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
--> $DIR/rename.rs:68:9 --> $DIR/rename.rs:69:9
| |
LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
--> $DIR/rename.rs:69:9 --> $DIR/rename.rs:70:9
| |
LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
--> $DIR/rename.rs:70:9 --> $DIR/rename.rs:71:9
| |
LL | #![warn(clippy::integer_arithmetic)] LL | #![warn(clippy::integer_arithmetic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
--> $DIR/rename.rs:71:9 --> $DIR/rename.rs:72:9
| |
LL | #![warn(clippy::logic_bug)] LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
--> $DIR/rename.rs:72:9 --> $DIR/rename.rs:73:9
| |
LL | #![warn(clippy::new_without_default_derive)] LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
--> $DIR/rename.rs:73:9 --> $DIR/rename.rs:74:9
| |
LL | #![warn(clippy::option_and_then_some)] LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:74:9 --> $DIR/rename.rs:75:9
| |
LL | #![warn(clippy::option_expect_used)] LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:75:9 --> $DIR/rename.rs:76:9
| |
LL | #![warn(clippy::option_map_unwrap_or)] LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:76:9 --> $DIR/rename.rs:77:9
| |
LL | #![warn(clippy::option_map_unwrap_or_else)] LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:77:9 --> $DIR/rename.rs:78:9
| |
LL | #![warn(clippy::option_unwrap_used)] LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
--> $DIR/rename.rs:78:9 --> $DIR/rename.rs:79:9
| |
LL | #![warn(clippy::ref_in_deref)] LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:79:9 --> $DIR/rename.rs:80:9
| |
LL | #![warn(clippy::result_expect_used)] LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:80:9 --> $DIR/rename.rs:81:9
| |
LL | #![warn(clippy::result_map_unwrap_or_else)] LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:81:9 --> $DIR/rename.rs:82:9
| |
LL | #![warn(clippy::result_unwrap_used)] LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
--> $DIR/rename.rs:82:9 --> $DIR/rename.rs:83:9
| |
LL | #![warn(clippy::single_char_push_str)] LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
--> $DIR/rename.rs:83:9 --> $DIR/rename.rs:84:9
| |
LL | #![warn(clippy::stutter)] LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
--> $DIR/rename.rs:84:9 --> $DIR/rename.rs:85:9
| |
LL | #![warn(clippy::to_string_in_display)] LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
--> $DIR/rename.rs:85:9 --> $DIR/rename.rs:86:9
| |
LL | #![warn(clippy::unwrap_or_else_default)] LL | #![warn(clippy::unwrap_or_else_default)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
--> $DIR/rename.rs:86:9 --> $DIR/rename.rs:87:9
| |
LL | #![warn(clippy::zero_width_space)] LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
--> $DIR/rename.rs:87:9 --> $DIR/rename.rs:88:9
| |
LL | #![warn(clippy::cast_ref_to_mut)] LL | #![warn(clippy::cast_ref_to_mut)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
--> $DIR/rename.rs:88:9 --> $DIR/rename.rs:89:9
| |
LL | #![warn(clippy::clone_double_ref)] LL | #![warn(clippy::clone_double_ref)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
--> $DIR/rename.rs:89:9 --> $DIR/rename.rs:90:9
| |
LL | #![warn(clippy::cmp_nan)] LL | #![warn(clippy::cmp_nan)]
| ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> $DIR/rename.rs:90:9 --> $DIR/rename.rs:91:9
| |
LL | #![warn(clippy::drop_bounds)] LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
--> $DIR/rename.rs:91:9 --> $DIR/rename.rs:92:9
| |
LL | #![warn(clippy::drop_copy)] LL | #![warn(clippy::drop_copy)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
error: lint `clippy::drop_ref` has been renamed to `dropping_references` error: lint `clippy::drop_ref` has been renamed to `dropping_references`
--> $DIR/rename.rs:92:9 --> $DIR/rename.rs:93:9
| |
LL | #![warn(clippy::drop_ref)] LL | #![warn(clippy::drop_ref)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
--> $DIR/rename.rs:93:9 --> $DIR/rename.rs:94:9
| |
LL | #![warn(clippy::fn_null_check)] LL | #![warn(clippy::fn_null_check)]
| ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:94:9 --> $DIR/rename.rs:95:9
| |
LL | #![warn(clippy::for_loop_over_option)] LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:95:9 --> $DIR/rename.rs:96:9
| |
LL | #![warn(clippy::for_loop_over_result)] LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:96:9 --> $DIR/rename.rs:97:9
| |
LL | #![warn(clippy::for_loops_over_fallibles)] LL | #![warn(clippy::for_loops_over_fallibles)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
--> $DIR/rename.rs:97:9 --> $DIR/rename.rs:98:9
| |
LL | #![warn(clippy::forget_copy)] LL | #![warn(clippy::forget_copy)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
error: lint `clippy::forget_ref` has been renamed to `forgetting_references` error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
--> $DIR/rename.rs:98:9 --> $DIR/rename.rs:99:9
| |
LL | #![warn(clippy::forget_ref)] LL | #![warn(clippy::forget_ref)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> $DIR/rename.rs:99:9 --> $DIR/rename.rs:100:9
| |
LL | #![warn(clippy::into_iter_on_array)] LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
--> $DIR/rename.rs:100:9 --> $DIR/rename.rs:101:9
| |
LL | #![warn(clippy::invalid_atomic_ordering)] LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value` error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
--> $DIR/rename.rs:101:9 --> $DIR/rename.rs:102:9
| |
LL | #![warn(clippy::invalid_ref)] LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
--> $DIR/rename.rs:102:9 --> $DIR/rename.rs:103:9
| |
LL | #![warn(clippy::invalid_utf8_in_unchecked)] LL | #![warn(clippy::invalid_utf8_in_unchecked)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
--> $DIR/rename.rs:103:9 --> $DIR/rename.rs:104:9
| |
LL | #![warn(clippy::let_underscore_drop)] LL | #![warn(clippy::let_underscore_drop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
--> $DIR/rename.rs:104:9 --> $DIR/rename.rs:105:9
| |
LL | #![warn(clippy::mem_discriminant_non_enum)] LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> $DIR/rename.rs:105:9 --> $DIR/rename.rs:106:9
| |
LL | #![warn(clippy::panic_params)] LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
--> $DIR/rename.rs:106:9 --> $DIR/rename.rs:107:9
| |
LL | #![warn(clippy::positional_named_format_parameters)] LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
--> $DIR/rename.rs:107:9 --> $DIR/rename.rs:108:9
| |
LL | #![warn(clippy::temporary_cstring_as_ptr)] LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
--> $DIR/rename.rs:108:9 --> $DIR/rename.rs:109:9
| |
LL | #![warn(clippy::undropped_manually_drops)] LL | #![warn(clippy::undropped_manually_drops)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> $DIR/rename.rs:109:9 --> $DIR/rename.rs:110:9
| |
LL | #![warn(clippy::unknown_clippy_lints)] LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels` error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> $DIR/rename.rs:110:9 --> $DIR/rename.rs:111:9
| |
LL | #![warn(clippy::unused_label)] LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
--> $DIR/rename.rs:111:9 --> $DIR/rename.rs:112:9
| |
LL | #![warn(clippy::vtable_address_comparisons)] LL | #![warn(clippy::vtable_address_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
error: aborting due to 57 previous errors error: aborting due to 58 previous errors

View file

@ -0,0 +1,38 @@
#![warn(clippy::repeat_vec_with_capacity)]
fn main() {
{
(0..123).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>();
//~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
}
{
let n = 123;
(0..n).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>();
//~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
}
{
macro_rules! from_macro {
($x:expr) => {
vec![$x; 123];
};
}
// vec expansion is from another macro, don't lint
from_macro!(Vec::<()>::with_capacity(42));
}
{
std::iter::repeat_with(|| Vec::<()>::with_capacity(42));
//~^ ERROR: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity
}
{
macro_rules! from_macro {
($x:expr) => {
std::iter::repeat($x)
};
}
from_macro!(Vec::<()>::with_capacity(42));
}
}

View file

@ -0,0 +1,38 @@
#![warn(clippy::repeat_vec_with_capacity)]
fn main() {
{
vec![Vec::<()>::with_capacity(42); 123];
//~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
}
{
let n = 123;
vec![Vec::<()>::with_capacity(42); n];
//~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
}
{
macro_rules! from_macro {
($x:expr) => {
vec![$x; 123];
};
}
// vec expansion is from another macro, don't lint
from_macro!(Vec::<()>::with_capacity(42));
}
{
std::iter::repeat(Vec::<()>::with_capacity(42));
//~^ ERROR: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity
}
{
macro_rules! from_macro {
($x:expr) => {
std::iter::repeat($x)
};
}
from_macro!(Vec::<()>::with_capacity(42));
}
}

View file

@ -0,0 +1,40 @@
error: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
--> $DIR/repeat_vec_with_capacity.rs:5:9
|
LL | vec![Vec::<()>::with_capacity(42); 123];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only the last `Vec` will have the capacity
= note: `-D clippy::repeat-vec-with-capacity` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::repeat_vec_with_capacity)]`
help: if you intended to initialize multiple `Vec`s with an initial capacity, try
|
LL | (0..123).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
--> $DIR/repeat_vec_with_capacity.rs:11:9
|
LL | vec![Vec::<()>::with_capacity(42); n];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only the last `Vec` will have the capacity
help: if you intended to initialize multiple `Vec`s with an initial capacity, try
|
LL | (0..n).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity
--> $DIR/repeat_vec_with_capacity.rs:26:9
|
LL | std::iter::repeat(Vec::<()>::with_capacity(42));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: none of the yielded `Vec`s will have the requested capacity
help: if you intended to create an iterator that yields `Vec`s with an initial capacity, try
|
LL | std::iter::repeat_with(|| Vec::<()>::with_capacity(42));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 3 previous errors

View file

@ -0,0 +1,22 @@
#![warn(clippy::uninhabited_references)]
#![feature(never_type)]
fn ret_uninh_ref() -> &'static std::convert::Infallible {
unsafe { std::mem::transmute(&()) }
}
macro_rules! ret_something {
($name:ident, $ty:ty) => {
fn $name(x: &$ty) -> &$ty {
&*x
}
};
}
ret_something!(id_u32, u32);
ret_something!(id_never, !);
fn main() {
let x = ret_uninh_ref();
let _ = *x;
}

View file

@ -0,0 +1,39 @@
error: dereferencing a reference to an uninhabited type would be undefined behavior
--> $DIR/uninhabited_references.rs:4:23
|
LL | fn ret_uninh_ref() -> &'static std::convert::Infallible {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::uninhabited-references` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::uninhabited_references)]`
error: dereferencing a reference to an uninhabited type would be undefined behavior
--> $DIR/uninhabited_references.rs:10:30
|
LL | fn $name(x: &$ty) -> &$ty {
| ^^^^
...
LL | ret_something!(id_never, !);
| --------------------------- in this macro invocation
|
= note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
error: dereferencing a reference to an uninhabited type is undefined behavior
--> $DIR/uninhabited_references.rs:11:14
|
LL | &*x
| ^^
...
LL | ret_something!(id_never, !);
| --------------------------- in this macro invocation
|
= note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
error: dereferencing a reference to an uninhabited type is undefined behavior
--> $DIR/uninhabited_references.rs:21:13
|
LL | let _ = *x;
| ^^
error: aborting due to 4 previous errors

View file

@ -7,6 +7,9 @@
)] )]
#![warn(clippy::unnecessary_operation)] #![warn(clippy::unnecessary_operation)]
use std::fmt::Display;
use std::ops::Shl;
struct Tuple(i32); struct Tuple(i32);
struct Struct { struct Struct {
field: i32, field: i32,
@ -50,6 +53,19 @@ fn get_drop_struct() -> DropStruct {
DropStruct { field: 0 } DropStruct { field: 0 }
} }
struct Cout;
impl<T> Shl<T> for Cout
where
T: Display,
{
type Output = Self;
fn shl(self, rhs: T) -> Self::Output {
println!("{}", rhs);
self
}
}
fn main() { fn main() {
get_number(); get_number();
get_number(); get_number();
@ -87,4 +103,7 @@ fn main() {
($($e:expr),*) => {{ $($e;)* }} ($($e:expr),*) => {{ $($e;)* }}
} }
use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one()); use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
// Issue #11885
Cout << 16;
} }

View file

@ -7,6 +7,9 @@
)] )]
#![warn(clippy::unnecessary_operation)] #![warn(clippy::unnecessary_operation)]
use std::fmt::Display;
use std::ops::Shl;
struct Tuple(i32); struct Tuple(i32);
struct Struct { struct Struct {
field: i32, field: i32,
@ -50,6 +53,19 @@ fn get_drop_struct() -> DropStruct {
DropStruct { field: 0 } DropStruct { field: 0 }
} }
struct Cout;
impl<T> Shl<T> for Cout
where
T: Display,
{
type Output = Self;
fn shl(self, rhs: T) -> Self::Output {
println!("{}", rhs);
self
}
}
fn main() { fn main() {
Tuple(get_number()); Tuple(get_number());
Struct { field: get_number() }; Struct { field: get_number() };
@ -91,4 +107,7 @@ fn main() {
($($e:expr),*) => {{ $($e;)* }} ($($e:expr),*) => {{ $($e;)* }}
} }
use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one()); use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
// Issue #11885
Cout << 16;
} }

View file

@ -1,5 +1,5 @@
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:54:5 --> $DIR/unnecessary_operation.rs:70:5
| |
LL | Tuple(get_number()); LL | Tuple(get_number());
| ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
@ -8,103 +8,103 @@ LL | Tuple(get_number());
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:55:5 --> $DIR/unnecessary_operation.rs:71:5
| |
LL | Struct { field: get_number() }; LL | Struct { field: get_number() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:56:5 --> $DIR/unnecessary_operation.rs:72:5
| |
LL | Struct { ..get_struct() }; LL | Struct { ..get_struct() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:57:5 --> $DIR/unnecessary_operation.rs:73:5
| |
LL | Enum::Tuple(get_number()); LL | Enum::Tuple(get_number());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:58:5 --> $DIR/unnecessary_operation.rs:74:5
| |
LL | Enum::Struct { field: get_number() }; LL | Enum::Struct { field: get_number() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:59:5 --> $DIR/unnecessary_operation.rs:75:5
| |
LL | 5 + get_number(); LL | 5 + get_number();
| ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:60:5 --> $DIR/unnecessary_operation.rs:76:5
| |
LL | *&get_number(); LL | *&get_number();
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:61:5 --> $DIR/unnecessary_operation.rs:77:5
| |
LL | &get_number(); LL | &get_number();
| ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:62:5 --> $DIR/unnecessary_operation.rs:78:5
| |
LL | (5, 6, get_number()); LL | (5, 6, get_number());
| ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:63:5 --> $DIR/unnecessary_operation.rs:79:5
| |
LL | get_number()..; LL | get_number()..;
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:64:5 --> $DIR/unnecessary_operation.rs:80:5
| |
LL | ..get_number(); LL | ..get_number();
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:65:5 --> $DIR/unnecessary_operation.rs:81:5
| |
LL | 5..get_number(); LL | 5..get_number();
| ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:66:5 --> $DIR/unnecessary_operation.rs:82:5
| |
LL | [42, get_number()]; LL | [42, get_number()];
| ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:67:5 --> $DIR/unnecessary_operation.rs:83:5
| |
LL | [42, 55][get_usize()]; LL | [42, 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:68:5 --> $DIR/unnecessary_operation.rs:84:5
| |
LL | (42, get_number()).1; LL | (42, get_number()).1;
| ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:69:5 --> $DIR/unnecessary_operation.rs:85:5
| |
LL | [get_number(); 55]; LL | [get_number(); 55];
| ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:70:5 --> $DIR/unnecessary_operation.rs:86:5
| |
LL | [42; 55][get_usize()]; LL | [42; 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:71:5 --> $DIR/unnecessary_operation.rs:87:5
| |
LL | / { LL | / {
LL | | get_number() LL | | get_number()
@ -112,7 +112,7 @@ LL | | };
| |______^ help: statement can be reduced to: `get_number();` | |______^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:74:5 --> $DIR/unnecessary_operation.rs:90:5
| |
LL | / FooString { LL | / FooString {
LL | | s: String::from("blah"), LL | | s: String::from("blah"),

Some files were not shown because too many files have changed in this diff Show more