Merge commit 'a859e5cc1ce100df22346a1005da30532d04de59' into clippyup

This commit is contained in:
Philipp Krones 2023-12-16 14:12:50 +01:00
commit 61f4a73c67
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5
108 changed files with 3063 additions and 636 deletions

View file

@ -206,6 +206,7 @@ jobs:
max-parallel: 6
matrix:
integration:
- 'matthiaskrgr/clippy_ci_panic_test'
- 'rust-lang/cargo'
- 'rust-lang/chalk'
- 'rust-lang/rustfmt'
@ -220,7 +221,6 @@ jobs:
- 'rust-itertools/itertools'
- 'rust-lang-nursery/failure'
- 'rust-lang/log'
- 'matthiaskrgr/clippy_ci_panic_test'
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
[`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
[`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
[`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
@ -5145,9 +5146,11 @@ Released 2018-09-13
[`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
[`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
[`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_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_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
@ -5462,6 +5465,7 @@ Released 2018-09-13
[`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
[`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
[`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
@ -5582,6 +5586,7 @@ Released 2018-09-13
[`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
[`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_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

View file

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

View file

@ -2,8 +2,8 @@
use std::num::ParseIntError;
use std::path::Path;
use std::process::Command;
use std::thread;
use std::time::{Duration, SystemTime};
use std::{env, thread};
/// # Panics
///
@ -16,7 +16,7 @@ pub fn run(port: u16, lint: Option<&String>) -> ! {
loop {
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")
.spawn()
.unwrap()

View file

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

View file

@ -48,11 +48,10 @@
impl<'tcx> LateLintPass<'tcx> for AsConversions {
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) {
return;
}
if let ExprKind::Cast(_, _) = expr.kind {
if let ExprKind::Cast(_, _) = expr.kind
&& !in_external_macro(cx.sess(), expr.span)
&& !is_from_proc_macro(cx, expr)
{
span_lint_and_help(
cx,
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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
&& !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
&& let ref_ty = cx.typeck_results().expr_ty(deref_target)
&& 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 matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..))
@ -75,6 +74,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
return;
}
}
if is_from_proc_macro(cx, e) {
return;
}
span_lint_and_then(
cx,

View file

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

View file

@ -3,12 +3,29 @@
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
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_middle::ty::{self, TypeAndMut};
use rustc_span::sym;
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) {
if !msrv.meets(msrvs::POINTER_CAST) {
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)
{
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 {
TyKind::Infer => String::new(),
TyKind::Ptr(mut_ty) => {
@ -41,13 +57,44 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
_ => 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(
cx,
PTR_AS_PTR,
expr.span,
"`as` casting between raw pointers without changing its mutability",
"try `pointer::cast`, a safer alternative",
format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
help,
final_suggestion,
app,
);
}

View file

@ -63,7 +63,7 @@
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_LOCK_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_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
crate::booleans::NONMINIMAL_BOOL_INFO,
@ -215,6 +215,7 @@
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
crate::indexing_slicing::INDEXING_SLICING_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::MAYBE_INFINITE_ITER_INFO,
crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
@ -265,6 +266,7 @@
crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
crate::loops::EXPLICIT_ITER_LOOP_INFO,
crate::loops::FOR_KV_MAP_INFO,
crate::loops::INFINITE_LOOP_INFO,
crate::loops::ITER_NEXT_LOOP_INFO,
crate::loops::MANUAL_FIND_INFO,
crate::loops::MANUAL_FLATTEN_INFO,
@ -598,6 +600,7 @@
crate::reference::DEREF_ADDROF_INFO,
crate::regex::INVALID_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::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO,
@ -678,6 +681,7 @@
crate::unicode::INVISIBLE_CHARACTERS_INFO,
crate::unicode::NON_ASCII_LITERAL_INFO,
crate::unicode::UNICODE_NOT_NFC_INFO,
crate::uninhabited_references::UNINHABITED_REFERENCES_INFO,
crate::uninit_vec::UNINIT_VEC_INFO,
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
crate::unit_types::LET_UNIT_VALUE_INFO,

View file

@ -9,11 +9,21 @@
use crate::doc::DOC_MARKDOWN;
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).`
// ^^
// 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.
if word.starts_with(':') && !word.starts_with("::") {
@ -84,7 +94,7 @@ fn has_hyphen(s: &str) -> bool {
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;
span_lint_and_then(

View file

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

View file

@ -194,7 +194,12 @@ fn is_same_generics<'tcx>(
.enumerate()
.skip(1) // skip `Self` implicit 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
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 @@
#[macro_use]
extern crate declare_clippy_lint;
use std::collections::BTreeMap;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{Lint, LintId};
@ -74,7 +76,7 @@
mod async_yields_async;
mod attrs;
mod await_holding_invalid;
mod blocks_in_if_conditions;
mod blocks_in_conditions;
mod bool_assert_comparison;
mod bool_to_int_with_if;
mod booleans;
@ -153,6 +155,7 @@
mod inconsistent_struct_constructor;
mod index_refutable_slice;
mod indexing_slicing;
mod ineffective_open_options;
mod infinite_iter;
mod inherent_impl;
mod inherent_to_string;
@ -289,6 +292,7 @@
mod ref_patterns;
mod reference;
mod regex;
mod repeat_vec_with_capacity;
mod reserve_after_initialization;
mod return_self_not_must_use;
mod returns;
@ -325,6 +329,7 @@
mod types;
mod undocumented_unsafe_blocks;
mod unicode;
mod uninhabited_references;
mod uninit_vec;
mod unit_return_expecting_ord;
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::new(len_zero::LenZero));
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(uninit_vec::UninitVec));
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 {
too_large_for_stack,
msrv: msrv(),
span_to_lint_map: BTreeMap::new(),
})
});
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_over_hash_type::IterOverHashType));
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`
}

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_into_iter_loop;
mod explicit_iter_loop;
mod for_kv_map;
mod infinite_loop;
mod iter_next_loop;
mod manual_find;
mod manual_flatten;
@ -635,6 +636,48 @@
"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 {
msrv: Msrv,
enforce_iter_loop_reborrow: bool,
@ -669,6 +712,7 @@ pub fn new(msrv: Msrv, enforce_iter_loop_reborrow: bool) -> Self {
MANUAL_FIND,
MANUAL_WHILE_LET_SOME,
UNUSED_ENUMERATE_INDEX,
INFINITE_LOOP,
]);
impl<'tcx> LateLintPass<'tcx> for Loops {
@ -707,10 +751,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// check for `loop { if let {} else break }` that could be `while let`
// (also matches an explicit "match" instead of "if let")
// (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]
empty_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);

View file

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

View file

@ -105,7 +105,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
// case somebody does that for some reason
&& (is_infinity(const_1) && is_neg_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 variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
@ -113,6 +112,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
(BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite,
_ => return,
};
if is_from_proc_macro(cx, expr) {
return;
}
span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| {
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;
if let ExprKind::Path(qpath) = &func.kind {
if let QPath::TypeRelative(_, _) = qpath {
// String::from(...) or String::try_from(...)
if let QPath::TypeRelative(ty, path_seg) = qpath
&& [sym::from, sym::try_from].contains(&path_seg.ident.name)
&& let TyKind::Path(qpath) = &ty.kind
&& let QPath::Resolved(_, path) = qpath
&& let [path_seg] = path.segments
&& path_seg.ident.name == sym::String
&& is_expr_kind_empty_str(arg_kind)
{
warn_then_suggest(cx, span);
}
// String::from(...) or String::try_from(...)
if let QPath::TypeRelative(ty, path_seg) = qpath
&& [sym::from, sym::try_from].contains(&path_seg.ident.name)
&& let TyKind::Path(qpath) = &ty.kind
&& let QPath::Resolved(_, path) = qpath
&& let [path_seg] = path.segments
&& path_seg.ident.name == sym::String
&& is_expr_kind_empty_str(arg_kind)
{
warn_then_suggest(cx, span);
} else if let QPath::Resolved(_, path) = qpath {
// From::from(...) or TryFrom::try_from(...)
if let [path_seg1, path_seg2] = path.segments

View file

@ -3906,7 +3906,7 @@ pub fn new(
]);
/// 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>,
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
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<'_>,
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_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();
@ -32,7 +28,7 @@ pub(super) fn check<'tcx>(
let body = cx.tcx.hir().body(body);
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;
}

View file

@ -15,8 +15,7 @@
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{
self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate,
TraitPredicate, Ty,
self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
};
use rustc_span::{sym, Symbol};
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)
}
#[expect(clippy::too_many_lines)]
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) {
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)) =
get_callee_generic_args_and_args(cx, parent_expr)
{
// FIXME: the `instantiate_identity()` below seems incorrect, since we eventually
// call `tcx.try_instantiate_and_normalize_erasing_regions` further down
// (i.e., we are explicitly not in the identity context).
let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
let bound_fn_sig = cx.tcx.fn_sig(callee_def_id);
let fn_sig = bound_fn_sig.skip_binder();
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 ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
&& let param_ty = fn_sig.input(arg_index).skip_binder()
&& 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
&& (*param_index as usize) < call_generic_args.len()
&& (param_index as usize) < call_generic_args.len()
{
if fn_sig
.skip_binder()
.inputs()
.iter()
.enumerate()
.filter(|(i, _)| *i != arg_index)
.any(|(_, ty)| ty.contains(*param_ty))
.any(|(_, ty)| ty.contains(param_ty))
{
return false;
}
@ -414,7 +413,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
.iter()
.filter(|predicate| {
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
} 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
.tcx
.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)
} else {
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| {
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);
!cx.tcx
.infer_ctxt()
@ -443,12 +442,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
return false;
}
let output_ty = fn_sig.output();
if output_ty.contains(*param_ty) {
let output_ty = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output());
if output_ty.contains(param_ty) {
if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions(
new_subst,
cx.param_env,
EarlyBinder::bind(output_ty),
bound_fn_sig.rebind(output_ty),
) {
expr = parent_expr;
ty = new_ty;

View file

@ -52,7 +52,7 @@
/// Use instead:
/// ```no_run
/// fn sum(v: &[u8]) -> u8 {
/// assert!(v.len() > 4);
/// assert!(v.len() > 3);
/// // no bounds checks
/// v[0] + v[1] + v[2] + v[3]
/// }
@ -87,11 +87,14 @@ enum LengthComparison {
LengthLessThanOrEqualInt,
/// `5 <= v.len()`
IntLessThanOrEqualLength,
/// `5 == v.len()`
/// `v.len() == 5`
LengthEqualInt,
}
/// 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>(
bin_op: BinOp,
left: &'hir Expr<'hir>,
@ -114,6 +117,8 @@ macro_rules! int_lit_pat {
(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!(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,
}
}
@ -316,11 +321,11 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
continue;
};
match entry {
match *entry {
IndexEntry::AssertWithIndex {
highest_index,
asserted_len,
indexes,
ref indexes,
comparison,
assert_span,
slice,
@ -343,6 +348,12 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
"assert!({}.len() > {highest_index})",
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,
};
@ -354,7 +365,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
indexes,
|diag| {
diag.span_suggestion(
*assert_span,
assert_span,
"provide the highest index that is indexed with",
sugg,
Applicability::MachineApplicable,
@ -364,7 +375,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
}
},
IndexEntry::IndexWithoutAssert {
indexes,
ref indexes,
highest_index,
slice,
} if indexes.len() > 1 => {

View file

@ -213,7 +213,9 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
if parent_id == cur_id {
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 {
Node::Expr(expr) => check_expr(vis, expr),

View file

@ -2,7 +2,7 @@
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::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 rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@ -169,6 +169,7 @@ fn needless_borrow_count<'tcx>(
) -> usize {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_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 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.
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);
if !is_copy(cx, referent_ty)

View file

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

View file

@ -87,6 +87,17 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
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) {
span_lint_hir_and_then(
cx,
@ -153,11 +164,26 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
false
}
fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if expr.span.from_expansion() {
return false;
fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
// It's very hard or impossable to check whether overridden operator have side-effect this lint.
// 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::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),

View file

@ -132,7 +132,11 @@ fn is_integral(ty: Ty<'_>) -> bool {
}
// 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";
span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
self.expr_span = Some(expr.span);
@ -160,10 +164,10 @@ fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
fn manage_bin_ops<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
expr: &hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'_>,
op: &Spanned<hir::BinOpKind>,
lhs: &hir::Expr<'tcx>,
rhs: &hir::Expr<'tcx>,
lhs: &'tcx hir::Expr<'_>,
rhs: &'tcx hir::Expr<'_>,
) {
if constant_simple(cx, cx.typeck_results(), expr).is_some() {
return;
@ -236,10 +240,10 @@ fn manage_bin_ops<'tcx>(
/// provided input.
fn manage_method_call<'tcx>(
&mut self,
args: &[hir::Expr<'tcx>],
args: &'tcx [hir::Expr<'_>],
cx: &LateContext<'tcx>,
ps: &hir::PathSegment<'tcx>,
receiver: &hir::Expr<'tcx>,
ps: &'tcx hir::PathSegment<'_>,
receiver: &'tcx hir::Expr<'_>,
) {
let Some(arg) = args.first() else {
return;
@ -264,8 +268,8 @@ fn manage_method_call<'tcx>(
fn manage_unary_ops<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
expr: &hir::Expr<'tcx>,
un_expr: &hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'_>,
un_expr: &'tcx hir::Expr<'_>,
un_op: hir::UnOp,
) {
let hir::UnOp::Neg = un_op else {
@ -287,14 +291,13 @@ fn manage_unary_ops<'tcx>(
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_from_proc_macro(cx, expr)
|| self.expr_span.is_some()
|| self.const_span.map_or(false, |sp| sp.contains(expr.span))
}
}
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) {
return;
}

View file

@ -4,8 +4,9 @@
pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
("clippy::blacklisted_name", "clippy::disallowed_names"),
("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
("clippy::block_in_if_condition_expr", "clippy::blocks_in_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::const_static_lifetime", "clippy::redundant_static_lifetimes"),
("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 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
&& let item = cx.tcx.hir().item(id)
&& let ItemKind::Impl(Impl {
items,
of_trait,
self_ty,
..
}) = &item.kind
items,
of_trait,
self_ty,
..
}) = &item.kind
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
{
if !map.contains_key(res) {
@ -75,24 +75,24 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
match of_trait {
Some(trait_ref) => {
let mut methods_in_trait: BTreeSet<Symbol> = if let Some(Node::TraitRef(TraitRef {
path, ..
})) = cx.tcx.opt_hir_node(trait_ref.hir_ref_id)
&& let Res::Def(DefKind::Trait, did) = path.res
{
// FIXME: if
// `rustc_middle::ty::assoc::AssocItems::items` is public,
// we can iterate its keys instead of `in_definition_order`,
// which's more efficient
cx.tcx
.associated_items(did)
.in_definition_order()
.filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn))
.map(|assoc_item| assoc_item.name)
.collect()
} else {
BTreeSet::new()
};
let mut methods_in_trait: BTreeSet<Symbol> =
if let Some(Node::TraitRef(TraitRef { path, .. })) =
cx.tcx.opt_hir_node(trait_ref.hir_ref_id)
&& let Res::Def(DefKind::Trait, did) = path.res
{
// FIXME: if
// `rustc_middle::ty::assoc::AssocItems::items` is public,
// we can iterate its keys instead of `in_definition_order`,
// which's more efficient
cx.tcx
.associated_items(did)
.in_definition_order()
.filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn))
.map(|assoc_item| assoc_item.name)
.collect()
} else {
BTreeSet::new()
};
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) {

View file

@ -72,8 +72,8 @@ fn check_fn(
) {
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id)
|| 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_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span))
{
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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
};
match constructor_symbol {
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,
}

View file

@ -28,12 +28,12 @@
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use std::collections::{BTreeSet, BinaryHeap};
use std::fmt;
use std::fmt::Write as _;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, fmt};
/// This is the json output file of the lint collector.
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 mut cmd = Command::new("cargo");
let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
cmd.current_dir(clippy_project_root)
.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) {
Res::Local(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)
} else {
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>> {
let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
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)
} else {
return None;
@ -264,7 +264,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation
.ptrs()
.values()
.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();
str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
.ok()

View file

@ -1,25 +1,27 @@
use std::collections::BTreeMap;
use std::ops::ControlFlow;
use clippy_config::msrvs::{self, Msrv};
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::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, higher, is_trait_method};
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_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span};
use rustc_span::{sym, DesugaringKind, Span};
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
pub struct UselessVec {
pub too_large_for_stack: u64,
pub msrv: Msrv,
pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
}
declare_clippy_lint! {
@ -69,64 +71,88 @@ pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
impl<'tcx> LateLintPass<'tcx> for UselessVec {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
if adjusts_to_slice(cx, expr)
&& let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows())
{
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 let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
// 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 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.peel_borrows())))
{
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);
}
// 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(())
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);
} 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 {
self.check_vec_macro(
cx,
&vec_args,
expr.span.ctxt().outer_expn_data().call_site,
SuggestedType::Array,
);
if adjusts_to_slice(cx, expr) {
self.check_vec_macro(cx, &vec_args, span, expr.hir_id, suggest_slice);
} else {
self.span_to_lint_map.insert(span, None);
}
}
}
}
// search for `for _ in vec![…]`
if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr)
&& let Some(vec_args) = higher::VecArgs::hir(cx, arg)
&& self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
{
// report the error around the `vec!` not inside `<std macros>:`
let span = arg.span.ctxt().outer_expn_data().call_site;
self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array);
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
for (span, lint_opt) in &self.span_to_lint_map {
if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
let help_msg = format!(
"you can use {} directly",
match suggest_slice {
SuggestedType::SliceRef(_) => "a slice",
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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
#[derive(Copy, Clone)]
enum SuggestedType {
pub(crate) enum SuggestedType {
/// Suggest using a slice `&[..]` / `&mut [..]`
SliceRef(Mutability),
/// Suggest using an array: `[..]`
@ -147,6 +173,7 @@ fn check_vec_macro<'tcx>(
cx: &LateContext<'tcx>,
vec_args: &higher::VecArgs<'tcx>,
span: Span,
hir_id: HirId,
suggest_slice: SuggestedType,
) {
if span.from_expansion() {
@ -204,21 +231,9 @@ fn check_vec_macro<'tcx>(
},
};
span_lint_and_sugg(
cx,
USELESS_VEC,
span,
"useless use of `vec!`",
&format!(
"you can use {} directly",
match suggest_slice {
SuggestedType::SliceRef(_) => "a slice",
SuggestedType::Array => "an array",
}
),
snippet,
applicability,
);
self.span_to_lint_map
.entry(span)
.or_insert(Some((hir_id, suggest_slice, snippet, applicability)));
}
}

View file

@ -206,7 +206,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
) => {
eq_closure_binder(lb, rb)
&& 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
&& eq_fn_decl(lf, rf)
&& 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 {
match (l, r) {
matches!(
(l, r),
(Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. }))
| (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. }))
| (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) => true,
(None, None) => true,
_ => false,
}
| (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. }))
| (
Some(CoroutineKind::AsyncGen { .. }),
Some(CoroutineKind::AsyncGen { .. })
)
| (None, None)
)
}
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
//! 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::AttrStyle;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, Impl, ImplItem,
ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, TraitItemKind, Ty,
TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem,
TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::TyCtxt;
@ -33,8 +33,6 @@
pub enum Pat {
/// A single string.
Str(&'static str),
/// A single string.
OwnedStr(String),
/// Any of the given strings.
MultiStr(&'static [&'static str]),
/// 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 == ',');
(match start_pat {
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::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
} && match end_pat {
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::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
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) {
match e.kind {
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::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),
@ -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) {
match attr.kind {
AttrKind::Normal(..) => {
let mut pat = if matches!(attr.style, AttrStyle::Outer) {
(Pat::Str("#["), Pat::Str("]"))
} else {
(Pat::Str("#!["), Pat::Str("]"))
};
if let Some(ident) = attr.ident()
&& let Pat::Str(old_pat) = pat.0
{
if let Some(ident) = attr.ident() {
// TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of
// refactoring
// 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, ..) => {
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) {
match ty.kind {
TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
TyKind::Ptr(MutTy { mutbl, ty }) => (
if mutbl.is_mut() {
Pat::Str("*const")
} else {
Pat::Str("*mut")
},
ty_search_pat(ty).1,
),
TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
TyKind::BareFn(bare_fn) => (
Pat::OwnedStr(format!("{}{} fn", bare_fn.unsafety.prefix_str(), bare_fn.abi.name())),
ty_search_pat(ty).1,
if bare_fn.unsafety == Unsafety::Unsafe {
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::Tup(..) => (Pat::Str("("), Pat::Str(")")),
TyKind::Never => (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::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("")),
}
}
fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
(Pat::OwnedStr(ident.name.as_str().to_owned()), Pat::Str(""))
}
pub trait WithSearchPat<'cx> {
type Context: LintContext;
fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
@ -408,7 +410,7 @@ impl<'cx> WithSearchPat<'cx> for Ident {
type Context = LateContext<'cx>;
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 {

View file

@ -214,8 +214,17 @@ pub fn implements_trait<'tcx>(
trait_id: DefId,
args: &[GenericArg<'tcx>],
) -> bool {
let callee_id = cx.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)))
let callee_id = cx
.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.
@ -227,7 +236,14 @@ pub fn implements_trait_with_env<'tcx>(
callee_id: DefId,
args: &[GenericArg<'tcx>],
) -> 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.
@ -248,19 +264,28 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
}
let infcx = tcx.infer_ctxt().build();
let args = args.into_iter().map(|arg| {
arg.into().unwrap_or_else(|| {
let orig = TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
};
infcx.next_ty_var(orig).into()
let args = args
.into_iter()
.map(|arg| {
arg.into().unwrap_or_else(|| {
let orig = TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
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.
let effect_arg = if tcx.generics_of(trait_id).host_effect_index.is_some_and(|x| args.get(x - 1).is_none()) {
Some(GenericArg::from(callee_id.map(|def_id| tcx.expected_host_effect_param_for_body(def_id)).unwrap_or(tcx.consts.true_)))
let effect_arg = if tcx
.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 {
None
};
@ -268,9 +293,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
let trait_ref = TraitRef::new(
tcx,
trait_id,
Some(GenericArg::from(ty))
.into_iter()
.chain(args).chain(effect_arg),
Some(GenericArg::from(ty)).into_iter().chain(args).chain(effect_arg),
);
debug_assert_matches!(

View file

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

View file

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

View file

@ -105,7 +105,7 @@ fn path() -> PathBuf {
}
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
.clippy_args
.iter()

View file

@ -12,7 +12,12 @@ fn old_test_headers() {
for entry in WalkDir::new("tests") {
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;
}

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`
= 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`
= 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`
= 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`
= 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::needless_if)]
#![warn(clippy::excessive_nesting)]
#![allow(clippy::collapsible_if)]
#![allow(clippy::collapsible_if, clippy::blocks_in_conditions)]
#[macro_use]
extern crate proc_macros;

View file

@ -1,5 +1,5 @@
#![deny(clippy::bind_instead_of_map)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::blocks_in_conditions)]
pub fn main() {
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)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::blocks_in_conditions)]
pub fn main() {
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)]
#![warn(clippy::nonminimal_bool)]
@ -21,6 +21,7 @@ fn macro_if() {
fn condition_has_block() -> i32 {
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;
x == 3
}; if res {
@ -32,6 +33,7 @@ fn condition_has_block() -> i32 {
fn condition_has_block_with_single_expression() -> i32 {
if true { 6 } else { 10 }
//~^ ERROR: omit braces around single expression condition
}
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() {}

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)]
#![warn(clippy::nonminimal_bool)]
@ -21,6 +21,7 @@ fn macro_if() {
fn condition_has_block() -> i32 {
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;
x == 3
} {
@ -32,6 +33,7 @@ fn condition_has_block() -> i32 {
fn condition_has_block_with_single_expression() -> i32 {
if { true } { 6 } else { 10 }
//~^ ERROR: omit braces around single expression condition
}
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() {}

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`
--> $DIR/blocks_in_if_conditions.rs:23:5
--> $DIR/blocks_in_conditions.rs:23:5
|
LL | / if {
LL | |
LL | | let x = 3;
LL | | x == 3
LL | | } {
| |_____^
|
= note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]`
= note: `-D clippy::blocks-in-conditions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]`
help: try
|
LL ~ let res = {
LL +
LL + let x = 3;
LL + x == 3
LL ~ }; if res {
|
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 }
| ^^^^^^^^ help: try: `true`
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 }
| ^^^^^^^^^^^^^^ 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`
= 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(
unused,
clippy::let_and_return,
@ -22,7 +22,7 @@ fn pred_test() {
&& predicate(
|x| {
//~^ 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;
x == target
},
@ -60,6 +60,23 @@ fn function_with_empty_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]
fn main() {
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`
--> $DIR/blocks_in_if_conditions_closure.rs:23:17
--> $DIR/blocks_in_conditions_closure.rs:23:17
|
LL | |x| {
| _________________^
@ -10,11 +10,11 @@ LL | | x == target
LL | | },
| |_____________^
|
= note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]`
= note: `-D clippy::blocks-in-conditions` implied by `-D warnings`
= 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`
--> $DIR/blocks_in_if_conditions_closure.rs:34:13
--> $DIR/blocks_in_conditions_closure.rs:34:13
|
LL | |x| {
| _____________^
@ -24,5 +24,16 @@ LL | | x == target
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
fn issue_11568() {}
/// There is no try (`do()` or `do_not()`).
fn parenthesized_word() {}

View file

@ -227,3 +227,6 @@ fn new() -> Self {
/// this checks if the lowerCamelCase issue is fixed
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`
| ~~~~~~~~~~~~~~~~~
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
#![allow(clippy::let_unit_value)]
#![allow(clippy::let_unit_value, clippy::needless_pass_by_ref_mut)]
extern crate proc_macros;
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)]
#![allow(dead_code, unreachable_code, unused_variables)]
#![allow(clippy::let_and_return)]
#![allow(clippy::let_and_return, clippy::uninhabited_references)]
enum SingleVariantEnum {
Variant(i32),

View file

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

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| {
println!("foo");
x > 10 && x < 100

View file

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

View file

@ -118,4 +118,19 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) {
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() {}

View file

@ -118,4 +118,19 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) {
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() {}

View file

@ -249,5 +249,57 @@ LL | let _ = v1[0] + v1[12];
| ^^^^^^
= 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 @@ pub const fn compute<T>(_: T)
{
}
}
// 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
#![feature(let_chains)]
#![allow(
clippy::blocks_in_if_conditions,
clippy::blocks_in_conditions,
clippy::if_same_then_else,
clippy::ifs_same_cond,
clippy::let_unit_value,

View file

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

View file

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

View file

@ -3,7 +3,7 @@
#![allow(unused)]
#![allow(
clippy::assign_op_pattern,
clippy::blocks_in_if_conditions,
clippy::blocks_in_conditions,
clippy::let_and_return,
clippy::let_unit_value,
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)
}
// `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() {
let mut u = 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
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
)]
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 Tuple(i32);
struct Struct {
@ -174,4 +198,11 @@ fn main() {
GreetStruct1("world");
GreetStruct2()("world");
GreetStruct3 {}("world");
fn n() -> i32 {
42
}
Cout << 142;
-Cout;
}

View file

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

View file

@ -71,3 +71,118 @@ fn _msrv_1_38() {
let _ = 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 _ = 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;
| ^^^^^^^^^^^^^^^^^^^ 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
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() {

View file

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

View file

@ -4,7 +4,7 @@
#![allow(clippy::almost_complete_range)]
#![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::blocks_in_conditions)]
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::cognitive_complexity)]
@ -56,6 +56,7 @@
#![warn(clippy::blacklisted_name)]
#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![warn(clippy::blocks_in_if_conditions)]
#![warn(clippy::box_vec)]
#![warn(clippy::const_static_lifetime)]
#![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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
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
|
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`
--> $DIR/rename.rs:59:9
--> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
--> $DIR/rename.rs:62:9
--> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::derive_hash_xor_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
--> $DIR/rename.rs:68:9
--> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
--> $DIR/rename.rs:69:9
--> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
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)]
| ^^^^^^^^^^^^^^^^^ 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`
--> $DIR/rename.rs:72:9
--> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
--> $DIR/rename.rs:73:9
--> $DIR/rename.rs:74:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
--> $DIR/rename.rs:76:9
--> $DIR/rename.rs:77:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
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)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
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)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
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)]
| ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
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)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
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)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
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)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
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)]
| ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
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)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
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)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
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)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
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)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
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)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
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)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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)]
use std::fmt::Display;
use std::ops::Shl;
struct Tuple(i32);
struct Struct {
field: i32,
@ -50,6 +53,19 @@ fn get_drop_struct() -> DropStruct {
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() {
get_number();
get_number();
@ -87,4 +103,7 @@ fn main() {
($($e:expr),*) => {{ $($e;)* }}
}
use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
// Issue #11885
Cout << 16;
}

View file

@ -7,6 +7,9 @@
)]
#![warn(clippy::unnecessary_operation)]
use std::fmt::Display;
use std::ops::Shl;
struct Tuple(i32);
struct Struct {
field: i32,
@ -50,6 +53,19 @@ fn get_drop_struct() -> DropStruct {
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() {
Tuple(get_number());
Struct { field: get_number() };
@ -91,4 +107,7 @@ macro_rules! use_expr {
($($e:expr),*) => {{ $($e;)* }}
}
use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
// Issue #11885
Cout << 16;
}

View file

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

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