mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
Auto merge of #119013 - flip1995:clippy-subtree-sync, r=Manishearth
Clippy subtree update r? `@matthiaskrgr` (As Manish wrote that he is a bit inactive until the new year)
This commit is contained in:
commit
e223c41028
@ -598,7 +598,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"quine-mc_cluskey",
|
||||
"regex",
|
||||
"regex-syntax 0.7.2",
|
||||
"regex-syntax 0.8.2",
|
||||
"rustc-semver",
|
||||
"semver",
|
||||
"serde",
|
||||
@ -3195,6 +3195,12 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "remote-test-client"
|
||||
version = "0.1.0"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -2,8 +2,8 @@ use std::ffi::OsStr;
|
||||
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()
|
||||
|
@ -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 }
|
||||
|
@ -48,11 +48,10 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
|
||||
|
||||
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,
|
||||
|
137
src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
Normal file
137
src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
Normal 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)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -57,7 +57,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
&& !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 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if is_from_proc_macro(cx, e) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
@ -9,11 +9,10 @@ use rustc_middle::ty::{self, Ty, TypeAndMut};
|
||||
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()
|
||||
|
@ -3,12 +3,29 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
|
||||
crate::await_holding_invalid::AWAIT_HOLDING_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 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
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 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
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 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
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 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
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,
|
||||
|
@ -9,11 +9,21 @@ use url::Url;
|
||||
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 check_word(cx: &LateContext<'_>, word: &str, span: Span) {
|
||||
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(
|
||||
|
@ -15,7 +15,7 @@ declare_clippy_lint! {
|
||||
/// 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -50,6 +50,8 @@ extern crate clippy_utils;
|
||||
#[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 assertions_on_result_states;
|
||||
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 implied_bounds_in_impls;
|
||||
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_option_ref;
|
||||
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 tuple_array_conversions;
|
||||
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`
|
||||
}
|
||||
|
||||
|
125
src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
Normal file
125
src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
Normal 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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ mod explicit_counter_loop;
|
||||
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 @@ declare_clippy_lint! {
|
||||
"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 @@ impl_lint_pass!(Loops => [
|
||||
MANUAL_FIND,
|
||||
MANUAL_WHILE_LET_SOME,
|
||||
UNUSED_ENUMERATE_INDEX,
|
||||
INFINITE_LOOP,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
@ -707,10 +751,11 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
// check for `loop { if let {} else break }` that could be `while let`
|
||||
// (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);
|
||||
|
@ -13,8 +13,7 @@ use rustc_lint::LateContext;
|
||||
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.
|
||||
|
@ -105,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
||||
// 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 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
||||
(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 {
|
||||
|
@ -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
|
||||
|
@ -3906,7 +3906,7 @@ impl_lint_pass!(Methods => [
|
||||
]);
|
||||
|
||||
/// 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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,7 @@ use rustc_lint::LateContext;
|
||||
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;
|
||||
|
@ -52,7 +52,7 @@ declare_clippy_lint! {
|
||||
/// 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 @@ fn len_comparison<'hir>(
|
||||
(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 => {
|
||||
|
@ -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),
|
||||
|
@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv};
|
||||
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)
|
||||
|
@ -44,7 +44,6 @@ impl LateLintPass<'_> for NeedlessIf {
|
||||
&& 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 @@ impl LateLintPass<'_> for NeedlessIf {
|
||||
// - #[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,
|
||||
|
@ -87,6 +87,17 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
|
||||
|
||||
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),
|
||||
|
@ -132,7 +132,11 @@ impl ArithmeticSideEffects {
|
||||
}
|
||||
|
||||
// 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 @@ impl ArithmeticSideEffects {
|
||||
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 @@ impl ArithmeticSideEffects {
|
||||
/// 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 @@ impl ArithmeticSideEffects {
|
||||
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 @@ impl ArithmeticSideEffects {
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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"),
|
||||
|
114
src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
Normal file
114
src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -55,11 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|
||||
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 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|
||||
|
||||
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) {
|
||||
|
@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn {
|
||||
) {
|
||||
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;
|
||||
}
|
||||
|
84
src/tools/clippy/clippy_lints/src/uninhabited_references.rs
Normal file
84
src/tools/clippy/clippy_lints/src/uninhabited_references.rs
Normal 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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
|
||||
};
|
||||
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,
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,12 @@ use rustc_span::{sym, Loc, Span, Symbol};
|
||||
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")
|
||||
|
@ -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()
|
||||
|
@ -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 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum SuggestedType {
|
||||
pub(crate) enum SuggestedType {
|
||||
/// Suggest using a slice `&[..]` / `&mut [..]`
|
||||
SliceRef(Mutability),
|
||||
/// Suggest using an array: `[..]`
|
||||
@ -147,6 +173,7 @@ impl UselessVec {
|
||||
cx: &LateContext<'tcx>,
|
||||
vec_args: &higher::VecArgs<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
suggest_slice: SuggestedType,
|
||||
) {
|
||||
if span.from_expansion() {
|
||||
@ -204,21 +231,9 @@ impl UselessVec {
|
||||
},
|
||||
};
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 @@ use rustc_target::spec::abi::Abi;
|
||||
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 {
|
||||
|
@ -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!(
|
||||
|
@ -367,7 +367,7 @@ impl Crate {
|
||||
//
|
||||
// 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 @@ impl Crate {
|
||||
|
||||
/// 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();
|
||||
|
@ -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"]
|
||||
|
@ -105,7 +105,7 @@ impl ClippyCmd {
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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() });
|
||||
|
@ -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()) });
|
||||
|
@ -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() {}
|
@ -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() {}
|
@ -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
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
41
src/tools/clippy/tests/ui/ineffective_open_options.fixed
Normal file
41
src/tools/clippy/tests/ui/ineffective_open_options.fixed
Normal 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();
|
||||
}
|
41
src/tools/clippy/tests/ui/ineffective_open_options.rs
Normal file
41
src/tools/clippy/tests/ui/ineffective_open_options.rs
Normal 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();
|
||||
}
|
17
src/tools/clippy/tests/ui/ineffective_open_options.stderr
Normal file
17
src/tools/clippy/tests/ui/ineffective_open_options.stderr
Normal 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
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
366
src/tools/clippy/tests/ui/infinite_loops.rs
Normal file
366
src/tools/clippy/tests/ui/infinite_loops.rs
Normal 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() {}
|
259
src/tools/clippy/tests/ui/infinite_loops.stderr
Normal file
259
src/tools/clippy/tests/ui/infinite_loops.stderr
Normal 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
|
||||
|
@ -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
|
||||
|
@ -135,7 +135,7 @@ fn main() {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(clippy::blocks_in_if_conditions)]
|
||||
#[allow(clippy::blocks_in_conditions)]
|
||||
match Some(11) {
|
||||
// Lint, statement is preserved by `.filter`
|
||||
Some(x) => {
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 _
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
||||
|
38
src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed
Normal file
38
src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed
Normal 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));
|
||||
}
|
||||
}
|
38
src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs
Normal file
38
src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs
Normal 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));
|
||||
}
|
||||
}
|
40
src/tools/clippy/tests/ui/repeat_vec_with_capacity.stderr
Normal file
40
src/tools/clippy/tests/ui/repeat_vec_with_capacity.stderr
Normal 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
|
||||
|
22
src/tools/clippy/tests/ui/uninhabited_references.rs
Normal file
22
src/tools/clippy/tests/ui/uninhabited_references.rs
Normal 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;
|
||||
}
|
39
src/tools/clippy/tests/ui/uninhabited_references.stderr
Normal file
39
src/tools/clippy/tests/ui/uninhabited_references.stderr
Normal 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 @@ fn main() {
|
||||
($($e:expr),*) => {{ $($e;)* }}
|
||||
}
|
||||
use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
|
||||
|
||||
// Issue #11885
|
||||
Cout << 16;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user