Auto merge of #131205 - flip1995:clippy-subtree-update, r=Manishearth
Clippy subtree update r? `@Manishearth`
This commit is contained in:
commit
56e35a5dbb
183 changed files with 2484 additions and 848 deletions
|
@ -19,7 +19,7 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18.x'
|
||||
|
||||
|
|
|
@ -5871,6 +5871,7 @@ Released 2018-09-13
|
|||
[`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr
|
||||
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
|
||||
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
|
||||
[`ref_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option
|
||||
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
|
||||
[`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
|
||||
|
|
|
@ -353,6 +353,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
|
|||
* [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
|
||||
* [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
|
||||
* [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation)
|
||||
* [`ref_option`](https://rust-lang.github.io/rust-clippy/master/index.html#ref_option)
|
||||
* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn)
|
||||
* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
|
||||
* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns)
|
||||
|
|
|
@ -378,6 +378,7 @@ define_Conf! {
|
|||
rc_buffer,
|
||||
rc_mutex,
|
||||
redundant_allocation,
|
||||
ref_option,
|
||||
single_call_fn,
|
||||
trivially_copy_pass_by_ref,
|
||||
unnecessary_box_returns,
|
||||
|
|
|
@ -19,6 +19,7 @@ macro_rules! msrv_aliases {
|
|||
msrv_aliases! {
|
||||
1,83,0 { CONST_EXTERN_FN }
|
||||
1,83,0 { CONST_FLOAT_BITS_CONV }
|
||||
1,82,0 { IS_NONE_OR }
|
||||
1,81,0 { LINT_REASONS_STABILIZATION }
|
||||
1,80,0 { BOX_INTO_ITER}
|
||||
1,77,0 { C_STR_LITERALS }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||
use clippy_utils::eq_expr_value;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
|
@ -7,7 +9,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
||||
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass, Level};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_session::{RustcVersion, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
|
@ -69,9 +71,25 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
// For each pairs, both orders are considered.
|
||||
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
|
||||
const METHODS_WITH_NEGATION: [(Option<RustcVersion>, &str, &str); 3] = [
|
||||
(None, "is_some", "is_none"),
|
||||
(None, "is_err", "is_ok"),
|
||||
(Some(msrvs::IS_NONE_OR), "is_some_and", "is_none_or"),
|
||||
];
|
||||
|
||||
declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
|
||||
pub struct NonminimalBool {
|
||||
msrv: Msrv,
|
||||
}
|
||||
|
||||
impl NonminimalBool {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
|
||||
fn check_fn(
|
||||
|
@ -83,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
|
|||
_: Span,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
NonminimalBoolVisitor { cx }.visit_body(body);
|
||||
NonminimalBoolVisitor { cx, msrv: &self.msrv }.visit_body(body);
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
|
@ -100,6 +118,8 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
|
|||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn inverted_bin_op_eq_str(op: BinOpKind) -> Option<&'static str> {
|
||||
|
@ -176,11 +196,11 @@ fn check_inverted_bool_in_condition(
|
|||
);
|
||||
}
|
||||
|
||||
fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
fn check_simplify_not(cx: &LateContext<'_>, msrv: &Msrv, expr: &Expr<'_>) {
|
||||
if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind
|
||||
&& !expr.span.from_expansion()
|
||||
&& !inner.span.from_expansion()
|
||||
&& let Some(suggestion) = simplify_not(cx, inner)
|
||||
&& let Some(suggestion) = simplify_not(cx, msrv, inner)
|
||||
&& cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
|
@ -197,6 +217,7 @@ fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
|
||||
struct NonminimalBoolVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
msrv: &'a Msrv,
|
||||
}
|
||||
|
||||
use quine_mc_cluskey::Bool;
|
||||
|
@ -205,7 +226,7 @@ struct Hir2Qmm<'a, 'tcx, 'v> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
||||
impl<'v> Hir2Qmm<'_, '_, 'v> {
|
||||
fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
|
||||
for a in a {
|
||||
if let ExprKind::Binary(binop, lhs, rhs) = &a.kind {
|
||||
|
@ -289,10 +310,11 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
|||
struct SuggestContext<'a, 'tcx, 'v> {
|
||||
terminals: &'v [&'v Expr<'v>],
|
||||
cx: &'a LateContext<'tcx>,
|
||||
msrv: &'a Msrv,
|
||||
output: String,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
||||
impl SuggestContext<'_, '_, '_> {
|
||||
fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
|
||||
use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True};
|
||||
match suggestion {
|
||||
|
@ -311,7 +333,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
|||
},
|
||||
Term(n) => {
|
||||
let terminal = self.terminals[n as usize];
|
||||
if let Some(str) = simplify_not(self.cx, terminal) {
|
||||
if let Some(str) = simplify_not(self.cx, self.msrv, terminal) {
|
||||
self.output.push_str(&str);
|
||||
} else {
|
||||
self.output.push('!');
|
||||
|
@ -358,7 +380,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
|||
}
|
||||
}
|
||||
|
||||
fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
||||
fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Option<String> {
|
||||
match &expr.kind {
|
||||
ExprKind::Binary(binop, lhs, rhs) => {
|
||||
if !implements_ord(cx, lhs) {
|
||||
|
@ -389,7 +411,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
|||
Some(format!("{lhs_snippet}{op}{rhs_snippet}"))
|
||||
})
|
||||
},
|
||||
ExprKind::MethodCall(path, receiver, [], _) => {
|
||||
ExprKind::MethodCall(path, receiver, args, _) => {
|
||||
let type_of_receiver = cx.typeck_results().expr_ty(receiver);
|
||||
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
|
||||
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
|
||||
|
@ -399,21 +421,41 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
|||
METHODS_WITH_NEGATION
|
||||
.iter()
|
||||
.copied()
|
||||
.flat_map(|(a, b)| vec![(a, b), (b, a)])
|
||||
.find(|&(a, _)| {
|
||||
let path: &str = path.ident.name.as_str();
|
||||
a == path
|
||||
.flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)])
|
||||
.find(|&(msrv, a, _)| msrv.is_none_or(|msrv| curr_msrv.meets(msrv)) && a == path.ident.name.as_str())
|
||||
.and_then(|(_, _, neg_method)| {
|
||||
let negated_args = args
|
||||
.iter()
|
||||
.map(|arg| simplify_not(cx, curr_msrv, arg))
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
.join(", ");
|
||||
Some(format!(
|
||||
"{}.{neg_method}({negated_args})",
|
||||
receiver.span.get_source_text(cx)?
|
||||
))
|
||||
})
|
||||
.and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?)))
|
||||
},
|
||||
ExprKind::Closure(closure) => {
|
||||
let body = cx.tcx.hir().body(closure.body);
|
||||
let params = body
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| param.span.get_source_text(cx).map(|t| t.to_string()))
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
.join(", ");
|
||||
let negated = simplify_not(cx, curr_msrv, body.value)?;
|
||||
Some(format!("|{params}| {negated}"))
|
||||
},
|
||||
ExprKind::Unary(UnOp::Not, expr) => expr.span.get_source_text(cx).map(|t| t.to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest(cx: &LateContext<'_>, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String {
|
||||
fn suggest(cx: &LateContext<'_>, msrv: &Msrv, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String {
|
||||
let mut suggest_context = SuggestContext {
|
||||
terminals,
|
||||
cx,
|
||||
msrv,
|
||||
output: String::new(),
|
||||
};
|
||||
suggest_context.recurse(suggestion);
|
||||
|
@ -475,7 +517,7 @@ fn terminal_stats(b: &Bool) -> Stats {
|
|||
stats
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
||||
impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> {
|
||||
fn bool_expr(&self, e: &'tcx Expr<'_>) {
|
||||
let mut h2q = Hir2Qmm {
|
||||
terminals: Vec::new(),
|
||||
|
@ -526,7 +568,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
|||
diag.span_suggestion(
|
||||
e.span,
|
||||
"it would look like the following",
|
||||
suggest(self.cx, suggestion, &h2q.terminals),
|
||||
suggest(self.cx, self.msrv, suggestion, &h2q.terminals),
|
||||
// nonminimal_bool can produce minimal but
|
||||
// not human readable expressions (#3141)
|
||||
Applicability::Unspecified,
|
||||
|
@ -569,12 +611,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
if improvements.is_empty() {
|
||||
check_simplify_not(self.cx, e);
|
||||
check_simplify_not(self.cx, self.msrv, e);
|
||||
} else {
|
||||
nonminimal_bool_lint(
|
||||
improvements
|
||||
.into_iter()
|
||||
.map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals))
|
||||
.map(|suggestion| suggest(self.cx, self.msrv, suggestion, &h2q.terminals))
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
@ -582,7 +624,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if !e.span.from_expansion() {
|
||||
match &e.kind {
|
||||
|
|
|
@ -91,7 +91,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
|
|||
#[derive(Default)]
|
||||
struct InferVisitor(bool);
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for InferVisitor {
|
||||
impl Visitor<'_> for InferVisitor {
|
||||
fn visit_ty(&mut self, t: &Ty<'_>) {
|
||||
self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
|
||||
if !self.0 {
|
||||
|
|
|
@ -10,27 +10,27 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b
|
|||
// only run the lint if publish is `None` (`publish = true` or skipped entirely)
|
||||
// or if the vector isn't empty (`publish = ["something"]`)
|
||||
if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || ignore_publish {
|
||||
if is_empty_str(&package.description) {
|
||||
if is_empty_str(package.description.as_ref()) {
|
||||
missing_warning(cx, package, "package.description");
|
||||
}
|
||||
|
||||
if is_empty_str(&package.license) && is_empty_str(&package.license_file) {
|
||||
if is_empty_str(package.license.as_ref()) && is_empty_str(package.license_file.as_ref()) {
|
||||
missing_warning(cx, package, "either package.license or package.license_file");
|
||||
}
|
||||
|
||||
if is_empty_str(&package.repository) {
|
||||
if is_empty_str(package.repository.as_ref()) {
|
||||
missing_warning(cx, package, "package.repository");
|
||||
}
|
||||
|
||||
if is_empty_str(&package.readme) {
|
||||
if is_empty_str(package.readme.as_ref()) {
|
||||
missing_warning(cx, package, "package.readme");
|
||||
}
|
||||
|
||||
if is_empty_vec(&package.keywords) {
|
||||
if is_empty_vec(package.keywords.as_ref()) {
|
||||
missing_warning(cx, package, "package.keywords");
|
||||
}
|
||||
|
||||
if is_empty_vec(&package.categories) {
|
||||
if is_empty_vec(package.categories.as_ref()) {
|
||||
missing_warning(cx, package, "package.categories");
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel
|
|||
span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
|
||||
}
|
||||
|
||||
fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: &Option<T>) -> bool {
|
||||
value.as_ref().map_or(true, |s| s.as_ref().is_empty())
|
||||
fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: Option<&T>) -> bool {
|
||||
value.map_or(true, |s| s.as_ref().is_empty())
|
||||
}
|
||||
|
||||
fn is_empty_vec(value: &[String]) -> bool {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_no_std_crate;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::std_or_core;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -16,8 +16,8 @@ pub(super) fn check<'tcx>(
|
|||
) {
|
||||
if matches!(cast_to.kind, TyKind::Ptr(_))
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
|
||||
&& let Some(std_or_core) = std_or_core(cx)
|
||||
{
|
||||
let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
|
||||
let macro_name = match mutability {
|
||||
Mutability::Not => "addr_of",
|
||||
Mutability::Mut => "addr_of_mut",
|
||||
|
@ -40,7 +40,7 @@ pub(super) fn check<'tcx>(
|
|||
expr.span,
|
||||
"borrow as raw pointer",
|
||||
"try",
|
||||
format!("{core_or_std}::ptr::{macro_name}!({snip})"),
|
||||
format!("{std_or_core}::ptr::{macro_name}!({snip})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate};
|
||||
use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability, Ty, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -25,8 +25,8 @@ pub(super) fn check<'tcx>(
|
|||
&& let use_cx = expr_use_ctxt(cx, expr)
|
||||
// TODO: only block the lint if `cast_expr` is a temporary
|
||||
&& !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
|
||||
&& let Some(std_or_core) = std_or_core(cx)
|
||||
{
|
||||
let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
|
||||
let fn_name = match to_mutbl {
|
||||
Mutability::Not => "from_ref",
|
||||
Mutability::Mut => "from_mut",
|
||||
|
@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(
|
|||
expr.span,
|
||||
"reference as raw pointer",
|
||||
"try",
|
||||
format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
|
||||
format!("{std_or_core}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
|
||||
app,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ impl CheckedConversions {
|
|||
|
||||
impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
|
||||
impl LateLintPass<'_> for CheckedConversions {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
|
||||
if let ExprKind::Binary(op, lhs, rhs) = item.kind
|
||||
&& let (lt1, gt1, op2) = match op.node {
|
||||
|
|
|
@ -202,6 +202,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::functions::MUST_USE_CANDIDATE_INFO,
|
||||
crate::functions::MUST_USE_UNIT_INFO,
|
||||
crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
|
||||
crate::functions::REF_OPTION_INFO,
|
||||
crate::functions::RENAMED_FUNCTION_PARAMS_INFO,
|
||||
crate::functions::RESULT_LARGE_ERR_INFO,
|
||||
crate::functions::RESULT_UNIT_ERR_INFO,
|
||||
|
|
|
@ -119,7 +119,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
match &expr.kind {
|
||||
ExprKind::Block(
|
||||
|
|
|
@ -385,7 +385,7 @@ fn check_unsafe_derive_deserialize<'tcx>(
|
|||
&& cx
|
||||
.tcx
|
||||
.inherent_impls(def.did())
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
|
||||
.any(|imp| has_unsafe(cx, imp))
|
||||
{
|
||||
|
|
|
@ -970,7 +970,7 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
@ -60,7 +60,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
|
||||
impl LateLintPass<'_> for EmptyEnum {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if let ItemKind::Enum(..) = item.kind
|
||||
// Only suggest the `never_type` if the feature is enabled
|
||||
|
|
|
@ -141,7 +141,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
|
|||
matches!(tcx.parent_hir_node(id), Node::Param(_))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
||||
impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> {
|
||||
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
|
||||
if cmt.place.projections.is_empty() {
|
||||
if let PlaceBase::Local(lid) = cmt.place.base {
|
||||
|
@ -188,7 +188,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
|||
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
|
||||
impl<'tcx> EscapeDelegate<'_, 'tcx> {
|
||||
fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
|
||||
// Large types need to be boxed to avoid stack overflows.
|
||||
if let Some(boxed_ty) = ty.boxed_ty() {
|
||||
|
|
|
@ -135,7 +135,7 @@ impl NestingVisitor<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
|
||||
impl Visitor<'_> for NestingVisitor<'_, '_> {
|
||||
fn visit_block(&mut self, block: &Block) {
|
||||
if block.span.from_expansion() {
|
||||
return;
|
||||
|
|
|
@ -193,7 +193,7 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
|
|||
bound.trait_ref()?.trait_def_id()?.as_local()
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
||||
|
|
|
@ -73,7 +73,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
|
|||
result: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
|
||||
if is_panic(self.lcx, macro_call.def_id) {
|
||||
|
|
|
@ -219,7 +219,7 @@ struct FormatArgsExpr<'a, 'tcx> {
|
|||
ignore_mixed: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
|
||||
impl FormatArgsExpr<'_, '_> {
|
||||
fn check_templates(&self) {
|
||||
for piece in &self.format_args.template {
|
||||
if let FormatArgsPiece::Placeholder(placeholder) = piece
|
||||
|
|
|
@ -148,7 +148,7 @@ struct FormatImplExpr<'a, 'tcx> {
|
|||
format_trait_impl: FormatTraitNames,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
|
||||
impl FormatImplExpr<'_, '_> {
|
||||
fn check_to_string_in_display(&self) {
|
||||
if self.format_trait_impl.name == sym::Display
|
||||
&& let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind
|
||||
|
|
|
@ -126,7 +126,7 @@ struct SelfFinder<'a, 'tcx> {
|
|||
invalid: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
|
@ -2,6 +2,7 @@ mod impl_trait_in_params;
|
|||
mod misnamed_getters;
|
||||
mod must_use;
|
||||
mod not_unsafe_ptr_arg_deref;
|
||||
mod ref_option;
|
||||
mod renamed_function_params;
|
||||
mod result;
|
||||
mod too_many_arguments;
|
||||
|
@ -399,6 +400,53 @@ declare_clippy_lint! {
|
|||
"renamed function parameters in trait implementation"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Warns when a function signature uses `&Option<T>` instead of `Option<&T>`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// More flexibility, better memory optimization, and more idiomatic Rust code.
|
||||
///
|
||||
/// `&Option<T>` in a function signature breaks encapsulation because the caller must own T
|
||||
/// and move it into an Option to call with it. When returned, the owner must internally store
|
||||
/// it as `Option<T>` in order to return it.
|
||||
/// At a lower level, `&Option<T>` points to memory with the `presence` bit flag plus the `T` value,
|
||||
/// whereas `Option<&T>` is usually [optimized](https://doc.rust-lang.org/1.81.0/std/option/index.html#representation)
|
||||
/// to a single pointer, so it may be more optimal.
|
||||
///
|
||||
/// See this [YouTube video](https://www.youtube.com/watch?v=6c7pZYP_iIE) by
|
||||
/// Logan Smith for an in-depth explanation of why this is important.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint recommends changing the function signatures, but it cannot
|
||||
/// automatically change the function calls or the function implementations.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// // caller uses foo(&opt)
|
||||
/// fn foo(a: &Option<String>) {}
|
||||
/// # struct Unit {}
|
||||
/// # impl Unit {
|
||||
/// fn bar(&self) -> &Option<String> { &None }
|
||||
/// # }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// // caller should use `foo1(opt.as_ref())`
|
||||
/// fn foo1(a: Option<&String>) {}
|
||||
/// // better yet, use string slice `foo2(opt.as_deref())`
|
||||
/// fn foo2(a: Option<&str>) {}
|
||||
/// # struct Unit {}
|
||||
/// # impl Unit {
|
||||
/// fn bar(&self) -> Option<&String> { None }
|
||||
/// # }
|
||||
/// ```
|
||||
#[clippy::version = "1.82.0"]
|
||||
pub REF_OPTION,
|
||||
pedantic,
|
||||
"function signature uses `&Option<T>` instead of `Option<&T>`"
|
||||
}
|
||||
|
||||
pub struct Functions {
|
||||
too_many_arguments_threshold: u64,
|
||||
too_many_lines_threshold: u64,
|
||||
|
@ -437,6 +485,7 @@ impl_lint_pass!(Functions => [
|
|||
MISNAMED_GETTERS,
|
||||
IMPL_TRAIT_IN_PARAMS,
|
||||
RENAMED_FUNCTION_PARAMS,
|
||||
REF_OPTION,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Functions {
|
||||
|
@ -455,6 +504,16 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
|||
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
|
||||
misnamed_getters::check_fn(cx, kind, decl, body, span);
|
||||
impl_trait_in_params::check_fn(cx, &kind, body, hir_id);
|
||||
ref_option::check_fn(
|
||||
cx,
|
||||
kind,
|
||||
decl,
|
||||
span,
|
||||
hir_id,
|
||||
def_id,
|
||||
body,
|
||||
self.avoid_breaking_exported_api,
|
||||
);
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
|
@ -475,5 +534,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
|||
must_use::check_trait_item(cx, item);
|
||||
result::check_trait_item(cx, item, self.large_error_threshold);
|
||||
impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
|
||||
ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api);
|
||||
}
|
||||
}
|
||||
|
|
122
src/tools/clippy/clippy_lints/src/functions/ref_option.rs
Normal file
122
src/tools/clippy/clippy_lints/src/functions/ref_option.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use crate::functions::REF_OPTION;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_trait_impl_item;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{FnDecl, HirId};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
|
||||
if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
|
||||
&& is_type_diagnostic_item(cx, *opt_ty, sym::Option)
|
||||
&& let ty::Adt(_, opt_gen) = opt_ty.kind()
|
||||
&& let [gen] = opt_gen.as_slice()
|
||||
&& let GenericArgKind::Type(gen_ty) = gen.unpack()
|
||||
&& !gen_ty.is_ref()
|
||||
// Need to gen the original spans, so first parsing mid, and hir parsing afterward
|
||||
&& let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
|
||||
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
|
||||
&& let (Some(first), Some(last)) = (path.segments.first(), path.segments.last())
|
||||
&& let Some(hir::GenericArgs {
|
||||
args: [hir::GenericArg::Type(opt_ty)],
|
||||
..
|
||||
}) = last.args
|
||||
{
|
||||
let lifetime = snippet(cx, lifetime.ident.span, "..");
|
||||
fixes.push((
|
||||
param.span,
|
||||
format!(
|
||||
"{}<&{lifetime}{}{}>",
|
||||
snippet(cx, first.ident.span.to(last.ident.span), ".."),
|
||||
if lifetime.is_empty() { "" } else { " " },
|
||||
snippet(cx, opt_ty.span, "..")
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty::FnSig<'a>) {
|
||||
let mut fixes = Vec::new();
|
||||
// Check function arguments' types
|
||||
for (param, param_ty) in decl.inputs.iter().zip(sig.inputs()) {
|
||||
check_ty(cx, param, *param_ty, &mut fixes);
|
||||
}
|
||||
// Check return type
|
||||
if let hir::FnRetTy::Return(ty) = &decl.output {
|
||||
check_ty(cx, ty, sig.output(), &mut fixes);
|
||||
}
|
||||
if !fixes.is_empty() {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REF_OPTION,
|
||||
span,
|
||||
"it is more idiomatic to use `Option<&T>` instead of `&Option<T>`",
|
||||
|diag| {
|
||||
diag.multipart_suggestion("change this to", fixes, Applicability::Unspecified);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn check_fn<'a>(
|
||||
cx: &LateContext<'a>,
|
||||
kind: FnKind<'_>,
|
||||
decl: &FnDecl<'a>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
body: &hir::Body<'_>,
|
||||
avoid_breaking_exported_api: bool,
|
||||
) {
|
||||
if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let FnKind::Closure = kind {
|
||||
// Compute the span of the closure parameters + return type if set
|
||||
let span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
|
||||
if decl.inputs.is_empty() {
|
||||
out_ty.span
|
||||
} else {
|
||||
span.with_hi(out_ty.span.hi())
|
||||
}
|
||||
} else if let (Some(first), Some(last)) = (decl.inputs.first(), decl.inputs.last()) {
|
||||
first.span.to(last.span)
|
||||
} else {
|
||||
// No parameters - no point in checking
|
||||
return;
|
||||
};
|
||||
|
||||
// Figure out the signature of the closure
|
||||
let ty::Closure(_, args) = cx.typeck_results().expr_ty(body.value).kind() else {
|
||||
return;
|
||||
};
|
||||
let sig = args.as_closure().sig().skip_binder();
|
||||
|
||||
check_fn_sig(cx, decl, span, sig);
|
||||
} else if !is_trait_impl_item(cx, hir_id) {
|
||||
let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
|
||||
check_fn_sig(cx, decl, span, sig);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_trait_item<'a>(
|
||||
cx: &LateContext<'a>,
|
||||
trait_item: &hir::TraitItem<'a>,
|
||||
avoid_breaking_exported_api: bool,
|
||||
) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
|
||||
&& !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id))
|
||||
{
|
||||
let def_id = trait_item.owner_id.def_id;
|
||||
let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
|
||||
check_fn_sig(cx, sig.decl, sig.span, ty_sig);
|
||||
}
|
||||
}
|
|
@ -281,7 +281,7 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> {
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
|
||||
if let Some(target) = ImplicitHasherType::new(self.cx, t) {
|
||||
self.found.push(target);
|
||||
|
@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_body(&mut self, body: &Body<'tcx>) {
|
||||
|
|
|
@ -226,7 +226,7 @@ struct SliceIndexLintingVisitor<'a, 'tcx> {
|
|||
max_suggested_slice: u64,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
|
@ -460,7 +460,7 @@ fn check_for_is_empty(
|
|||
let is_empty = cx
|
||||
.tcx
|
||||
.inherent_impls(impl_ty)
|
||||
.into_iter()
|
||||
.iter()
|
||||
.flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
|
||||
.find(|item| item.kind == AssocKind::Fn);
|
||||
|
||||
|
@ -628,7 +628,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
/// Checks the inherent impl's items for an `is_empty(self)` method.
|
||||
fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
|
||||
let is_empty = sym!(is_empty);
|
||||
cx.tcx.inherent_impls(id).into_iter().any(|imp| {
|
||||
cx.tcx.inherent_impls(id).iter().any(|imp| {
|
||||
cx.tcx
|
||||
.associated_items(*imp)
|
||||
.filter_by_name_unhygienic(is_empty)
|
||||
|
|
|
@ -609,7 +609,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(move |tcx| Box::new(await_holding_invalid::AwaitHolding::new(tcx, conf)));
|
||||
store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
|
||||
store.register_late_pass(move |_| Box::new(types::Types::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
|
||||
store.register_late_pass(move |_| Box::new(booleans::NonminimalBool::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
|
||||
store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
|
||||
store.register_late_pass(|_| Box::new(ptr::Ptr));
|
||||
|
|
|
@ -6,12 +6,12 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::FnRetTy::Return;
|
||||
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
|
||||
use rustc_hir::intravisit::{
|
||||
Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
|
||||
walk_poly_trait_ref, walk_trait_ref, walk_ty,
|
||||
Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
|
||||
walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate,
|
||||
};
|
||||
use rustc_hir::{
|
||||
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl,
|
||||
ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
|
||||
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
|
||||
Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
|
||||
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
@ -21,7 +21,7 @@ use rustc_middle::lint::in_external_macro;
|
|||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw};
|
||||
use rustc_span::symbol::{Ident, kw};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -191,45 +191,10 @@ fn check_fn_inner<'tcx>(
|
|||
if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lts = elidable_lts
|
||||
.iter()
|
||||
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
||||
// `Node::GenericParam`.
|
||||
.filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|<| cx.tcx.def_span(lt))
|
||||
.chain(usages.iter().filter_map(|usage| {
|
||||
if let LifetimeName::Param(def_id) = usage.res
|
||||
&& elidable_lts.contains(&def_id)
|
||||
{
|
||||
return Some(usage.ident.span);
|
||||
}
|
||||
|
||||
None
|
||||
}))
|
||||
.collect_vec(),
|
||||
format!("the following explicit lifetimes could be elided: {lts}"),
|
||||
|diag| {
|
||||
if sig.header.is_async() {
|
||||
// async functions have usages whose spans point at the lifetime declaration which messes up
|
||||
// suggestions
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) {
|
||||
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
// async functions have usages whose spans point at the lifetime declaration which messes up
|
||||
// suggestions
|
||||
let include_suggestions = !sig.header.is_async();
|
||||
report_elidable_lifetimes(cx, generics, &elidable_lts, &usages, include_suggestions);
|
||||
}
|
||||
|
||||
if report_extra_lifetimes {
|
||||
|
@ -237,97 +202,6 @@ fn check_fn_inner<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn elision_suggestions(
|
||||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
) -> Option<Vec<(Span, String)>> {
|
||||
let explicit_params = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut suggestions = if elidable_lts.len() == explicit_params.len() {
|
||||
// if all the params are elided remove the whole generic block
|
||||
//
|
||||
// fn x<'a>() {}
|
||||
// ^^^^
|
||||
vec![(generics.span, String::new())]
|
||||
} else {
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
let pos = explicit_params.iter().position(|param| param.def_id == id)?;
|
||||
let param = explicit_params.get(pos)?;
|
||||
|
||||
let span = if let Some(next) = explicit_params.get(pos + 1) {
|
||||
// fn x<'prev, 'a, 'next>() {}
|
||||
// ^^^^
|
||||
param.span.until(next.span)
|
||||
} else {
|
||||
// `pos` should be at least 1 here, because the param in position 0 would either have a `next`
|
||||
// param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
|
||||
let prev = explicit_params.get(pos - 1)?;
|
||||
|
||||
// fn x<'prev, 'a>() {}
|
||||
// ^^^^
|
||||
param.span.with_lo(prev.span.hi())
|
||||
};
|
||||
|
||||
Some((span, String::new()))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
};
|
||||
|
||||
suggestions.extend(
|
||||
usages
|
||||
.iter()
|
||||
.filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
|
||||
.map(|usage| {
|
||||
match cx.tcx.parent_hir_node(usage.hir_id) {
|
||||
Node::Ty(Ty {
|
||||
kind: TyKind::Ref(..), ..
|
||||
}) => {
|
||||
// expand `&'a T` to `&'a T`
|
||||
// ^^ ^^^
|
||||
let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
|
||||
|
||||
(span, String::new())
|
||||
},
|
||||
// `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
|
||||
_ => (usage.ident.span, String::from("'_")),
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Some(suggestions)
|
||||
}
|
||||
|
||||
// elision doesn't work for explicit self types, see rust-lang/rust#69064
|
||||
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
|
||||
if let Some(ident) = ident
|
||||
&& ident.name == kw::SelfLower
|
||||
&& !func.implicit_self.has_implicit_self()
|
||||
&& let Some(self_ty) = func.inputs.first()
|
||||
{
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
visitor.visit_ty(self_ty);
|
||||
|
||||
!visitor.all_lts().is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
|
||||
match lt.res {
|
||||
LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn could_use_elision<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
func: &'tcx FnDecl<'_>,
|
||||
|
@ -450,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId
|
|||
.collect()
|
||||
}
|
||||
|
||||
// elision doesn't work for explicit self types, see rust-lang/rust#69064
|
||||
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
|
||||
if let Some(ident) = ident
|
||||
&& ident.name == kw::SelfLower
|
||||
&& !func.implicit_self.has_implicit_self()
|
||||
&& let Some(self_ty) = func.inputs.first()
|
||||
{
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
visitor.visit_ty(self_ty);
|
||||
|
||||
!visitor.all_lts().is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
|
||||
/// relative order.
|
||||
#[must_use]
|
||||
|
@ -470,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
|
|||
occurrences
|
||||
}
|
||||
|
||||
fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
|
||||
match lt.res {
|
||||
LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
struct RefVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
lts: Vec<Lifetime>,
|
||||
|
@ -500,7 +397,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
self.lts.push(*lifetime);
|
||||
|
@ -594,23 +491,43 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
|
|||
false
|
||||
}
|
||||
|
||||
struct Usage {
|
||||
lifetime: Lifetime,
|
||||
in_where_predicate: bool,
|
||||
in_generics_arg: bool,
|
||||
}
|
||||
|
||||
struct LifetimeChecker<'cx, 'tcx, F> {
|
||||
cx: &'cx LateContext<'tcx>,
|
||||
map: FxHashMap<Symbol, Span>,
|
||||
map: FxHashMap<LocalDefId, Vec<Usage>>,
|
||||
where_predicate_depth: usize,
|
||||
generic_args_depth: usize,
|
||||
phantom: std::marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
|
||||
fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap<Symbol, Span>) -> LifetimeChecker<'cx, 'tcx, F> {
|
||||
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> {
|
||||
let map = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit,
|
||||
} => Some((par.def_id, Vec::new())),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
Self {
|
||||
cx,
|
||||
map,
|
||||
where_predicate_depth: 0,
|
||||
generic_args_depth: 0,
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
|
||||
impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
|
||||
where
|
||||
F: NestedFilter<'tcx>,
|
||||
{
|
||||
|
@ -619,18 +536,27 @@ where
|
|||
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
self.map.remove(&lifetime.ident.name);
|
||||
if let LifetimeName::Param(def_id) = lifetime.res
|
||||
&& let Some(usages) = self.map.get_mut(&def_id)
|
||||
{
|
||||
usages.push(Usage {
|
||||
lifetime: *lifetime,
|
||||
in_where_predicate: self.where_predicate_depth != 0,
|
||||
in_generics_arg: self.generic_args_depth != 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
|
||||
// don't actually visit `<'a>` or `<'a: 'b>`
|
||||
// we've already visited the `'a` declarations and
|
||||
// don't want to spuriously remove them
|
||||
// `'b` in `'a: 'b` is useless unless used elsewhere in
|
||||
// a non-lifetime bound
|
||||
if let GenericParamKind::Type { .. } = param.kind {
|
||||
walk_generic_param(self, param);
|
||||
}
|
||||
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
||||
self.where_predicate_depth += 1;
|
||||
walk_where_predicate(self, predicate);
|
||||
self.where_predicate_depth -= 1;
|
||||
}
|
||||
|
||||
fn visit_generic_args(&mut self, generic_args: &'tcx GenericArgs<'tcx>) -> Self::Result {
|
||||
self.generic_args_depth += 1;
|
||||
walk_generic_args(self, generic_args);
|
||||
self.generic_args_depth -= 1;
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
@ -639,44 +565,28 @@ where
|
|||
}
|
||||
|
||||
fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
|
||||
let hs = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit,
|
||||
} => Some((par.name.ident().name, par.span)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, hs);
|
||||
let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, generics);
|
||||
|
||||
walk_generics(&mut checker, generics);
|
||||
walk_fn_decl(&mut checker, func);
|
||||
|
||||
for &v in checker.map.values() {
|
||||
span_lint(
|
||||
cx,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
v,
|
||||
"this lifetime isn't used in the function definition",
|
||||
);
|
||||
for (def_id, usages) in checker.map {
|
||||
if usages
|
||||
.iter()
|
||||
.all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
cx.tcx.def_span(def_id),
|
||||
"this lifetime isn't used in the function definition",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) {
|
||||
let hs = impl_
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit,
|
||||
} => Some((par.name.ident().name, par.span)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, hs);
|
||||
let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, impl_.generics);
|
||||
|
||||
walk_generics(&mut checker, impl_.generics);
|
||||
if let Some(ref trait_ref) = impl_.of_trait {
|
||||
|
@ -687,9 +597,176 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
|
|||
walk_impl_item_ref(&mut checker, item);
|
||||
}
|
||||
|
||||
for &v in checker.map.values() {
|
||||
span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl");
|
||||
for (&def_id, usages) in &checker.map {
|
||||
if usages
|
||||
.iter()
|
||||
.all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
cx.tcx.def_span(def_id),
|
||||
"this lifetime isn't used in the impl",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
report_elidable_impl_lifetimes(cx, impl_, &checker.map);
|
||||
}
|
||||
|
||||
// An `impl` lifetime is elidable if it satisfies the following conditions:
|
||||
// - It is used exactly once.
|
||||
// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are
|
||||
// different from `GenericParam`s.)
|
||||
fn report_elidable_impl_lifetimes<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
impl_: &'tcx Impl<'_>,
|
||||
map: &FxHashMap<LocalDefId, Vec<Usage>>,
|
||||
) {
|
||||
let single_usages = map
|
||||
.iter()
|
||||
.filter_map(|(def_id, usages)| {
|
||||
if let [
|
||||
Usage {
|
||||
lifetime,
|
||||
in_where_predicate: false,
|
||||
..
|
||||
}
|
||||
| Usage {
|
||||
lifetime,
|
||||
in_generics_arg: false,
|
||||
..
|
||||
},
|
||||
] = usages.as_slice()
|
||||
{
|
||||
Some((def_id, lifetime))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if single_usages.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip();
|
||||
|
||||
report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true);
|
||||
}
|
||||
|
||||
/// Generate diagnostic messages for elidable lifetimes.
|
||||
fn report_elidable_lifetimes(
|
||||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
include_suggestions: bool,
|
||||
) {
|
||||
let lts = elidable_lts
|
||||
.iter()
|
||||
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
||||
// `Node::GenericParam`.
|
||||
.filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|<| cx.tcx.def_span(lt))
|
||||
.chain(usages.iter().filter_map(|usage| {
|
||||
if let LifetimeName::Param(def_id) = usage.res
|
||||
&& elidable_lts.contains(&def_id)
|
||||
{
|
||||
return Some(usage.ident.span);
|
||||
}
|
||||
|
||||
None
|
||||
}))
|
||||
.collect_vec(),
|
||||
format!("the following explicit lifetimes could be elided: {lts}"),
|
||||
|diag| {
|
||||
if !include_suggestions {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) {
|
||||
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn elision_suggestions(
|
||||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
) -> Option<Vec<(Span, String)>> {
|
||||
let explicit_params = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut suggestions = if elidable_lts.len() == explicit_params.len() {
|
||||
// if all the params are elided remove the whole generic block
|
||||
//
|
||||
// fn x<'a>() {}
|
||||
// ^^^^
|
||||
vec![(generics.span, String::new())]
|
||||
} else {
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
let pos = explicit_params.iter().position(|param| param.def_id == id)?;
|
||||
let param = explicit_params.get(pos)?;
|
||||
|
||||
let span = if let Some(next) = explicit_params.get(pos + 1) {
|
||||
// fn x<'prev, 'a, 'next>() {}
|
||||
// ^^^^
|
||||
param.span.until(next.span)
|
||||
} else {
|
||||
// `pos` should be at least 1 here, because the param in position 0 would either have a `next`
|
||||
// param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
|
||||
let prev = explicit_params.get(pos - 1)?;
|
||||
|
||||
// fn x<'prev, 'a>() {}
|
||||
// ^^^^
|
||||
param.span.with_lo(prev.span.hi())
|
||||
};
|
||||
|
||||
Some((span, String::new()))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
};
|
||||
|
||||
suggestions.extend(
|
||||
usages
|
||||
.iter()
|
||||
.filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
|
||||
.map(|usage| {
|
||||
match cx.tcx.parent_hir_node(usage.hir_id) {
|
||||
Node::Ty(Ty {
|
||||
kind: TyKind::Ref(..), ..
|
||||
}) => {
|
||||
// expand `&'a T` to `&'a T`
|
||||
// ^^ ^^^
|
||||
let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
|
||||
|
||||
(span, String::new())
|
||||
},
|
||||
// `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
|
||||
_ => (usage.ident.span, String::from("'_")),
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Some(suggestions)
|
||||
}
|
||||
|
||||
struct BodyLifetimeChecker;
|
||||
|
|
|
@ -209,7 +209,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
#[derive(Clone)]
|
||||
struct MinifyingSugg<'a>(Sugg<'a>);
|
||||
|
||||
impl<'a> Display for MinifyingSugg<'a> {
|
||||
impl Display for MinifyingSugg<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::MISSING_SPIN_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_no_std_crate;
|
||||
use clippy_utils::std_or_core;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -41,6 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
|
|||
&& [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
|
||||
&& let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind()
|
||||
&& cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did())
|
||||
&& let Some(std_or_core) = std_or_core(cx)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -48,12 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
|
|||
body.span,
|
||||
"busy-waiting loop should at least have a spin loop hint",
|
||||
"try",
|
||||
(if is_no_std_crate(cx) {
|
||||
"{ core::hint::spin_loop() }"
|
||||
} else {
|
||||
"{ std::hint::spin_loop() }"
|
||||
})
|
||||
.into(),
|
||||
format!("{{ {std_or_core}::hint::spin_loop() }}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -241,7 +241,7 @@ struct VarVisitor<'a, 'tcx> {
|
|||
prefer_mutable: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
||||
impl<'tcx> VarVisitor<'_, 'tcx> {
|
||||
fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
|
||||
if let ExprKind::Path(ref seqpath) = seqexpr.kind
|
||||
// the indexed container is referenced by a name
|
||||
|
@ -292,7 +292,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind
|
||||
// a range index op
|
||||
|
|
|
@ -123,7 +123,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
match &expr.kind {
|
||||
// Non-determinism may occur ... don't give a lint
|
||||
|
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
// If node is a variable
|
||||
if let Some(def_id) = path_to_local(expr) {
|
||||
|
@ -138,7 +138,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
|
||||
|
|
|
@ -84,7 +84,7 @@ struct VarCollectorVisitor<'a, 'tcx> {
|
|||
skip: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
|
||||
impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
|
||||
fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Path(ref qpath) = ex.kind
|
||||
&& let QPath::Resolved(None, _) = *qpath
|
||||
|
@ -103,7 +103,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
match ex.kind {
|
||||
ExprKind::Path(_) => self.insert_def_id(ex),
|
||||
|
|
|
@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
found_local: bool,
|
||||
used_after: bool,
|
||||
}
|
||||
impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
|
|
|
@ -149,7 +149,7 @@ fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
|
|||
&& !cx.tcx.is_doc_hidden(def_id)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for BodyVisitor<'_, 'tcx> {
|
||||
fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
|
||||
let from_expn = s.span.from_expansion();
|
||||
if from_expn {
|
||||
|
|
|
@ -81,7 +81,7 @@ impl MacroUseImports {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
|
||||
impl LateLintPass<'_> for MacroUseImports {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
if cx.sess().opts.edition >= Edition::Edition2018
|
||||
&& let hir::ItemKind::Use(path, _kind) = &item.kind
|
||||
|
|
|
@ -741,7 +741,7 @@ enum MaybeBorrowedStmtKind<'a> {
|
|||
Owned(StmtKind<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Clone for MaybeBorrowedStmtKind<'a> {
|
||||
impl Clone for MaybeBorrowedStmtKind<'_> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Borrowed(t) => Self::Borrowed(t),
|
||||
|
|
|
@ -203,7 +203,7 @@ fn find_stripping<'tcx>(
|
|||
results: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
if is_ref_str(self.cx, ex)
|
||||
&& let unref = peel_ref(ex)
|
||||
|
|
|
@ -251,7 +251,7 @@ fn lint_map_unit_fn(
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MapUnit {
|
||||
impl LateLintPass<'_> for MapUnit {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
|
||||
if let hir::StmtKind::Semi(expr) = stmt.kind
|
||||
&& !stmt.span.from_expansion()
|
||||
|
|
|
@ -40,7 +40,7 @@ struct MatchExprVisitor<'a, 'tcx> {
|
|||
case_method: Option<CaseMethod>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
match ex.kind {
|
||||
ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
|
||||
|
@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
|
||||
impl MatchExprVisitor<'_, '_> {
|
||||
fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
|
||||
if let Some(case_method) = get_case_method(segment_ident) {
|
||||
let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
|
||||
|
|
|
@ -1045,7 +1045,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
|||
if !from_expansion {
|
||||
// These don't depend on a relationship between multiple arms
|
||||
match_wild_err_arm::check(cx, ex, arms);
|
||||
wild_in_or_pats::check(cx, arms);
|
||||
wild_in_or_pats::check(cx, ex, arms);
|
||||
}
|
||||
|
||||
if let MatchSource::TryDesugar(_) = source {
|
||||
|
|
|
@ -96,13 +96,13 @@ where
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
|
||||
|
||||
impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
|
||||
impl<T: Copy + Ord> PartialOrd for RangeBound<'_, T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
|
||||
impl<T: Copy + Ord> Ord for RangeBound<'_, T> {
|
||||
fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
|
||||
let RangeBound(self_value, self_kind, _) = *self;
|
||||
(self_value, self_kind).cmp(&(*other_value, *other_kind))
|
||||
|
|
|
@ -424,7 +424,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
|
|||
ty.visit_with(&mut V).is_break()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
// We've emitted a lint on some neighborhood expression. That lint will suggest to move out the
|
||||
// _parent_ expression (not the expression itself). Since we decide to move out the parent
|
||||
|
@ -495,7 +495,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr
|
|||
helper.found_sig_drop_spans
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ArmSigDropHelper<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
if self.sig_drop_checker.is_sig_drop_expr(ex) {
|
||||
self.found_sig_drop_spans.insert(ex.span);
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_wild;
|
||||
use rustc_hir::{Arm, PatKind};
|
||||
use clippy_utils::{has_non_exhaustive_attr, is_wild};
|
||||
use rustc_hir::{Arm, Expr, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
|
||||
use super::WILDCARD_IN_OR_PATTERNS;
|
||||
|
||||
pub(crate) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
|
||||
pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||
// first check if we are matching on an enum that has the non_exhaustive attribute
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
if let ty::Adt(adt_def, _) = ty.kind()
|
||||
&& has_non_exhaustive_attr(cx.tcx, *adt_def)
|
||||
{
|
||||
return;
|
||||
};
|
||||
for arm in arms {
|
||||
if let PatKind::Or(fields) = arm.pat.kind {
|
||||
// look for multiple fields in this arm that contains at least one Wild pattern
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::expr_custom_deref_adjustment;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use super::MUT_MUTEX_LOCK;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
|
||||
if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut))
|
||||
&& let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind()
|
||||
&& let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv))
|
||||
&& ref_depth >= 1
|
||||
&& let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
|
||||
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
|
||||
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
|
||||
|
|
|
@ -441,7 +441,7 @@ struct UsedCountVisitor<'a, 'tcx> {
|
|||
count: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
@ -130,7 +130,7 @@ struct UnwrapVisitor<'a, 'tcx> {
|
|||
identifiers: FxHashSet<HirId>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) {
|
||||
|
@ -154,7 +154,7 @@ struct ReferenceVisitor<'a, 'tcx> {
|
|||
unwrap_or_span: Span,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> {
|
||||
|
|
|
@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
|
|||
let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| {
|
||||
cx.tcx
|
||||
.inherent_impls(adt_def.did())
|
||||
.into_iter()
|
||||
.iter()
|
||||
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
|
||||
.find_map(|assoc| {
|
||||
if assoc.fn_has_self_parameter
|
||||
|
|
|
@ -86,7 +86,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
|
|||
references_to_binding: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
@ -123,7 +123,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
impl<'tcx> CloneOrCopyVisitor<'_, 'tcx> {
|
||||
fn is_binding(&self, expr: &Expr<'tcx>) -> bool {
|
||||
self.binding_hir_ids
|
||||
.iter()
|
||||
|
|
|
@ -116,7 +116,7 @@ struct DivergenceVisitor<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
|
||||
impl<'tcx> DivergenceVisitor<'_, 'tcx> {
|
||||
fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
match e.kind {
|
||||
ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {},
|
||||
|
@ -148,7 +148,7 @@ fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
|
|||
!matches!(stmt.kind, StmtKind::Item(..))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
match e.kind {
|
||||
// fix #10776
|
||||
|
@ -321,7 +321,7 @@ struct ReadVisitor<'a, 'tcx> {
|
|||
last_expr: &'tcx Expr<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if expr.hir_id == self.last_expr.hir_id {
|
||||
return;
|
||||
|
|
|
@ -55,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
|
||||
if in_external_macro(self.cx.sess(), expr.span) {
|
||||
return;
|
||||
|
|
|
@ -87,7 +87,7 @@ impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
@ -133,7 +133,7 @@ struct RetCollector {
|
|||
loop_depth: u16,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RetCollector {
|
||||
impl Visitor<'_> for RetCollector {
|
||||
fn visit_expr(&mut self, expr: &Expr<'_>) {
|
||||
match expr.kind {
|
||||
ExprKind::Ret(..) => {
|
||||
|
|
|
@ -311,7 +311,7 @@ struct MutablyUsedVariablesCtxt<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
|
||||
impl MutablyUsedVariablesCtxt<'_> {
|
||||
fn add_mutably_used_var(&mut self, used_id: HirId) {
|
||||
self.mutably_used_vars.insert(used_id);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> {
|
|||
single_char_names: Vec<Vec<Ident>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
|
||||
impl SimilarNamesLocalVisitor<'_, '_> {
|
||||
fn check_single_char_names(&self) {
|
||||
if self.single_char_names.last().map(Vec::len) == Some(0) {
|
||||
return;
|
||||
|
@ -152,7 +152,7 @@ fn chars_are_similar(a: char, b: char) -> bool {
|
|||
|
||||
struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
|
||||
|
||||
impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
impl<'tcx> Visitor<'tcx> for SimilarNamesNameVisitor<'_, 'tcx, '_> {
|
||||
fn visit_pat(&mut self, pat: &'tcx Pat) {
|
||||
match pat.kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
|
@ -189,7 +189,7 @@ fn allowed_to_be_similar(interned_name: &str, list: &[&str]) -> bool {
|
|||
.any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
impl SimilarNamesNameVisitor<'_, '_, '_> {
|
||||
fn check_short_ident(&mut self, ident: Ident) {
|
||||
// Ignore shadowing
|
||||
if self
|
||||
|
@ -329,7 +329,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
|
||||
impl SimilarNamesLocalVisitor<'_, '_> {
|
||||
/// ensure scoping rules work
|
||||
fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
|
||||
let n = self.names.len();
|
||||
|
@ -340,7 +340,7 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> {
|
||||
fn visit_local(&mut self, local: &'tcx Local) {
|
||||
if let Some((init, els)) = &local.kind.init_else_opt() {
|
||||
self.apply(|this| walk_expr(this, init));
|
||||
|
|
|
@ -159,7 +159,7 @@ struct NonSendField<'tcx> {
|
|||
generic_params: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> NonSendField<'tcx> {
|
||||
impl NonSendField<'_> {
|
||||
fn generic_params_string(&self) -> String {
|
||||
self.generic_params
|
||||
.iter()
|
||||
|
|
|
@ -110,7 +110,7 @@ pub struct PassByRefOrValue {
|
|||
avoid_breaking_exported_api: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> PassByRefOrValue {
|
||||
impl PassByRefOrValue {
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| {
|
||||
let bit_width = u64::from(tcx.sess.target.pointer_width);
|
||||
|
@ -130,7 +130,7 @@ impl<'tcx> PassByRefOrValue {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
|
||||
fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
|
||||
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ struct PathbufPushSearcher<'tcx> {
|
|||
err_span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> PathbufPushSearcher<'tcx> {
|
||||
impl PathbufPushSearcher<'_> {
|
||||
/// Try to generate a suggestion with `PathBuf::from`.
|
||||
/// Returns `None` if the suggestion would be invalid.
|
||||
fn gen_pathbuf_from(&self, cx: &LateContext<'_>) -> Option<String> {
|
||||
|
|
|
@ -271,14 +271,18 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
&& let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
|
||||
&& let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id)
|
||||
{
|
||||
// TODO: `ptr_slice_from_raw_parts` and its mutable variant should probably still be linted
|
||||
// conditionally based on how the return value is used, but not universally like the other
|
||||
// functions since there are valid uses for null slice pointers.
|
||||
//
|
||||
// See: https://github.com/rust-lang/rust-clippy/pull/13452/files#r1773772034
|
||||
|
||||
// `arg` positions where null would cause U.B.
|
||||
let arg_indices: &[_] = match name {
|
||||
sym::ptr_read
|
||||
| sym::ptr_read_unaligned
|
||||
| sym::ptr_read_volatile
|
||||
| sym::ptr_replace
|
||||
| sym::ptr_slice_from_raw_parts
|
||||
| sym::ptr_slice_from_raw_parts_mut
|
||||
| sym::ptr_write
|
||||
| sym::ptr_write_bytes
|
||||
| sym::ptr_write_unaligned
|
||||
|
|
|
@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
|
|||
path: &'tcx hir::Path<'tcx>,
|
||||
count: usize,
|
||||
}
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ClosureUsageCount<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
|
|
|
@ -140,7 +140,7 @@ enum RetReplacement<'tcx> {
|
|||
Expr(Cow<'tcx, str>, Applicability),
|
||||
}
|
||||
|
||||
impl<'tcx> RetReplacement<'tcx> {
|
||||
impl RetReplacement<'_> {
|
||||
fn sugg_help(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Empty | Self::Expr(..) => "remove `return`",
|
||||
|
@ -158,7 +158,7 @@ impl<'tcx> RetReplacement<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Display for RetReplacement<'tcx> {
|
||||
impl Display for RetReplacement<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Empty => write!(f, ""),
|
||||
|
@ -421,7 +421,7 @@ fn check_final_expr<'tcx>(
|
|||
if matches!(Level::from_attr(attr), Some(Level::Expect(_)))
|
||||
&& let metas = attr.meta_item_list()
|
||||
&& let Some(lst) = metas
|
||||
&& let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice()
|
||||
&& let [NestedMetaItem::MetaItem(meta_item), ..] = lst.as_slice()
|
||||
&& let [tool, lint_name] = meta_item.path.segments.as_slice()
|
||||
&& tool.ident.name == sym::clippy
|
||||
&& matches!(
|
||||
|
|
|
@ -249,7 +249,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> {
|
||||
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
|
||||
self.ap.curr_block_hir_id = block.hir_id;
|
||||
self.ap.curr_block_span = block.span;
|
||||
|
|
|
@ -102,7 +102,7 @@ struct ImportUsageVisitor {
|
|||
imports_referenced_with_self: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ImportUsageVisitor {
|
||||
impl Visitor<'_> for ImportUsageVisitor {
|
||||
fn visit_expr(&mut self, expr: &Expr) {
|
||||
if let ExprKind::Path(_, path) = &expr.kind
|
||||
&& path.segments.len() > 1
|
||||
|
|
|
@ -229,7 +229,7 @@ struct VectorInitializationVisitor<'a, 'tcx> {
|
|||
initialization_found: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
|
||||
impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
|
||||
/// Checks if the given expression is extending a vector with `repeat(0).take(..)`
|
||||
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if self.initialization_found
|
||||
|
@ -299,7 +299,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for VectorInitializationVisitor<'_, 'tcx> {
|
||||
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
|
||||
if self.initialization_found {
|
||||
match stmt.kind {
|
||||
|
|
|
@ -332,7 +332,7 @@ struct IndexBinding<'a, 'tcx> {
|
|||
applicability: &'a mut Applicability,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> IndexBinding<'a, 'tcx> {
|
||||
impl<'tcx> IndexBinding<'_, 'tcx> {
|
||||
fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String {
|
||||
let mut bindings = FxHashSet::default();
|
||||
for expr in exprs {
|
||||
|
|
|
@ -275,12 +275,15 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
|||
|k, ps1, idx| matches!(
|
||||
k,
|
||||
TupleStruct(qself2, path2, ps2)
|
||||
if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
|
||||
if eq_maybe_qself(qself1.as_ref(), qself2.as_ref())
|
||||
&& eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
|
||||
),
|
||||
|k| always_pat!(k, TupleStruct(_, _, ps) => ps),
|
||||
),
|
||||
// Transform a record pattern `S { fp_0, ..., fp_n }`.
|
||||
Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives),
|
||||
Struct(qself1, path1, fps1, rest1) => {
|
||||
extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives)
|
||||
},
|
||||
};
|
||||
|
||||
alternatives[focus_idx].kind = focus_kind;
|
||||
|
@ -292,7 +295,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
|||
/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
|
||||
/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
|
||||
fn extend_with_struct_pat(
|
||||
qself1: &Option<P<ast::QSelf>>,
|
||||
qself1: Option<&P<ast::QSelf>>,
|
||||
path1: &ast::Path,
|
||||
fps1: &mut [ast::PatField],
|
||||
rest1: ast::PatFieldsRest,
|
||||
|
@ -307,7 +310,7 @@ fn extend_with_struct_pat(
|
|||
|k| {
|
||||
matches!(k, Struct(qself2, path2, fps2, rest2)
|
||||
if rest1 == *rest2 // If one struct pattern has `..` so must the other.
|
||||
&& eq_maybe_qself(qself1, qself2)
|
||||
&& eq_maybe_qself(qself1, qself2.as_ref())
|
||||
&& eq_path(path1, path2)
|
||||
&& fps1.len() == fps2.len()
|
||||
&& fps1.iter().enumerate().all(|(idx_1, fp1)| {
|
||||
|
|
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
|
|||
use clippy_utils::is_def_id_trait_method;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
@ -67,7 +67,7 @@ struct AsyncFnVisitor<'a, 'tcx> {
|
|||
async_depth: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
|
@ -137,17 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
|
||||
fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
|
||||
matches!(
|
||||
node,
|
||||
Node::Expr(Expr {
|
||||
kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
|
||||
..
|
||||
}) if *span == expected_receiver
|
||||
)
|
||||
}
|
||||
|
||||
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: HirId) {
|
||||
// Find paths to local async functions that aren't immediately called.
|
||||
// E.g. `async fn f() {}; let x = f;`
|
||||
// Depending on how `x` is used, f's asyncness might be required despite not having any `await`
|
||||
|
@ -156,7 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
|
|||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& cx.tcx.def_kind(def_id) == DefKind::Fn
|
||||
&& cx.tcx.asyncness(def_id).is_async()
|
||||
&& !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span)
|
||||
&& let parent = cx.tcx.parent_hir_node(hir_id)
|
||||
&& !matches!(
|
||||
parent,
|
||||
Node::Expr(Expr {
|
||||
kind: ExprKind::Call(Expr { span, .. }, _),
|
||||
..
|
||||
}) if *span == path.span
|
||||
)
|
||||
{
|
||||
self.async_fns_as_value.insert(local_def_id);
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
|
|||
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
|
||||
impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> {
|
||||
fn visit_branch(
|
||||
&mut self,
|
||||
if_expr: &'tcx Expr<'_>,
|
||||
|
@ -288,7 +288,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
@ -280,7 +280,7 @@ struct SkipTyCollector {
|
|||
types_to_skip: Vec<HirId>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for SkipTyCollector {
|
||||
impl Visitor<'_> for SkipTyCollector {
|
||||
fn visit_infer(&mut self, inf: &hir::InferArg) {
|
||||
self.types_to_skip.push(inf.hir_id);
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
|
|||
&& let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
|
||||
&& match_type(cx, ty, &paths::SYMBOL)
|
||||
&& let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
|
||||
&& let Ok(value) = value.to_u32()
|
||||
&& let Some(value) = value.to_u32().discard_err()
|
||||
{
|
||||
self.symbol_map.insert(value, item_def_id);
|
||||
}
|
||||
|
|
|
@ -72,8 +72,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
|
|||
SimplifiedType::Bool,
|
||||
]
|
||||
.iter()
|
||||
.flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter())
|
||||
.flatten()
|
||||
.flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
|
||||
.copied();
|
||||
for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
|
||||
let lang_item_path = cx.get_def_path(item_def_id);
|
||||
|
|
|
@ -270,7 +270,7 @@ struct LintCollector<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::sym;
|
||||
use std::ops::ControlFlow;
|
||||
|
@ -118,7 +119,8 @@ enum WaitFinder<'a, 'tcx> {
|
|||
Found(&'a LateContext<'tcx>, HirId),
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
type Result = ControlFlow<BreakReason>;
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result {
|
||||
|
@ -204,6 +206,11 @@ impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> {
|
|||
|
||||
walk_expr(self, ex)
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
let (Self::Found(cx, _) | Self::WalkUpTo(cx, _)) = self;
|
||||
cx.tcx.hir()
|
||||
}
|
||||
}
|
||||
|
||||
/// This function has shared logic between the different kinds of nodes that can trigger the lint.
|
||||
|
@ -300,7 +307,7 @@ struct ExitPointFinder<'a, 'tcx> {
|
|||
|
||||
struct ExitCallFound;
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ExitPointFinder<'_, 'tcx> {
|
||||
type Result = ControlFlow<ExitCallFound>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
|
||||
|
|
|
@ -37,20 +37,27 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
|||
(_, Paren(r)) => eq_pat(l, r),
|
||||
(Wild, Wild) | (Rest, Rest) => true,
|
||||
(Lit(l), Lit(r)) => eq_expr(l, r),
|
||||
(Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)),
|
||||
(Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
|
||||
b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
|
||||
},
|
||||
(Range(lf, lt, le), Range(rf, rt, re)) => {
|
||||
eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node)
|
||||
eq_expr_opt(lf.as_ref(), rf.as_ref())
|
||||
&& eq_expr_opt(lt.as_ref(), rt.as_ref())
|
||||
&& eq_range_end(&le.node, &re.node)
|
||||
},
|
||||
(Box(l), Box(r))
|
||||
| (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
|
||||
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
|
||||
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
|
||||
(TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
|
||||
eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
|
||||
eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
|
||||
},
|
||||
(Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
|
||||
lr == rr && eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat)
|
||||
lr == rr
|
||||
&& eq_maybe_qself(lqself.as_ref(), rqself.as_ref())
|
||||
&& eq_path(lp, rp)
|
||||
&& unordered_over(lfs, rfs, eq_field_pat)
|
||||
},
|
||||
(Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
|
@ -79,7 +86,7 @@ pub fn eq_qself(l: &P<QSelf>, r: &P<QSelf>) -> bool {
|
|||
l.position == r.position && eq_ty(&l.ty, &r.ty)
|
||||
}
|
||||
|
||||
pub fn eq_maybe_qself(l: &Option<P<QSelf>>, r: &Option<P<QSelf>>) -> bool {
|
||||
pub fn eq_maybe_qself(l: Option<&P<QSelf>>, r: Option<&P<QSelf>>) -> bool {
|
||||
match (l, r) {
|
||||
(Some(l), Some(r)) => eq_qself(l, r),
|
||||
(None, None) => true,
|
||||
|
@ -92,7 +99,7 @@ pub fn eq_path(l: &Path, r: &Path) -> bool {
|
|||
}
|
||||
|
||||
pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
|
||||
eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r))
|
||||
eq_id(l.ident, r.ident) && both(l.args.as_ref(), r.args.as_ref(), |l, r| eq_generic_args(l, r))
|
||||
}
|
||||
|
||||
pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
|
||||
|
@ -122,7 +129,7 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
|
||||
pub fn eq_expr_opt(l: Option<&P<Expr>>, r: Option<&P<Expr>>) -> bool {
|
||||
both(l, r, |l, r| eq_expr(l, r))
|
||||
}
|
||||
|
||||
|
@ -169,8 +176,12 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
|||
(Lit(l), Lit(r)) => l == r,
|
||||
(Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
|
||||
(Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re),
|
||||
(If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
|
||||
(While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
|
||||
(If(lc, lt, le), If(rc, rt, re)) => {
|
||||
eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref())
|
||||
},
|
||||
(While(lc, lt, ll), While(rc, rt, rl)) => {
|
||||
eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt)
|
||||
},
|
||||
(
|
||||
ForLoop {
|
||||
pat: lp,
|
||||
|
@ -186,13 +197,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
|||
label: rl,
|
||||
kind: rk,
|
||||
},
|
||||
) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
|
||||
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt),
|
||||
(Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
|
||||
) => eq_label(ll.as_ref(), rl.as_ref()) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
|
||||
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
|
||||
(Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
|
||||
(TryBlock(l), TryBlock(r)) => eq_block(l, r),
|
||||
(Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
|
||||
(Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
|
||||
(Continue(ll), Continue(rl)) => eq_label(ll, rl),
|
||||
(Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()),
|
||||
(Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()),
|
||||
(Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
|
||||
(Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
|
||||
eq_expr(l1, r1) && eq_expr(l2, r2)
|
||||
},
|
||||
|
@ -227,12 +238,14 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
|||
&& eq_expr(le, re)
|
||||
},
|
||||
(Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk,
|
||||
(Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
|
||||
(Range(lf, lt, ll), Range(rf, rt, rl)) => {
|
||||
ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref())
|
||||
},
|
||||
(AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
(Struct(lse), Struct(rse)) => {
|
||||
eq_maybe_qself(&lse.qself, &rse.qself)
|
||||
eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref())
|
||||
&& eq_path(&lse.path, &rse.path)
|
||||
&& eq_struct_rest(&lse.rest, &rse.rest)
|
||||
&& unordered_over(&lse.fields, &rse.fields, eq_field)
|
||||
|
@ -264,12 +277,12 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
|
|||
pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
|
||||
l.is_placeholder == r.is_placeholder
|
||||
&& eq_pat(&l.pat, &r.pat)
|
||||
&& eq_expr_opt(&l.body, &r.body)
|
||||
&& eq_expr_opt(&l.guard, &r.guard)
|
||||
&& eq_expr_opt(l.body.as_ref(), r.body.as_ref())
|
||||
&& eq_expr_opt(l.guard.as_ref(), r.guard.as_ref())
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
}
|
||||
|
||||
pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
|
||||
pub fn eq_label(l: Option<&Label>, r: Option<&Label>) -> bool {
|
||||
both(l, r, |l, r| eq_id(l.ident, r.ident))
|
||||
}
|
||||
|
||||
|
@ -282,7 +295,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
|
|||
match (&l.kind, &r.kind) {
|
||||
(Let(l), Let(r)) => {
|
||||
eq_pat(&l.pat, &r.pat)
|
||||
&& both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
|
||||
&& both(l.ty.as_ref(), r.ty.as_ref(), |l, r| eq_ty(l, r))
|
||||
&& eq_local_kind(&l.kind, &r.kind)
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
},
|
||||
|
@ -329,7 +342,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
expr: re,
|
||||
safety: rs,
|
||||
}),
|
||||
) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
|
||||
(
|
||||
Const(box ConstItem {
|
||||
defaultness: ld,
|
||||
|
@ -343,7 +356,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
ty: rt,
|
||||
expr: re,
|
||||
}),
|
||||
) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
defaultness: ld,
|
||||
|
@ -358,7 +371,10 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
body: rb,
|
||||
}),
|
||||
) => {
|
||||
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_fn_sig(lf, rf)
|
||||
&& eq_generics(lg, rg)
|
||||
&& both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
|
||||
},
|
||||
(Mod(lu, lmk), Mod(ru, rmk)) => {
|
||||
lu == ru
|
||||
|
@ -371,7 +387,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
}
|
||||
},
|
||||
(ForeignMod(l), ForeignMod(r)) => {
|
||||
both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
|
||||
both(l.abi.as_ref(), r.abi.as_ref(), eq_str_lit)
|
||||
&& over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
|
||||
},
|
||||
(
|
||||
TyAlias(box ast::TyAlias {
|
||||
|
@ -392,7 +409,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& both(lt, rt, |l, r| eq_ty(l, r))
|
||||
&& both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
|
||||
},
|
||||
(Enum(le, lg), Enum(re, rg)) => over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg),
|
||||
(Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
|
||||
|
@ -448,7 +465,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
&& eq_defaultness(*ld, *rd)
|
||||
&& matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
|
||||
&& eq_generics(lg, rg)
|
||||
&& both(lot, rot, |l, r| eq_path(&l.path, &r.path))
|
||||
&& both(lot.as_ref(), rot.as_ref(), |l, r| eq_path(&l.path, &r.path))
|
||||
&& eq_ty(lst, rst)
|
||||
&& over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
|
||||
},
|
||||
|
@ -474,7 +491,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
|||
expr: re,
|
||||
safety: rs,
|
||||
}),
|
||||
) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re) && ls == rs,
|
||||
) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs,
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
defaultness: ld,
|
||||
|
@ -489,7 +506,10 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
|||
body: rb,
|
||||
}),
|
||||
) => {
|
||||
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_fn_sig(lf, rf)
|
||||
&& eq_generics(lg, rg)
|
||||
&& both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
|
||||
},
|
||||
(
|
||||
TyAlias(box ast::TyAlias {
|
||||
|
@ -510,7 +530,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
|||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& both(lt, rt, |l, r| eq_ty(l, r))
|
||||
&& both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
|
||||
},
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
_ => false,
|
||||
|
@ -533,7 +553,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
ty: rt,
|
||||
expr: re,
|
||||
}),
|
||||
) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
defaultness: ld,
|
||||
|
@ -548,7 +568,10 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
body: rb,
|
||||
}),
|
||||
) => {
|
||||
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_fn_sig(lf, rf)
|
||||
&& eq_generics(lg, rg)
|
||||
&& both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
|
||||
},
|
||||
(
|
||||
Type(box TyAlias {
|
||||
|
@ -569,7 +592,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& both(lt, rt, |l, r| eq_ty(l, r))
|
||||
&& both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
|
||||
},
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
_ => false,
|
||||
|
@ -582,7 +605,9 @@ pub fn eq_variant(l: &Variant, r: &Variant) -> bool {
|
|||
&& eq_vis(&l.vis, &r.vis)
|
||||
&& eq_id(l.ident, r.ident)
|
||||
&& eq_variant_data(&l.data, &r.data)
|
||||
&& both(&l.disr_expr, &r.disr_expr, |l, r| eq_expr(&l.value, &r.value))
|
||||
&& both(l.disr_expr.as_ref(), r.disr_expr.as_ref(), |l, r| {
|
||||
eq_expr(&l.value, &r.value)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool {
|
||||
|
@ -600,7 +625,7 @@ pub fn eq_struct_field(l: &FieldDef, r: &FieldDef) -> bool {
|
|||
l.is_placeholder == r.is_placeholder
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
&& eq_vis(&l.vis, &r.vis)
|
||||
&& both(&l.ident, &r.ident, |l, r| eq_id(*l, *r))
|
||||
&& both(l.ident.as_ref(), r.ident.as_ref(), |l, r| eq_id(*l, *r))
|
||||
&& eq_ty(&l.ty, &r.ty)
|
||||
}
|
||||
|
||||
|
@ -664,7 +689,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
|
|||
use UseTreeKind::*;
|
||||
match (l, r) {
|
||||
(Glob, Glob) => true,
|
||||
(Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)),
|
||||
(Simple(l), Simple(r)) => both(l.as_ref(), r.as_ref(), |l, r| eq_id(*l, *r)),
|
||||
(Nested { items: l, .. }, Nested { items: r, .. }) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -726,7 +751,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
|
|||
(Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
|
||||
(Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
|
||||
(Ref(ll, l), Ref(rl, r)) => {
|
||||
both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
|
||||
both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
|
||||
},
|
||||
(BareFn(l), BareFn(r)) => {
|
||||
l.safety == r.safety
|
||||
|
@ -735,7 +760,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
|
|||
&& eq_fn_decl(&l.decl, &r.decl)
|
||||
},
|
||||
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
|
||||
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
|
||||
(ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
|
||||
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
|
||||
|
@ -771,7 +796,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
|||
&& over(&l.bounds, &r.bounds, eq_generic_bound)
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(Lifetime, Lifetime) => true,
|
||||
(Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
|
||||
(Type { default: l }, Type { default: r }) => both(l.as_ref(), r.as_ref(), |l, r| eq_ty(l, r)),
|
||||
(
|
||||
Const {
|
||||
ty: lt,
|
||||
|
@ -783,7 +808,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
|||
kw_span: _,
|
||||
default: rd,
|
||||
},
|
||||
) => eq_ty(lt, rt) && both(ld, rd, eq_anon_const),
|
||||
) => eq_ty(lt, rt) && both(ld.as_ref(), rd.as_ref(), eq_anon_const),
|
||||
_ => false,
|
||||
}
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
|
|
|
@ -118,7 +118,7 @@ impl IntTypeBounds for IntTy {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PartialEq for Constant<'tcx> {
|
||||
impl PartialEq for Constant<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Str(ls), Self::Str(rs)) => ls == rs,
|
||||
|
@ -147,7 +147,7 @@ impl<'tcx> PartialEq for Constant<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Hash for Constant<'tcx> {
|
||||
impl Hash for Constant<'_> {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
|
@ -203,7 +203,7 @@ impl<'tcx> Hash for Constant<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Constant<'tcx> {
|
||||
impl Constant<'_> {
|
||||
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
|
||||
match (left, right) {
|
||||
(Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)),
|
||||
|
|
|
@ -118,7 +118,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
|
|||
eagerness: EagernessSuggestion,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
use EagernessSuggestion::{ForceNoChange, Lazy, NoChange};
|
||||
if self.eagerness == ForceNoChange {
|
||||
|
|
|
@ -121,9 +121,9 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
|
||||
// eq_pat adds the HirIds to the locals map. We therefore call it last to make sure that
|
||||
// these only get added if the init and type is equal.
|
||||
both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
|
||||
&& both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
|
||||
&& both(&l.els, &r.els, |l, r| self.eq_block(l, r))
|
||||
both(l.init.as_ref(), r.init.as_ref(), |l, r| self.eq_expr(l, r))
|
||||
&& both(l.ty.as_ref(), r.ty.as_ref(), |l, r| self.eq_ty(l, r))
|
||||
&& both(l.els.as_ref(), r.els.as_ref(), |l, r| self.eq_block(l, r))
|
||||
&& self.eq_pat(l.pat, r.pat)
|
||||
},
|
||||
(&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
|
||||
|
@ -142,7 +142,9 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
if lspan.ctxt != SyntaxContext::root() && rspan.ctxt != SyntaxContext::root() {
|
||||
// Don't try to check in between statements inside macros.
|
||||
return over(left.stmts, right.stmts, |left, right| self.eq_stmt(left, right))
|
||||
&& both(&left.expr, &right.expr, |left, right| self.eq_expr(left, right));
|
||||
&& both(left.expr.as_ref(), right.expr.as_ref(), |left, right| {
|
||||
self.eq_expr(left, right)
|
||||
});
|
||||
}
|
||||
if lspan.ctxt != rspan.ctxt {
|
||||
return false;
|
||||
|
@ -285,8 +287,8 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
})
|
||||
},
|
||||
(&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => {
|
||||
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
|
||||
&& both(le, re, |l, r| self.eq_expr(l, r))
|
||||
both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name)
|
||||
&& both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r))
|
||||
},
|
||||
(&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
|
||||
self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
|
||||
|
@ -297,7 +299,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
(&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false,
|
||||
(&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body),
|
||||
(&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
|
||||
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
|
||||
both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name)
|
||||
},
|
||||
(&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
|
||||
(&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
|
||||
|
@ -305,21 +307,25 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
},
|
||||
(&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
|
||||
(&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
|
||||
self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
|
||||
self.eq_expr(lc, rc) && self.eq_expr(lt, rt)
|
||||
&& both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r))
|
||||
},
|
||||
(&ExprKind::Let(l), &ExprKind::Let(r)) => {
|
||||
self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
|
||||
self.eq_pat(l.pat, r.pat)
|
||||
&& both(l.ty.as_ref(), r.ty.as_ref(), |l, r| self.eq_ty(l, r))
|
||||
&& self.eq_expr(l.init, r.init)
|
||||
},
|
||||
(ExprKind::Lit(l), ExprKind::Lit(r)) => l.node == r.node,
|
||||
(&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
|
||||
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
|
||||
lls == rls && self.eq_block(lb, rb)
|
||||
&& both(ll.as_ref(), rl.as_ref(), |l, r| l.ident.name == r.ident.name)
|
||||
},
|
||||
(&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
|
||||
(ls == rs || (matches!((ls, rs), (TryDesugar(_), TryDesugar(_)))))
|
||||
&& self.eq_expr(le, re)
|
||||
&& over(la, ra, |l, r| {
|
||||
self.eq_pat(l.pat, r.pat)
|
||||
&& both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r))
|
||||
&& both(l.guard.as_ref(), r.guard.as_ref(), |l, r| self.eq_expr(l, r))
|
||||
&& self.eq_expr(l.body, r.body)
|
||||
})
|
||||
},
|
||||
|
@ -339,10 +345,10 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
(&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
|
||||
self.eq_expr(le, re) && self.eq_array_length(ll, rl)
|
||||
},
|
||||
(ExprKind::Ret(l), ExprKind::Ret(r)) => both(l, r, |l, r| self.eq_expr(l, r)),
|
||||
(ExprKind::Ret(l), ExprKind::Ret(r)) => both(l.as_ref(), r.as_ref(), |l, r| self.eq_expr(l, r)),
|
||||
(&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
|
||||
self.eq_qpath(l_path, r_path)
|
||||
&& both(lo, ro, |l, r| self.eq_expr(l, r))
|
||||
&& both(lo.as_ref(), ro.as_ref(), |l, r| self.eq_expr(l, r))
|
||||
&& over(lf, rf, |l, r| self.eq_expr_field(l, r))
|
||||
},
|
||||
(&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
|
||||
|
@ -450,7 +456,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
|
||||
},
|
||||
(&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
|
||||
let eq = lb == rb && both(lp, rp, |l, r| self.eq_pat(l, r));
|
||||
let eq = lb == rb && both(lp.as_ref(), rp.as_ref(), |l, r| self.eq_pat(l, r));
|
||||
if eq {
|
||||
self.locals.insert(li, ri);
|
||||
}
|
||||
|
@ -460,13 +466,15 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
(&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
|
||||
(&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
|
||||
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
|
||||
both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
|
||||
both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b))
|
||||
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b))
|
||||
&& (li == ri)
|
||||
},
|
||||
(&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
|
||||
(&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
|
||||
over(ls, rs, |l, r| self.eq_pat(l, r))
|
||||
&& over(le, re, |l, r| self.eq_pat(l, r))
|
||||
&& both(li, ri, |l, r| self.eq_pat(l, r))
|
||||
&& both(li.as_ref(), ri.as_ref(), |l, r| self.eq_pat(l, r))
|
||||
},
|
||||
(&PatKind::Wild, &PatKind::Wild) => true,
|
||||
_ => false,
|
||||
|
@ -476,7 +484,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
|
||||
match (left, right) {
|
||||
(&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
|
||||
both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
|
||||
both(lty.as_ref(), rty.as_ref(), |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
|
||||
},
|
||||
(&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
|
||||
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
|
||||
|
@ -510,7 +518,10 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
|
||||
// The == of idents doesn't work with different contexts,
|
||||
// we have to be explicit about hygiene
|
||||
left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
|
||||
left.ident.name == right.ident.name
|
||||
&& both(left.args.as_ref(), right.args.as_ref(), |l, r| {
|
||||
self.eq_path_parameters(l, r)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
|
||||
|
@ -649,7 +660,7 @@ fn swap_binop<'a>(
|
|||
|
||||
/// Checks if the two `Option`s are both `None` or some equal values as per
|
||||
/// `eq_fn`.
|
||||
pub fn both<X>(l: &Option<X>, r: &Option<X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
|
||||
pub fn both<X>(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
|
||||
l.as_ref()
|
||||
.map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
|
||||
}
|
||||
|
|
|
@ -597,7 +597,7 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It
|
|||
},
|
||||
};
|
||||
|
||||
tcx.incoherent_impls(ty).into_iter().copied()
|
||||
tcx.incoherent_impls(ty).iter().copied()
|
||||
}
|
||||
|
||||
fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
|
||||
|
@ -731,7 +731,7 @@ pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec<Res>, mut path: &[&
|
|||
// `impl S { ... }`
|
||||
let inherent_impl_children = tcx
|
||||
.inherent_impls(def_id)
|
||||
.into_iter()
|
||||
.iter()
|
||||
.flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
|
||||
|
||||
let direct_children = item_children_by_name(tcx, def_id, segment);
|
||||
|
@ -1341,7 +1341,7 @@ pub struct ContainsName<'a, 'tcx> {
|
|||
pub result: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_name(&mut self, name: Symbol) {
|
||||
|
@ -3111,7 +3111,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<
|
|||
is_never: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> V<'_, 'tcx> {
|
||||
impl V<'_, '_> {
|
||||
fn push_break_target(&mut self, id: HirId) {
|
||||
self.break_targets.push(BreakTarget { id, unused: true });
|
||||
self.break_targets_for_result_ty += u32::from(self.in_final_expr);
|
||||
|
|
|
@ -58,7 +58,7 @@ struct V<'a> {
|
|||
results: Vec<LocalUsage>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
|
||||
impl<'tcx> Visitor<'tcx> for V<'_> {
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) {
|
||||
if loc.block == self.location.block && loc.statement_index <= self.location.statement_index {
|
||||
return;
|
||||
|
|
|
@ -65,7 +65,7 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
|
||||
impl<'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'_, '_, 'tcx> {
|
||||
fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
|
||||
let lhs = place.local;
|
||||
match rvalue {
|
||||
|
@ -177,8 +177,8 @@ pub struct PossibleBorrowerMap<'b, 'tcx> {
|
|||
pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
|
||||
pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
|
||||
impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
|
||||
pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
|
||||
let possible_origin = {
|
||||
let mut vis = PossibleOriginVisitor::new(mir);
|
||||
vis.visit_body(mir);
|
||||
|
|
|
@ -39,7 +39,7 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
|
||||
impl<'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'_, 'tcx> {
|
||||
fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
|
||||
let lhs = place.local;
|
||||
match rvalue {
|
||||
|
|
|
@ -131,7 +131,8 @@ fn check_rvalue<'tcx>(
|
|||
CastKind::PointerCoercion(
|
||||
PointerCoercion::UnsafeFnPointer
|
||||
| PointerCoercion::ClosureFnPointer(_)
|
||||
| PointerCoercion::ReifyFnPointer, _
|
||||
| PointerCoercion::ReifyFnPointer,
|
||||
_,
|
||||
),
|
||||
_,
|
||||
_,
|
||||
|
|
|
@ -1319,7 +1319,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
|
|||
/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
|
||||
pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
|
||||
if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
|
||||
cx.tcx.inherent_impls(ty_did).into_iter().find_map(|&did| {
|
||||
cx.tcx.inherent_impls(ty_did).iter().find_map(|&did| {
|
||||
cx.tcx
|
||||
.associated_items(did)
|
||||
.filter_by_name_unhygienic(method_name)
|
||||
|
|
|
@ -108,7 +108,7 @@ impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> {
|
||||
impl<'cx> Visitor<'cx> for CertaintyVisitor<'cx, '_> {
|
||||
fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) {
|
||||
self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true));
|
||||
if self.certainty != Certainty::Uncertain {
|
||||
|
|
|
@ -46,8 +46,8 @@ struct MutVarsDelegate {
|
|||
skip: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVarsDelegate {
|
||||
fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
|
||||
impl MutVarsDelegate {
|
||||
fn update(&mut self, cat: &PlaceWithHirId<'_>) {
|
||||
match cat.place.base {
|
||||
PlaceBase::Local(id) => {
|
||||
self.used_mutably.insert(id);
|
||||
|
@ -122,7 +122,7 @@ impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
|
|||
finder.usage_found
|
||||
}
|
||||
}
|
||||
impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
|
|
|
@ -552,7 +552,7 @@ pub fn for_each_local_use_after_expr<'tcx, B>(
|
|||
res: ControlFlow<B>,
|
||||
f: F,
|
||||
}
|
||||
impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> {
|
||||
impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'_, 'tcx, F, B> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
|
@ -734,7 +734,7 @@ pub fn for_each_local_assignment<'tcx, B>(
|
|||
res: ControlFlow<B>,
|
||||
f: F,
|
||||
}
|
||||
impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> {
|
||||
impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'_, 'tcx, F, B> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
|
|
|
@ -68,7 +68,7 @@ impl Crate {
|
|||
total_crates_to_lint: usize,
|
||||
config: &LintcheckConfig,
|
||||
lint_levels_args: &[String],
|
||||
server: &Option<LintcheckServer>,
|
||||
server: Option<&LintcheckServer>,
|
||||
) -> Vec<ClippyCheckOutput> {
|
||||
// advance the atomic index by one
|
||||
let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
|
||||
|
@ -359,7 +359,7 @@ fn lintcheck(config: LintcheckConfig) {
|
|||
crates.len(),
|
||||
&config,
|
||||
&lint_level_args,
|
||||
&server,
|
||||
server.as_ref(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-09-22"
|
||||
channel = "nightly-2024-10-03"
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
|
|
@ -22,7 +22,6 @@ use rustc_span::symbol::Symbol;
|
|||
|
||||
use std::env;
|
||||
use std::fs::read_to_string;
|
||||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
|
||||
|
@ -30,12 +29,8 @@ use anstream::println;
|
|||
|
||||
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
|
||||
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
|
||||
fn arg_value<'a, T: Deref<Target = str>>(
|
||||
args: &'a [T],
|
||||
find_arg: &str,
|
||||
pred: impl Fn(&str) -> bool,
|
||||
) -> Option<&'a str> {
|
||||
let mut args = args.iter().map(Deref::deref);
|
||||
fn arg_value<'a>(args: &'a [String], find_arg: &str, pred: impl Fn(&str) -> bool) -> Option<&'a str> {
|
||||
let mut args = args.iter().map(String::as_str);
|
||||
while let Some(arg) = args.next() {
|
||||
let mut arg = arg.splitn(2, '=');
|
||||
if arg.next() != Some(find_arg) {
|
||||
|
@ -50,11 +45,15 @@ fn arg_value<'a, T: Deref<Target = str>>(
|
|||
None
|
||||
}
|
||||
|
||||
fn has_arg(args: &[String], find_arg: &str) -> bool {
|
||||
args.iter().any(|arg| find_arg == arg.split('=').next().unwrap())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_value() {
|
||||
let args = &["--bar=bar", "--foobar", "123", "--foo"];
|
||||
let args = &["--bar=bar", "--foobar", "123", "--foo"].map(String::from);
|
||||
|
||||
assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
|
||||
assert_eq!(arg_value(&[], "--foobar", |_| true), None);
|
||||
assert_eq!(arg_value(args, "--bar", |_| false), None);
|
||||
assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
|
||||
assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
|
||||
|
@ -65,11 +64,21 @@ fn test_arg_value() {
|
|||
assert_eq!(arg_value(args, "--foo", |_| true), None);
|
||||
}
|
||||
|
||||
fn track_clippy_args(psess: &mut ParseSess, args_env_var: &Option<String>) {
|
||||
psess.env_depinfo.get_mut().insert((
|
||||
Symbol::intern("CLIPPY_ARGS"),
|
||||
args_env_var.as_deref().map(Symbol::intern),
|
||||
));
|
||||
#[test]
|
||||
fn test_has_arg() {
|
||||
let args = &["--foo=bar", "-vV", "--baz"].map(String::from);
|
||||
assert!(has_arg(args, "--foo"));
|
||||
assert!(has_arg(args, "--baz"));
|
||||
assert!(has_arg(args, "-vV"));
|
||||
|
||||
assert!(!has_arg(args, "--bar"));
|
||||
}
|
||||
|
||||
fn track_clippy_args(psess: &mut ParseSess, args_env_var: Option<&str>) {
|
||||
psess
|
||||
.env_depinfo
|
||||
.get_mut()
|
||||
.insert((Symbol::intern("CLIPPY_ARGS"), args_env_var.map(Symbol::intern)));
|
||||
}
|
||||
|
||||
/// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy
|
||||
|
@ -113,7 +122,7 @@ impl rustc_driver::Callbacks for RustcCallbacks {
|
|||
fn config(&mut self, config: &mut interface::Config) {
|
||||
let clippy_args_var = self.clippy_args_var.take();
|
||||
config.psess_created = Some(Box::new(move |psess| {
|
||||
track_clippy_args(psess, &clippy_args_var);
|
||||
track_clippy_args(psess, clippy_args_var.as_deref());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +139,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
|
|||
let previous = config.register_lints.take();
|
||||
let clippy_args_var = self.clippy_args_var.take();
|
||||
config.psess_created = Some(Box::new(move |psess| {
|
||||
track_clippy_args(psess, &clippy_args_var);
|
||||
track_clippy_args(psess, clippy_args_var.as_deref());
|
||||
track_files(psess);
|
||||
|
||||
// Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so
|
||||
|
@ -189,7 +198,7 @@ pub fn main() {
|
|||
let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?;
|
||||
|
||||
let has_sysroot_arg = |args: &mut [String]| -> bool {
|
||||
if arg_value(args, "--sysroot", |_| true).is_some() {
|
||||
if has_arg(args, "--sysroot") {
|
||||
return true;
|
||||
}
|
||||
// https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path
|
||||
|
@ -199,7 +208,7 @@ pub fn main() {
|
|||
if let Some(arg_file_path) = arg.strip_prefix('@') {
|
||||
if let Ok(arg_file) = read_to_string(arg_file_path) {
|
||||
let split_arg_file: Vec<String> = arg_file.lines().map(ToString::to_string).collect();
|
||||
if arg_value(&split_arg_file, "--sysroot", |_| true).is_some() {
|
||||
if has_arg(&split_arg_file, "--sysroot") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -271,16 +280,18 @@ pub fn main() {
|
|||
.chain(vec!["--cfg".into(), "clippy".into()])
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
// We enable Clippy if one of the following conditions is met
|
||||
// - IF Clippy is run on its test suite OR
|
||||
// - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
|
||||
// - IF `--no-deps` is not set (`!no_deps`) OR
|
||||
// - IF `--no-deps` is set and Clippy is run on the specified primary package
|
||||
// If no Clippy lints will be run we do not need to run Clippy
|
||||
let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some()
|
||||
&& arg_value(&orig_args, "--force-warn", |val| val.contains("clippy::")).is_none();
|
||||
let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
|
||||
|
||||
let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
|
||||
// If `--no-deps` is enabled only lint the primary pacakge
|
||||
let relevant_package = !no_deps || env::var("CARGO_PRIMARY_PACKAGE").is_ok();
|
||||
|
||||
// Do not run Clippy for Cargo's info queries so that invalid CLIPPY_ARGS are not cached
|
||||
// https://github.com/rust-lang/cargo/issues/14385
|
||||
let info_query = has_arg(&orig_args, "-vV") || has_arg(&orig_args, "--print");
|
||||
|
||||
let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
|
||||
if clippy_enabled {
|
||||
args.extend(clippy_args);
|
||||
rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::useless_vec,
|
||||
clippy::out_of_bounds_indexing
|
||||
clippy::out_of_bounds_indexing,
|
||||
clippy::needless_lifetimes
|
||||
)]
|
||||
|
||||
const ARR: [i32; 2] = [1, 2];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: indexing may panic
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:26:5
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:27:5
|
||||
|
|
||||
LL | x[index];
|
||||
| ^^^^^^^^
|
||||
|
@ -9,7 +9,7 @@ LL | x[index];
|
|||
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
|
||||
|
||||
error: indexing may panic
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:41:5
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:42:5
|
||||
|
|
||||
LL | v[0];
|
||||
| ^^^^
|
||||
|
@ -17,7 +17,7 @@ LL | v[0];
|
|||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:42:5
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:43:5
|
||||
|
|
||||
LL | v[10];
|
||||
| ^^^^^
|
||||
|
@ -25,7 +25,7 @@ LL | v[10];
|
|||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:43:5
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:44:5
|
||||
|
|
||||
LL | v[1 << 3];
|
||||
| ^^^^^^^^^
|
||||
|
@ -33,7 +33,7 @@ LL | v[1 << 3];
|
|||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:49:5
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:50:5
|
||||
|
|
||||
LL | v[N];
|
||||
| ^^^^
|
||||
|
@ -41,7 +41,7 @@ LL | v[N];
|
|||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:50:5
|
||||
--> tests/ui-toml/suppress_lint_in_const/test.rs:51:5
|
||||
|
|
||||
LL | v[M];
|
||||
| ^^^^
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![allow(unused)]
|
||||
#![warn(clippy::as_ptr_cast_mut)]
|
||||
#![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)]
|
||||
//@no-rustfix
|
||||
//@no-rustfix: incorrect suggestion
|
||||
|
||||
struct MutPtrWrapper(Vec<u8>);
|
||||
impl MutPtrWrapper {
|
||||
|
|
133
src/tools/clippy/tests/ui/borrow_box.fixed
Normal file
133
src/tools/clippy/tests/ui/borrow_box.fixed
Normal file
|
@ -0,0 +1,133 @@
|
|||
#![deny(clippy::borrowed_box)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
#![allow(
|
||||
clippy::uninlined_format_args,
|
||||
clippy::disallowed_names,
|
||||
clippy::needless_pass_by_ref_mut,
|
||||
clippy::needless_lifetimes
|
||||
)]
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
pub fn test1(foo: &mut Box<bool>) {
|
||||
// Although this function could be changed to "&mut bool",
|
||||
// avoiding the Box, mutable references to boxes are not
|
||||
// flagged by this lint.
|
||||
//
|
||||
// This omission is intentional: By passing a mutable Box,
|
||||
// the memory location of the pointed-to object could be
|
||||
// modified. By passing a mutable reference, the contents
|
||||
// could change, but not the location.
|
||||
println!("{:?}", foo)
|
||||
}
|
||||
|
||||
pub fn test2() {
|
||||
let foo: &bool;
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
}
|
||||
|
||||
struct Test3<'a> {
|
||||
foo: &'a bool,
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
}
|
||||
|
||||
trait Test4 {
|
||||
fn test4(a: &bool);
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
}
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
pub fn test5(foo: &mut Box<dyn Any>) {
|
||||
println!("{:?}", foo)
|
||||
}
|
||||
|
||||
pub fn test6() {
|
||||
let foo: &Box<dyn Any>;
|
||||
}
|
||||
|
||||
struct Test7<'a> {
|
||||
foo: &'a Box<dyn Any>,
|
||||
}
|
||||
|
||||
trait Test8 {
|
||||
fn test8(a: &Box<dyn Any>);
|
||||
}
|
||||
|
||||
impl<'a> Test8 for Test7<'a> {
|
||||
fn test8(a: &Box<dyn Any>) {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test9(foo: &mut Box<dyn Any + Send + Sync>) {
|
||||
let _ = foo;
|
||||
}
|
||||
|
||||
pub fn test10() {
|
||||
let foo: &Box<dyn Any + Send + 'static>;
|
||||
}
|
||||
|
||||
struct Test11<'a> {
|
||||
foo: &'a Box<dyn Any + Send>,
|
||||
}
|
||||
|
||||
trait Test12 {
|
||||
fn test4(a: &Box<dyn Any + 'static>);
|
||||
}
|
||||
|
||||
impl<'a> Test12 for Test11<'a> {
|
||||
fn test4(a: &Box<dyn Any + 'static>) {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test13(boxed_slice: &mut Box<[i32]>) {
|
||||
// Unconditionally replaces the box pointer.
|
||||
//
|
||||
// This cannot be accomplished if "&mut [i32]" is passed,
|
||||
// and provides a test case where passing a reference to
|
||||
// a Box is valid.
|
||||
let mut data = vec![12];
|
||||
*boxed_slice = data.into_boxed_slice();
|
||||
}
|
||||
|
||||
// The suggestion should include proper parentheses to avoid a syntax error.
|
||||
pub fn test14(_display: &dyn Display) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
pub fn test15(_display: &(dyn Display + Send)) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
pub fn test16<'a>(_display: &'a (dyn Display + 'a)) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
|
||||
pub fn test17(_display: &impl Display) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
pub fn test18(_display: &(impl Display + Send)) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
pub fn test19<'a>(_display: &'a (impl Display + 'a)) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
|
||||
// This exists only to check what happens when parentheses are already present.
|
||||
// Even though the current implementation doesn't put extra parentheses,
|
||||
// it's fine that unnecessary parentheses appear in the future for some reason.
|
||||
pub fn test20(_display: &(dyn Display + Send)) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
|
||||
#[allow(clippy::borrowed_box)]
|
||||
trait Trait {
|
||||
fn f(b: &Box<bool>);
|
||||
}
|
||||
|
||||
// Trait impls are not linted
|
||||
impl Trait for () {
|
||||
fn f(_: &Box<bool>) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1(&mut Box::new(false));
|
||||
test2();
|
||||
test5(&mut (Box::new(false) as Box<dyn Any>));
|
||||
test6();
|
||||
test9(&mut (Box::new(false) as Box<dyn Any + Send + Sync>));
|
||||
test10();
|
||||
}
|
|
@ -3,9 +3,9 @@
|
|||
#![allow(
|
||||
clippy::uninlined_format_args,
|
||||
clippy::disallowed_names,
|
||||
clippy::needless_pass_by_ref_mut
|
||||
clippy::needless_pass_by_ref_mut,
|
||||
clippy::needless_lifetimes
|
||||
)]
|
||||
//@no-rustfix
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
|
@ -36,12 +36,6 @@ trait Test4 {
|
|||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
}
|
||||
|
||||
impl<'a> Test4 for Test3<'a> {
|
||||
fn test4(a: &Box<bool>) {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
pub fn test5(foo: &mut Box<dyn Any>) {
|
||||
|
@ -119,6 +113,16 @@ pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
|
|||
pub fn test20(_display: &Box<(dyn Display + Send)>) {}
|
||||
//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
|
||||
#[allow(clippy::borrowed_box)]
|
||||
trait Trait {
|
||||
fn f(b: &Box<bool>);
|
||||
}
|
||||
|
||||
// Trait impls are not linted
|
||||
impl Trait for () {
|
||||
fn f(_: &Box<bool>) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1(&mut Box::new(false));
|
||||
test2();
|
||||
|
|
|
@ -23,43 +23,43 @@ LL | fn test4(a: &Box<bool>);
|
|||
| ^^^^^^^^^^ help: try: `&bool`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:102:25
|
||||
--> tests/ui/borrow_box.rs:96:25
|
||||
|
|
||||
LL | pub fn test14(_display: &Box<dyn Display>) {}
|
||||
| ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:104:25
|
||||
--> tests/ui/borrow_box.rs:98:25
|
||||
|
|
||||
LL | pub fn test15(_display: &Box<dyn Display + Send>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:106:29
|
||||
--> tests/ui/borrow_box.rs:100:29
|
||||
|
|
||||
LL | pub fn test16<'a>(_display: &'a Box<dyn Display + 'a>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:109:25
|
||||
--> tests/ui/borrow_box.rs:103:25
|
||||
|
|
||||
LL | pub fn test17(_display: &Box<impl Display>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:111:25
|
||||
--> tests/ui/borrow_box.rs:105:25
|
||||
|
|
||||
LL | pub fn test18(_display: &Box<impl Display + Send>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:113:29
|
||||
--> tests/ui/borrow_box.rs:107:29
|
||||
|
|
||||
LL | pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)`
|
||||
|
||||
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
|
||||
--> tests/ui/borrow_box.rs:119:25
|
||||
--> tests/ui/borrow_box.rs:113:25
|
||||
|
|
||||
LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
clippy::needless_pass_by_value,
|
||||
clippy::unused_unit,
|
||||
clippy::redundant_clone,
|
||||
clippy::match_single_binding
|
||||
clippy::match_single_binding,
|
||||
clippy::needless_lifetimes
|
||||
)]
|
||||
#![warn(clippy::boxed_local)]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: local variable doesn't need to be boxed here
|
||||
--> tests/ui/boxed_local.rs:39:13
|
||||
--> tests/ui/boxed_local.rs:40:13
|
||||
|
|
||||
LL | fn warn_arg(x: Box<A>) {
|
||||
| ^
|
||||
|
@ -8,19 +8,19 @@ LL | fn warn_arg(x: Box<A>) {
|
|||
= help: to override `-D warnings` add `#[allow(clippy::boxed_local)]`
|
||||
|
||||
error: local variable doesn't need to be boxed here
|
||||
--> tests/ui/boxed_local.rs:122:12
|
||||
--> tests/ui/boxed_local.rs:123:12
|
||||
|
|
||||
LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: local variable doesn't need to be boxed here
|
||||
--> tests/ui/boxed_local.rs:187:44
|
||||
--> tests/ui/boxed_local.rs:188:44
|
||||
|
|
||||
LL | fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
|
||||
| ^
|
||||
|
||||
error: local variable doesn't need to be boxed here
|
||||
--> tests/ui/boxed_local.rs:195:16
|
||||
--> tests/ui/boxed_local.rs:196:16
|
||||
|
|
||||
LL | fn foo(x: Box<u32>) {}
|
||||
| ^
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue