Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
3fac496339
149 changed files with 2070 additions and 512 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// REUSE-IgnoreStart
|
||||
|
||||
Copyright 2014-2025 The Rust Project Developers
|
||||
Copyright (c) The Rust Project Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ walkdir = "2.3"
|
|||
filetime = "0.2.9"
|
||||
itertools = "0.12"
|
||||
pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] }
|
||||
askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] }
|
||||
askama = { version = "0.15", default-features = false, features = ["alloc", "config", "derive"] }
|
||||
|
||||
[dev-dependencies.toml]
|
||||
version = "0.9.7"
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014-2025 The Rust Project Developers
|
||||
Copyright (c) The Rust Project Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2014-2025 The Rust Project Developers
|
||||
Copyright (c) The Rust Project Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
|
|||
|
||||
<!-- REUSE-IgnoreStart -->
|
||||
|
||||
Copyright 2014-2025 The Rust Project Developers
|
||||
Copyright (c) The Rust Project Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use super::ALLOW_ATTRIBUTES;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_ast::{AttrStyle, Attribute};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, LintContext};
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
|
||||
// Separate each crate's features.
|
||||
pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) {
|
||||
|
|
@ -15,12 +15,7 @@ pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) {
|
|||
{
|
||||
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
|
||||
span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| {
|
||||
diag.span_suggestion(
|
||||
path_span,
|
||||
"replace it with",
|
||||
"expect",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.span_suggestion(path_span, "replace it with", "expect", Applicability::MachineApplicable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ mod utils;
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::msrvs::{self, Msrv, MsrvStack};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind, AttrItemKind};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrItemKind, AttrKind, Attribute, MetaItemInner, MetaItemKind};
|
||||
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
@ -604,7 +604,9 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
|
|||
|
||||
if attr.has_name(sym::ignore)
|
||||
&& match &attr.kind {
|
||||
AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })),
|
||||
AttrKind::Normal(normal_attr) => {
|
||||
!matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. }))
|
||||
},
|
||||
AttrKind::DocComment(..) => true,
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT};
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use rustc_ast::token::{Token, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenTree;
|
||||
use rustc_ast::{AttrArgs, AttrKind, AttrItemKind};
|
||||
use rustc_ast::{AttrArgs, AttrItemKind, AttrKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::EarlyContext;
|
||||
use rustc_span::sym;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
|
||||
use clippy_utils::source::walk_span_to_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
|
|
@ -130,22 +131,24 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
|
|||
|
||||
let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
|
||||
|
||||
if let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) {
|
||||
let sugg = if bool_value ^ eq_macro {
|
||||
!sugg.maybe_paren()
|
||||
} else if ty::Bool == *non_lit_ty.kind() {
|
||||
sugg
|
||||
} else {
|
||||
!!sugg.maybe_paren()
|
||||
};
|
||||
suggestions.push((non_lit_expr.span, sugg.to_string()));
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = Sugg::hir_with_context(cx, non_lit_expr, macro_call.span.ctxt(), "..", &mut applicability);
|
||||
let sugg = if bool_value ^ eq_macro {
|
||||
!sugg.maybe_paren()
|
||||
} else if ty::Bool == *non_lit_ty.kind() {
|
||||
sugg
|
||||
} else {
|
||||
!!sugg.maybe_paren()
|
||||
};
|
||||
let non_lit_expr_span =
|
||||
walk_span_to_context(non_lit_expr.span, macro_call.span.ctxt()).unwrap_or(non_lit_expr.span);
|
||||
suggestions.push((non_lit_expr_span, sugg.to_string()));
|
||||
|
||||
diag.multipart_suggestion(
|
||||
format!("replace it with `{non_eq_mac}!(..)`"),
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
diag.multipart_suggestion(
|
||||
format!("replace it with `{non_eq_mac}!(..)`"),
|
||||
suggestions,
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, Level};
|
|||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Span, Symbol, SyntaxContext};
|
||||
use std::fmt::Write as _;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -356,7 +357,7 @@ impl SuggestContext<'_, '_, '_> {
|
|||
if app != Applicability::MachineApplicable {
|
||||
return None;
|
||||
}
|
||||
self.output.push_str(&(!snip).to_string());
|
||||
let _cannot_fail = write!(&mut self.output, "{}", &(!snip));
|
||||
}
|
||||
},
|
||||
True | False | Not(_) => {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ declare_clippy_lint! {
|
|||
/// Because this can be caused purely by the dependencies
|
||||
/// themselves, it's not always possible to fix this issue.
|
||||
/// In those cases, you can allow that specific crate using
|
||||
/// the `allowed_duplicate_crates` configuration option.
|
||||
/// the `allowed-duplicate-crates` configuration option.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```toml
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_ast::attr::data_structures::CfgEntry;
|
||||
use rustc_ast::{AttrItemKind, EarlyParsedAttribute};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_ast::AttrItemKind;
|
||||
use rustc_ast::EarlyParsedAttribute;
|
||||
use rustc_span::sym;
|
||||
use rustc_ast::attr::data_structures::CfgEntry;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -40,7 +39,7 @@ impl EarlyLintPass for CfgNotTest {
|
|||
unreachable!()
|
||||
};
|
||||
|
||||
if contains_not_test(&cfg, false) {
|
||||
if contains_not_test(cfg, false) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CFG_NOT_TEST,
|
||||
|
|
@ -58,11 +57,9 @@ impl EarlyLintPass for CfgNotTest {
|
|||
|
||||
fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool {
|
||||
match cfg {
|
||||
CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| {
|
||||
contains_not_test(item, not)
|
||||
}),
|
||||
CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| contains_not_test(item, not)),
|
||||
CfgEntry::Not(sub, _) => contains_not_test(sub, !not),
|
||||
CfgEntry::NameValue { name: sym::test, .. } => not,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
|
||||
|
|
@ -80,7 +80,8 @@ impl LateLintPass<'_> for CheckedConversions {
|
|||
&& self.msrv.meets(cx, msrvs::TRY_FROM)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
|
||||
let (snippet, _) =
|
||||
snippet_with_context(cx, cv.expr_to_cast.span, item.span.ctxt(), "_", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
CHECKED_CONVERSIONS,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::fulfill_or_allowed;
|
||||
use rustc_hir::{self as hir, HirId};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::DERIVE_ORD_XOR_PARTIAL_ORD;
|
||||
|
||||
/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
span: Span,
|
||||
item: &hir::Item<'_>,
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
adt_hir_id: HirId,
|
||||
|
|
@ -19,6 +20,8 @@ pub(super) fn check<'tcx>(
|
|||
&& let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
|
||||
&& let Some(def_id) = &trait_ref.trait_def_id()
|
||||
&& *def_id == ord_trait_def_id
|
||||
&& let item_hir_id = cx.tcx.local_def_id_to_hir_id(item.owner_id)
|
||||
&& !fulfill_or_allowed(cx, DERIVE_ORD_XOR_PARTIAL_ORD, [adt_hir_id])
|
||||
{
|
||||
// Look for the PartialOrd implementations for `ty`
|
||||
cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
|
||||
|
|
@ -39,7 +42,7 @@ pub(super) fn check<'tcx>(
|
|||
"you are deriving `Ord` but have implemented `PartialOrd` explicitly"
|
||||
};
|
||||
|
||||
span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, adt_hir_id, span, mess, |diag| {
|
||||
span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, item_hir_id, item.span, mess, |diag| {
|
||||
if let Some(local_def_id) = impl_id.as_local() {
|
||||
let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
|
||||
diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here");
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
|
|||
let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
|
||||
|
||||
derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived);
|
||||
derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived);
|
||||
derive_ord_xor_partial_ord::check(cx, item, trait_ref, ty, adt_hir_id, is_automatically_derived);
|
||||
|
||||
if is_automatically_derived {
|
||||
unsafe_derive_deserialize::check(cx, item, trait_ref, ty, adt_hir_id);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute, AttrItemKind};
|
||||
use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, AttrStyle, Attribute};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::EarlyContext;
|
||||
|
||||
|
|
|
|||
|
|
@ -869,10 +869,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
|
|||
}),
|
||||
true,
|
||||
);
|
||||
let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| {
|
||||
add_doc_fragment(&mut acc, fragment);
|
||||
acc
|
||||
});
|
||||
|
||||
let mut doc = String::with_capacity(fragments.iter().map(|frag| frag.doc.as_str().len() + 1).sum());
|
||||
|
||||
for fragment in &fragments {
|
||||
add_doc_fragment(&mut doc, fragment);
|
||||
}
|
||||
doc.pop();
|
||||
|
||||
if doc.trim().is_empty() {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ fn check_source(cx: &EarlyContext<'_>, inner: &Expr) -> bool {
|
|||
&& inner.starts_with('(')
|
||||
&& inner.ends_with(')')
|
||||
&& outer_after_inner.trim_start().starts_with(')')
|
||||
// Don't lint macro repetition patterns like `($($result),*)` where parens are necessary
|
||||
&& !inner.trim_start_matches('(').trim_start().starts_with("$(")
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::{Sugg, make_binop};
|
||||
use clippy_utils::{
|
||||
SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym,
|
||||
SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, is_integer_literal_untyped,
|
||||
peel_blocks, peel_blocks_with_stmt, sym,
|
||||
};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
|
|
@ -238,10 +242,21 @@ fn check_subtraction(
|
|||
if eq_expr_value(cx, left, big_expr) && eq_expr_value(cx, right, little_expr) {
|
||||
// This part of the condition is voluntarily split from the one before to ensure that
|
||||
// if `snippet_opt` fails, it won't try the next conditions.
|
||||
if (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST))
|
||||
&& let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_paren)
|
||||
&& let Some(little_expr_sugg) = Sugg::hir_opt(cx, little_expr)
|
||||
{
|
||||
if !is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let big_expr_sugg = (if is_integer_literal_untyped(big_expr) {
|
||||
let get_snippet = |span: Span| {
|
||||
let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
|
||||
let big_expr_ty = cx.typeck_results().expr_ty(big_expr);
|
||||
Cow::Owned(format!("{snippet}_{big_expr_ty}"))
|
||||
};
|
||||
Sugg::hir_from_snippet(cx, big_expr, get_snippet)
|
||||
} else {
|
||||
Sugg::hir_with_applicability(cx, big_expr, "..", &mut applicability)
|
||||
})
|
||||
.maybe_paren();
|
||||
let little_expr_sugg = Sugg::hir_with_applicability(cx, little_expr, "..", &mut applicability);
|
||||
|
||||
let sugg = format!(
|
||||
"{}{big_expr_sugg}.saturating_sub({little_expr_sugg}){}",
|
||||
if is_composited { "{ " } else { "" },
|
||||
|
|
@ -254,7 +269,7 @@ fn check_subtraction(
|
|||
"manual arithmetic check found",
|
||||
"replace it with",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
} else if eq_expr_value(cx, left, little_expr)
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::{is_in_const_context, is_in_test, sym};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince, find_attr};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::def_id::{CrateNum, DefId};
|
||||
use rustc_span::{ExpnKind, Span};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::find_attr;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -270,6 +269,9 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv {
|
|||
/// attribute.
|
||||
fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool {
|
||||
cx.tcx.hir_parent_id_iter(hir_id).any(|id| {
|
||||
find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace)
|
||||
find_attr!(
|
||||
cx.tcx.hir_attrs(id),
|
||||
AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,21 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
|
|||
InherentImplLintScope::Crate => Criterion::Crate,
|
||||
};
|
||||
let is_test = is_cfg_test(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id);
|
||||
match type_map.entry((impl_ty, criterion, is_test)) {
|
||||
let predicates = {
|
||||
// Gets the predicates (bounds) for the given impl block,
|
||||
// sorted for consistent comparison to allow distinguishing between impl blocks
|
||||
// with different generic bounds.
|
||||
let mut predicates = cx
|
||||
.tcx
|
||||
.predicates_of(impl_id)
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|(clause, _)| *clause)
|
||||
.collect::<Vec<_>>();
|
||||
predicates.sort_by_key(|c| format!("{c:?}"));
|
||||
predicates
|
||||
};
|
||||
match type_map.entry((impl_ty, predicates, criterion, is_test)) {
|
||||
Entry::Vacant(e) => {
|
||||
// Store the id for the first impl block of this type. The span is retrieved lazily.
|
||||
e.insert(IdOrSpan::Id(impl_id));
|
||||
|
|
@ -152,15 +166,12 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
|
|||
fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
|
||||
let id = cx.tcx.local_def_id_to_hir_id(id);
|
||||
if let Node::Item(&Item {
|
||||
kind: ItemKind::Impl(impl_item),
|
||||
kind: ItemKind::Impl(_),
|
||||
span,
|
||||
..
|
||||
}) = cx.tcx.hir_node(id)
|
||||
{
|
||||
(!span.from_expansion()
|
||||
&& impl_item.generics.params.is_empty()
|
||||
&& !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id]))
|
||||
.then_some(span)
|
||||
(!span.from_expansion() && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])).then_some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use rustc_ast::AttrItemKind;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::root_macro_call_first_node;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::{AttrArgs, AttrKind, Attribute, LitKind};
|
||||
use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, Attribute, LitKind};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,15 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
|
|||
})
|
||||
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
|
||||
{
|
||||
// libtest might generate a large array containing the test cases, and no span will be associated
|
||||
// to it. In this case it is better not to complain.
|
||||
//
|
||||
// Note that this condition is not checked explicitly by a unit test. Do not remove it without
|
||||
// ensuring that <https://github.com/rust-lang/rust-clippy/issues/13774> stays fixed.
|
||||
if expr.span.is_dummy() {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
LARGE_STACK_ARRAYS,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
use super::FOR_KV_MAP;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::source::{snippet_with_applicability, walk_span_to_context};
|
||||
use clippy_utils::{pat_is_wild, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
/// Checks for the `FOR_KV_MAP` lint.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat: &'tcx Pat<'_>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
body: &'tcx Expr<'_>,
|
||||
span: Span,
|
||||
) {
|
||||
let pat_span = pat.span;
|
||||
|
||||
if let PatKind::Tuple(pat, _) = pat.kind
|
||||
|
|
@ -34,21 +40,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
|
|||
_ => arg,
|
||||
};
|
||||
|
||||
if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) {
|
||||
if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap))
|
||||
&& let Some(arg_span) = walk_span_to_context(arg_span, span.ctxt())
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
FOR_KV_MAP,
|
||||
arg_span,
|
||||
format!("you seem to want to iterate on a map's {kind}s"),
|
||||
|diag| {
|
||||
let map = sugg::Sugg::hir(cx, arg, "map");
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let map = sugg::Sugg::hir_with_context(cx, arg, span.ctxt(), "map", &mut applicability);
|
||||
let pat = snippet_with_applicability(cx, new_pat_span, kind, &mut applicability);
|
||||
diag.multipart_suggestion(
|
||||
"use the corresponding method",
|
||||
vec![
|
||||
(pat_span, snippet(cx, new_pat_span, kind).into_owned()),
|
||||
(pat_span, pat.to_string()),
|
||||
(arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -943,7 +943,7 @@ impl Loops {
|
|||
explicit_counter_loop::check(cx, pat, arg, body, expr, label);
|
||||
}
|
||||
self.check_for_loop_arg(cx, pat, arg);
|
||||
for_kv_map::check(cx, pat, arg, body);
|
||||
for_kv_map::check(cx, pat, arg, body, span);
|
||||
mut_range_bound::check(cx, arg, body);
|
||||
single_element_loop::check(cx, pat, arg, body, expr);
|
||||
same_item_push::check(cx, pat, arg, body, expr, self.msrv);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sym;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -111,14 +111,12 @@ impl LateLintPass<'_> for ManualIgnoreCaseCmp {
|
|||
"manual case-insensitive ASCII comparison",
|
||||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let (left_snip, _) = snippet_with_context(cx, left_span, expr.span.ctxt(), "..", &mut app);
|
||||
let (right_snip, _) = snippet_with_context(cx, right_span, expr.span.ctxt(), "..", &mut app);
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"consider using `.eq_ignore_ascii_case()` instead",
|
||||
format!(
|
||||
"{neg}{}.eq_ignore_ascii_case({deref}{})",
|
||||
snippet_with_applicability(cx, left_span, "_", &mut app),
|
||||
snippet_with_applicability(cx, right_span, "_", &mut app)
|
||||
),
|
||||
format!("{neg}{left_snip}.eq_ignore_ascii_case({deref}{right_snip})"),
|
||||
app,
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{is_from_proc_macro, sym};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
|
|
@ -102,7 +102,7 @@ impl LateLintPass<'_> for ManualIlog2 {
|
|||
|
||||
fn emit(cx: &LateContext<'_>, recv: &Expr<'_>, full_expr: &Expr<'_>) {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let recv = snippet_with_applicability(cx, recv.span, "_", &mut app);
|
||||
let (recv, _) = snippet_with_context(cx, recv.span, full_expr.span.ctxt(), "_", &mut app);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_ILOG2,
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
|
|||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
|
||||
let scrut = Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_paren();
|
||||
|
||||
let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee);
|
||||
let (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
|
|||
let cast = if input_ty == output_ty { "" } else { ".map(|x| x as _)" };
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let ctxt = expr.span.ctxt();
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MATCH_AS_REF,
|
||||
|
|
@ -59,7 +60,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
|
|||
"use `Option::as_ref()`",
|
||||
format!(
|
||||
"{}.as_ref(){cast}",
|
||||
Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(),
|
||||
Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
|
@ -69,7 +70,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
|
|||
format!("use `Option::{method}()` directly"),
|
||||
format!(
|
||||
"{}.{method}(){cast}",
|
||||
Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(),
|
||||
Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
|||
&& arms
|
||||
.iter()
|
||||
.all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..))))
|
||||
&& arms.len() == 2
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
@ -23,59 +24,58 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
|||
expr.span,
|
||||
"`match` on a boolean expression",
|
||||
move |diag| {
|
||||
if arms.len() == 2 {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
|
||||
let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app);
|
||||
if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
|
||||
match &lit.node {
|
||||
LitKind::Bool(true) => Some(test),
|
||||
LitKind::Bool(false) => Some(!test),
|
||||
_ => None,
|
||||
}
|
||||
.map(|test| {
|
||||
if let Some(guard) = &arms[0]
|
||||
.guard
|
||||
.map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app))
|
||||
{
|
||||
test.and(guard)
|
||||
} else {
|
||||
test
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let ctxt = expr.span.ctxt();
|
||||
let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
|
||||
let test = Sugg::hir_with_context(cx, scrutinee, ctxt, "_", &mut app);
|
||||
if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
|
||||
match &lit.node {
|
||||
LitKind::Bool(true) => Some(test),
|
||||
LitKind::Bool(false) => Some(!test),
|
||||
_ => None,
|
||||
}
|
||||
.map(|test| {
|
||||
if let Some(guard) = &arms[0]
|
||||
.guard
|
||||
.map(|g| Sugg::hir_with_context(cx, g, ctxt, "_", &mut app))
|
||||
{
|
||||
test.and(guard)
|
||||
} else {
|
||||
test
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(test_sugg) = test_sugg {
|
||||
let ctxt = expr.span.ctxt();
|
||||
let (true_expr, false_expr) = (arms[0].body, arms[1].body);
|
||||
let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
|
||||
(false, false) => Some(format!(
|
||||
"if {} {} else {}",
|
||||
test_sugg,
|
||||
expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app),
|
||||
expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
|
||||
)),
|
||||
(false, true) => Some(format!(
|
||||
"if {} {}",
|
||||
test_sugg,
|
||||
expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app)
|
||||
)),
|
||||
(true, false) => Some(format!(
|
||||
"if {} {}",
|
||||
!test_sugg,
|
||||
expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
|
||||
)),
|
||||
(true, true) => None,
|
||||
};
|
||||
|
||||
if let Some(test_sugg) = test_sugg {
|
||||
let ctxt = expr.span.ctxt();
|
||||
let (true_expr, false_expr) = (arms[0].body, arms[1].body);
|
||||
let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
|
||||
(false, false) => Some(format!(
|
||||
"if {} {} else {}",
|
||||
test_sugg,
|
||||
expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app),
|
||||
expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
|
||||
)),
|
||||
(false, true) => Some(format!(
|
||||
"if {} {}",
|
||||
test_sugg,
|
||||
expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app)
|
||||
)),
|
||||
(true, false) => Some(format!(
|
||||
"if {} {}",
|
||||
!test_sugg,
|
||||
expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
|
||||
)),
|
||||
(true, true) => None,
|
||||
};
|
||||
|
||||
if let Some(sugg) = sugg {
|
||||
diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app);
|
||||
}
|
||||
if let Some(sugg) = sugg {
|
||||
diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use super::REDUNDANT_PATTERN_MATCHING;
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::source::walk_span_to_context;
|
||||
use clippy_utils::sugg::{Sugg, make_unop};
|
||||
use clippy_utils::ty::needs_ordered_drop;
|
||||
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
|
||||
|
|
@ -25,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
..
|
||||
}) = higher::WhileLet::hir(expr)
|
||||
{
|
||||
find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
|
||||
find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false, let_span);
|
||||
find_if_let_true(cx, let_pat, let_expr, let_span);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +38,7 @@ pub(super) fn check_if_let<'tcx>(
|
|||
let_span: Span,
|
||||
) {
|
||||
find_if_let_true(cx, pat, scrutinee, let_span);
|
||||
find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
|
||||
find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else, let_span);
|
||||
}
|
||||
|
||||
/// Looks for:
|
||||
|
|
@ -182,6 +181,7 @@ fn find_method_sugg_for_if_let<'tcx>(
|
|||
let_expr: &'tcx Expr<'_>,
|
||||
keyword: &'static str,
|
||||
has_else: bool,
|
||||
let_span: Span,
|
||||
) {
|
||||
// also look inside refs
|
||||
// if we have &None for example, peel it so we can detect "if let None = x"
|
||||
|
|
@ -239,15 +239,9 @@ fn find_method_sugg_for_if_let<'tcx>(
|
|||
let expr_span = expr.span;
|
||||
let ctxt = expr.span.ctxt();
|
||||
|
||||
// if/while let ... = ... { ... }
|
||||
// ^^^
|
||||
let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// if/while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^
|
||||
let span = expr_span.until(res_span.shrink_to_hi());
|
||||
let span = expr_span.until(let_span.shrink_to_hi());
|
||||
|
||||
let mut app = if needs_drop {
|
||||
Applicability::MaybeIncorrect
|
||||
|
|
@ -273,13 +267,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
|
|||
if let Ok(arms) = arms.try_into() // TODO: use `slice::as_array` once stabilized
|
||||
&& let Some((good_method, maybe_guard)) = found_good_method(cx, arms)
|
||||
{
|
||||
let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
|
||||
let expr_span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span);
|
||||
|
||||
let result_expr = match &op.kind {
|
||||
ExprKind::AddrOf(_, _, borrowed) => borrowed,
|
||||
_ => op,
|
||||
};
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren();
|
||||
let receiver_sugg = Sugg::hir_with_context(cx, result_expr, expr_span.ctxt(), "_", &mut app).maybe_paren();
|
||||
let mut sugg = format!("{receiver_sugg}.{good_method}");
|
||||
|
||||
if let Some(guard) = maybe_guard {
|
||||
|
|
@ -302,14 +297,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
|
|||
return;
|
||||
}
|
||||
|
||||
let guard = Sugg::hir(cx, guard, "..");
|
||||
let guard = Sugg::hir_with_context(cx, guard, expr_span.ctxt(), "..", &mut app);
|
||||
let _ = write!(sugg, " && {}", guard.maybe_paren());
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
span,
|
||||
expr_span,
|
||||
format!("redundant pattern matching, consider using `{good_method}`"),
|
||||
"try",
|
||||
sugg,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ use clippy_utils::diagnostics::span_lint;
|
|||
use clippy_utils::macros::{is_assert_macro, root_macro_call};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context};
|
||||
use rustc_hir::{Expr, HirId};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_hir::{Expr, HirId, find_attr};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
|
||||
use super::CONST_IS_EMPTY;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use super::ITER_KV_MAP;
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::{pat_is_wild, sym};
|
||||
use rustc_hir::{Body, Expr, ExprKind, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -58,6 +58,8 @@ pub(super) fn check<'tcx>(
|
|||
applicability,
|
||||
);
|
||||
} else {
|
||||
let (body_snippet, _) =
|
||||
snippet_with_context(cx, body_expr.span, expr.span.ctxt(), "..", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_KV_MAP,
|
||||
|
|
@ -65,9 +67,8 @@ pub(super) fn check<'tcx>(
|
|||
format!("iterating on a map's {replacement_kind}s"),
|
||||
"try",
|
||||
format!(
|
||||
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})",
|
||||
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})",
|
||||
annotation.prefix_str(),
|
||||
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs};
|
||||
use rustc_ast::ast;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -59,6 +59,34 @@ struct Replacement {
|
|||
method_name: &'static str,
|
||||
has_args: bool,
|
||||
has_generic_return: bool,
|
||||
is_short_circuiting: bool,
|
||||
}
|
||||
|
||||
impl Replacement {
|
||||
fn default_applicability(&self) -> Applicability {
|
||||
if self.is_short_circuiting {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_add_note(&self, diag: &mut Diag<'_, ()>) {
|
||||
if self.is_short_circuiting {
|
||||
diag.note(format!(
|
||||
"the `{}` method is short circuiting and may change the program semantics if the iterator has side effects",
|
||||
self.method_name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_turbofish(&self, ty: Ty<'_>) -> String {
|
||||
if self.has_generic_return {
|
||||
format!("::<{ty}>")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fold_with_op(
|
||||
|
|
@ -86,32 +114,30 @@ fn check_fold_with_op(
|
|||
&& left_expr.res_local_id() == Some(first_arg_id)
|
||||
&& (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id))
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let turbofish = if replacement.has_generic_return {
|
||||
format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs())
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let sugg = if replacement.has_args {
|
||||
format!(
|
||||
"{method}{turbofish}(|{second_arg_ident}| {r})",
|
||||
method = replacement.method_name,
|
||||
r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
|
||||
)
|
||||
} else {
|
||||
format!("{method}{turbofish}()", method = replacement.method_name)
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
let span = fold_span.with_hi(expr.span.hi());
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNNECESSARY_FOLD,
|
||||
fold_span.with_hi(expr.span.hi()),
|
||||
span,
|
||||
"this `.fold` can be written more succinctly using another method",
|
||||
"try",
|
||||
sugg,
|
||||
applicability,
|
||||
|diag| {
|
||||
let mut applicability = replacement.default_applicability();
|
||||
let turbofish =
|
||||
replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs());
|
||||
let (r_snippet, _) =
|
||||
snippet_with_context(cx, right_expr.span, expr.span.ctxt(), "EXPR", &mut applicability);
|
||||
let sugg = if replacement.has_args {
|
||||
format!(
|
||||
"{method}{turbofish}(|{second_arg_ident}| {r_snippet})",
|
||||
method = replacement.method_name,
|
||||
)
|
||||
} else {
|
||||
format!("{method}{turbofish}()", method = replacement.method_name)
|
||||
};
|
||||
|
||||
diag.span_suggestion(span, "try", sugg, applicability);
|
||||
replacement.maybe_add_note(diag);
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -131,22 +157,25 @@ fn check_fold_with_method(
|
|||
// Check if the function belongs to the operator
|
||||
&& cx.tcx.is_diagnostic_item(method, fn_did)
|
||||
{
|
||||
let applicability = Applicability::MachineApplicable;
|
||||
|
||||
let turbofish = if replacement.has_generic_return {
|
||||
format!("::<{}>", cx.typeck_results().expr_ty(expr))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
let span = fold_span.with_hi(expr.span.hi());
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNNECESSARY_FOLD,
|
||||
fold_span.with_hi(expr.span.hi()),
|
||||
span,
|
||||
"this `.fold` can be written more succinctly using another method",
|
||||
"try",
|
||||
format!("{method}{turbofish}()", method = replacement.method_name),
|
||||
applicability,
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
format!(
|
||||
"{method}{turbofish}()",
|
||||
method = replacement.method_name,
|
||||
turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty(expr))
|
||||
),
|
||||
replacement.default_applicability(),
|
||||
);
|
||||
replacement.maybe_add_note(diag);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -171,6 +200,7 @@ pub(super) fn check<'tcx>(
|
|||
method_name: "any",
|
||||
has_args: true,
|
||||
has_generic_return: false,
|
||||
is_short_circuiting: true,
|
||||
};
|
||||
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, replacement);
|
||||
},
|
||||
|
|
@ -179,6 +209,7 @@ pub(super) fn check<'tcx>(
|
|||
method_name: "all",
|
||||
has_args: true,
|
||||
has_generic_return: false,
|
||||
is_short_circuiting: true,
|
||||
};
|
||||
check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, replacement);
|
||||
},
|
||||
|
|
@ -187,6 +218,7 @@ pub(super) fn check<'tcx>(
|
|||
method_name: "sum",
|
||||
has_args: false,
|
||||
has_generic_return: needs_turbofish(cx, expr),
|
||||
is_short_circuiting: false,
|
||||
};
|
||||
if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, replacement) {
|
||||
check_fold_with_method(cx, expr, acc, fold_span, sym::add, replacement);
|
||||
|
|
@ -197,6 +229,7 @@ pub(super) fn check<'tcx>(
|
|||
method_name: "product",
|
||||
has_args: false,
|
||||
has_generic_return: needs_turbofish(cx, expr),
|
||||
is_short_circuiting: false,
|
||||
};
|
||||
if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, replacement) {
|
||||
check_fold_with_method(cx, expr, acc, fold_span, sym::mul, replacement);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use clippy_utils::ty::implements_trait;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, GenericArgKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::Ident;
|
||||
use std::iter;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ impl LateLintPass<'_> for ImportRename {
|
|||
&& let Some(import) = match snip.split_once(" as ") {
|
||||
None => Some(snip.as_str()),
|
||||
Some((import, rename)) => {
|
||||
if rename.trim() == name.as_str() {
|
||||
let trimmed_rename = rename.trim();
|
||||
if trimmed_rename == "_" || trimmed_rename == name.as_str() {
|
||||
None
|
||||
} else {
|
||||
Some(import.trim())
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
#[clippy::version = "1.78.0"]
|
||||
pub MULTIPLE_BOUND_LOCATIONS,
|
||||
suspicious,
|
||||
style,
|
||||
"defining generic bounds in multiple locations"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,10 +99,6 @@ impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> {
|
|||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id)
|
||||
&& adj
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T
|
|||
&& new.ident.name == sym::new
|
||||
{
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability);
|
||||
let arg = Sugg::hir_with_context(cx, arg, expr.span.ctxt(), "_", &mut applicability);
|
||||
let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))];
|
||||
match ty_ascription {
|
||||
TypeAscriptionKind::Required(ty_ascription) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{
|
||||
SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_parent_stmt, is_receiver_of_method_call,
|
||||
|
|
@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
|||
&& SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
|
||||
let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability);
|
||||
let cond = Sugg::hir_with_context(cx, cond, e.span.ctxt(), "..", &mut applicability);
|
||||
let (lhs, _) = snippet_with_context(cx, lhs_a.span, e.span.ctxt(), "..", &mut applicability);
|
||||
let mut sugg = if a == b {
|
||||
format!("{cond}; {lhs} = {a:?};")
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -56,8 +56,20 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
|
||||
&& let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind
|
||||
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind {
|
||||
check_expr(cx, expr, stmt.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
|
||||
if let Some(expr) = block.expr {
|
||||
check_expr(cx, expr, expr.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) {
|
||||
if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind
|
||||
&& let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind
|
||||
// Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
|
||||
// `v.foo().iter().for_each()` must be skipped.
|
||||
|
|
@ -76,69 +88,74 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
|
|||
// Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
|
||||
// and suggesting `for … in … { unsafe { } }` is a little ugly.
|
||||
&& !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..))
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
// If any closure parameter has an explicit type specified, applying the lint would necessarily
|
||||
// remove that specification, possibly breaking type inference
|
||||
if fn_decl
|
||||
.inputs
|
||||
.iter()
|
||||
.any(|input| matches!(input.kind, TyKind::Infer(..)))
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
}
|
||||
|
||||
// If any closure parameter has an explicit type specified, applying the lint would necessarily
|
||||
// remove that specification, possibly breaking type inference
|
||||
if fn_decl
|
||||
.inputs
|
||||
.iter()
|
||||
.any(|input| matches!(input.kind, TyKind::Infer(..)))
|
||||
{
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
}
|
||||
let mut ret_collector = RetCollector::default();
|
||||
ret_collector.visit_expr(body.value);
|
||||
|
||||
let mut ret_collector = RetCollector::default();
|
||||
ret_collector.visit_expr(body.value);
|
||||
// Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
|
||||
if ret_collector.ret_in_loop {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
|
||||
if ret_collector.ret_in_loop {
|
||||
return;
|
||||
}
|
||||
let ret_suggs = if ret_collector.spans.is_empty() {
|
||||
None
|
||||
} else {
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
Some(
|
||||
ret_collector
|
||||
.spans
|
||||
.into_iter()
|
||||
.map(|span| (span, "continue".to_string()))
|
||||
.collect(),
|
||||
)
|
||||
};
|
||||
|
||||
let ret_suggs = if ret_collector.spans.is_empty() {
|
||||
None
|
||||
let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability);
|
||||
let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability);
|
||||
let (body_value_sugg, is_macro_call) =
|
||||
snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability);
|
||||
|
||||
let sugg = format!(
|
||||
"for {} in {} {}",
|
||||
body_param_sugg,
|
||||
for_each_rev_sugg,
|
||||
if is_macro_call {
|
||||
format!("{{ {body_value_sugg}; }}")
|
||||
} else {
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
Some(
|
||||
ret_collector
|
||||
.spans
|
||||
.into_iter()
|
||||
.map(|span| (span, "continue".to_string()))
|
||||
.collect(),
|
||||
)
|
||||
};
|
||||
|
||||
let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability);
|
||||
let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability);
|
||||
let (body_value_sugg, is_macro_call) =
|
||||
snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability);
|
||||
|
||||
let sugg = format!(
|
||||
"for {} in {} {}",
|
||||
body_param_sugg,
|
||||
for_each_rev_sugg,
|
||||
if is_macro_call {
|
||||
format!("{{ {body_value_sugg}; }}")
|
||||
} else {
|
||||
match body.value.kind {
|
||||
ExprKind::Block(block, _) if is_let_desugar(block) => {
|
||||
format!("{{ {body_value_sugg} }}")
|
||||
},
|
||||
ExprKind::Block(_, _) => body_value_sugg.to_string(),
|
||||
_ => format!("{{ {body_value_sugg}; }}"),
|
||||
}
|
||||
match body.value.kind {
|
||||
ExprKind::Block(block, _) if is_let_desugar(block) => {
|
||||
format!("{{ {body_value_sugg} }}")
|
||||
},
|
||||
ExprKind::Block(_, _) => body_value_sugg.to_string(),
|
||||
_ => format!("{{ {body_value_sugg}; }}"),
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| {
|
||||
diag.span_suggestion(stmt.span, "try", sugg, applicability);
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_FOR_EACH,
|
||||
outer_span,
|
||||
"needless use of `for_each`",
|
||||
|diag| {
|
||||
diag.span_suggestion(outer_span, "try", sugg, applicability);
|
||||
if let Some(ret_suggs) = ret_suggs {
|
||||
diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::return_ty;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
|
||||
use clippy_utils::sugg::DiagExt;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirIdSet;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{Attribute, HirIdSet};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::AssocKind;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::sym;
|
||||
use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -59,6 +58,7 @@ pub struct NewWithoutDefault {
|
|||
impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
||||
#[expect(clippy::too_many_lines)]
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
let hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: None,
|
||||
|
|
@ -139,16 +139,34 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app));
|
||||
sugg.push('\n');
|
||||
}
|
||||
|
||||
}
|
||||
sugg
|
||||
};
|
||||
let generics_sugg = snippet_with_applicability(cx, generics.span, "", &mut app);
|
||||
let where_clause_sugg = if generics.has_where_clause_predicates {
|
||||
format!(
|
||||
"\n{}\n",
|
||||
snippet_with_applicability(cx, generics.where_clause_span, "", &mut app)
|
||||
)
|
||||
let where_clause_sugg =
|
||||
snippet_with_applicability(cx, generics.where_clause_span, "", &mut app).to_string();
|
||||
let mut where_clause_sugg = reindent_multiline(&where_clause_sugg, true, Some(4));
|
||||
if impl_item.generics.has_where_clause_predicates {
|
||||
if !where_clause_sugg.ends_with(',') {
|
||||
where_clause_sugg.push(',');
|
||||
}
|
||||
|
||||
let additional_where_preds =
|
||||
snippet_with_applicability(cx, impl_item.generics.where_clause_span, "", &mut app);
|
||||
let ident = indent_of(cx, generics.where_clause_span).unwrap_or(0);
|
||||
// Remove the leading `where ` keyword
|
||||
let additional_where_preds = additional_where_preds.trim_start_matches("where").trim_start();
|
||||
where_clause_sugg.push('\n');
|
||||
where_clause_sugg.extend(std::iter::repeat_n(' ', ident));
|
||||
where_clause_sugg.push_str(additional_where_preds);
|
||||
}
|
||||
format!("\n{where_clause_sugg}\n")
|
||||
} else if impl_item.generics.has_where_clause_predicates {
|
||||
let where_clause_sugg =
|
||||
snippet_with_applicability(cx, impl_item.generics.where_clause_span, "", &mut app);
|
||||
let where_clause_sugg = reindent_multiline(&where_clause_sugg, true, Some(4));
|
||||
format!("\n{}\n", where_clause_sugg.trim_start())
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeQPath;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
|
|
@ -94,51 +94,37 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
|
|||
return;
|
||||
}
|
||||
|
||||
let arg_snip = snippet(cx, arg_span, "..");
|
||||
let expr_snip;
|
||||
let eq_impl;
|
||||
if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() {
|
||||
expr_snip = format!("*{arg_snip}");
|
||||
eq_impl = with_deref;
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let (arg_snip, _) = snippet_with_context(cx, arg_span, expr.span.ctxt(), "..", &mut applicability);
|
||||
let (expr_snip, eq_impl) = if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() {
|
||||
(format!("*{arg_snip}"), with_deref)
|
||||
} else {
|
||||
expr_snip = arg_snip.to_string();
|
||||
eq_impl = without_deref;
|
||||
}
|
||||
(arg_snip.to_string(), without_deref)
|
||||
};
|
||||
|
||||
let span;
|
||||
let hint;
|
||||
if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
|
||||
span = expr.span;
|
||||
hint = expr_snip;
|
||||
let (span, hint) = if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
|
||||
(expr.span, expr_snip)
|
||||
} else {
|
||||
span = expr.span.to(other.span);
|
||||
let span = expr.span.to(other.span);
|
||||
|
||||
let cmp_span = if other.span < expr.span {
|
||||
other.span.between(expr.span)
|
||||
} else {
|
||||
expr.span.between(other.span)
|
||||
};
|
||||
if eq_impl.ty_eq_other {
|
||||
hint = format!(
|
||||
"{expr_snip}{}{}",
|
||||
snippet(cx, cmp_span, ".."),
|
||||
snippet(cx, other.span, "..")
|
||||
);
|
||||
} else {
|
||||
hint = format!(
|
||||
"{}{}{expr_snip}",
|
||||
snippet(cx, other.span, ".."),
|
||||
snippet(cx, cmp_span, "..")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
hint,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
let (cmp_snippet, _) = snippet_with_context(cx, cmp_span, expr.span.ctxt(), "..", &mut applicability);
|
||||
let (other_snippet, _) =
|
||||
snippet_with_context(cx, other.span, expr.span.ctxt(), "..", &mut applicability);
|
||||
|
||||
if eq_impl.ty_eq_other {
|
||||
(span, format!("{expr_snip}{cmp_snippet}{other_snippet}"))
|
||||
} else {
|
||||
(span, format!("{other_snippet}{cmp_snippet}{expr_snip}"))
|
||||
}
|
||||
};
|
||||
|
||||
diag.span_suggestion(span, "try", hint, applicability);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath};
|
||||
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
|
||||
use clippy_utils::{SpanlessEq, sym};
|
||||
use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
|
||||
|
|
@ -7,7 +8,7 @@ use rustc_data_structures::packed::Pu128;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
||||
use super::MANUAL_DIV_CEIL;
|
||||
|
|
@ -16,59 +17,84 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, lhs: &
|
|||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
if op == BinOpKind::Div
|
||||
&& check_int_ty_and_feature(cx, lhs)
|
||||
&& check_int_ty_and_feature(cx, rhs)
|
||||
&& let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = lhs.kind
|
||||
&& check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(lhs))
|
||||
&& check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(rhs))
|
||||
&& msrv.meets(cx, msrvs::DIV_CEIL)
|
||||
{
|
||||
// (x + (y - 1)) / y
|
||||
if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind
|
||||
&& inner_op.node == BinOpKind::Add
|
||||
&& sub_op.node == BinOpKind::Sub
|
||||
&& check_literal(sub_rhs)
|
||||
&& check_eq_expr(cx, sub_lhs, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability);
|
||||
return;
|
||||
}
|
||||
match lhs.kind {
|
||||
ExprKind::Binary(inner_op, inner_lhs, inner_rhs) => {
|
||||
// (x + (y - 1)) / y
|
||||
if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind
|
||||
&& inner_op.node == BinOpKind::Add
|
||||
&& sub_op.node == BinOpKind::Sub
|
||||
&& check_literal(sub_rhs)
|
||||
&& check_eq_expr(cx, sub_lhs, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability);
|
||||
return;
|
||||
}
|
||||
|
||||
// ((y - 1) + x) / y
|
||||
if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind
|
||||
&& inner_op.node == BinOpKind::Add
|
||||
&& sub_op.node == BinOpKind::Sub
|
||||
&& check_literal(sub_rhs)
|
||||
&& check_eq_expr(cx, sub_lhs, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability);
|
||||
return;
|
||||
}
|
||||
// ((y - 1) + x) / y
|
||||
if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind
|
||||
&& inner_op.node == BinOpKind::Add
|
||||
&& sub_op.node == BinOpKind::Sub
|
||||
&& check_literal(sub_rhs)
|
||||
&& check_eq_expr(cx, sub_lhs, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability);
|
||||
return;
|
||||
}
|
||||
|
||||
// (x + y - 1) / y
|
||||
if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind
|
||||
&& inner_op.node == BinOpKind::Sub
|
||||
&& add_op.node == BinOpKind::Add
|
||||
&& check_literal(inner_rhs)
|
||||
&& check_eq_expr(cx, add_rhs, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, add_lhs, rhs, &mut applicability);
|
||||
}
|
||||
// (x + y - 1) / y
|
||||
if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind
|
||||
&& inner_op.node == BinOpKind::Sub
|
||||
&& add_op.node == BinOpKind::Add
|
||||
&& check_literal(inner_rhs)
|
||||
&& check_eq_expr(cx, add_rhs, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, add_lhs, rhs, &mut applicability);
|
||||
}
|
||||
|
||||
// (x + (Y - 1)) / Y
|
||||
if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) {
|
||||
build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability);
|
||||
}
|
||||
// (x + (Y - 1)) / Y
|
||||
if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) {
|
||||
build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability);
|
||||
}
|
||||
|
||||
// ((Y - 1) + x) / Y
|
||||
if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) {
|
||||
build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability);
|
||||
}
|
||||
// ((Y - 1) + x) / Y
|
||||
if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) {
|
||||
build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability);
|
||||
}
|
||||
|
||||
// (x - (-Y - 1)) / Y
|
||||
if inner_op.node == BinOpKind::Sub
|
||||
&& let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind
|
||||
&& differ_by_one(abs_div_rhs, inner_rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability);
|
||||
// (x - (-Y - 1)) / Y
|
||||
if inner_op.node == BinOpKind::Sub
|
||||
&& let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind
|
||||
&& differ_by_one(abs_div_rhs, inner_rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability);
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(method, receiver, [next_multiple_of_arg], _) => {
|
||||
// x.next_multiple_of(Y) / Y
|
||||
if method.ident.name == sym::next_multiple_of
|
||||
&& check_int_ty(cx.typeck_results().expr_ty(receiver))
|
||||
&& check_eq_expr(cx, next_multiple_of_arg, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, receiver, rhs, &mut applicability);
|
||||
}
|
||||
},
|
||||
ExprKind::Call(callee, [receiver, next_multiple_of_arg]) => {
|
||||
// int_type::next_multiple_of(x, Y) / Y
|
||||
if let Some(impl_ty_binder) = callee
|
||||
.ty_rel_def_if_named(cx, sym::next_multiple_of)
|
||||
.assoc_fn_parent(cx)
|
||||
.opt_impl_ty(cx)
|
||||
&& check_int_ty(impl_ty_binder.skip_binder())
|
||||
&& check_eq_expr(cx, next_multiple_of_arg, rhs)
|
||||
{
|
||||
build_suggestion(cx, expr, receiver, rhs, &mut applicability);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +117,11 @@ fn differ_by_one(small_expr: &Expr<'_>, large_expr: &Expr<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let expr_ty = cx.typeck_results().expr_ty(expr);
|
||||
fn check_int_ty(expr_ty: Ty<'_>) -> bool {
|
||||
matches!(expr_ty.peel_refs().kind(), ty::Int(_) | ty::Uint(_))
|
||||
}
|
||||
|
||||
fn check_int_ty_and_feature(cx: &LateContext<'_>, expr_ty: Ty<'_>) -> bool {
|
||||
match expr_ty.peel_refs().kind() {
|
||||
ty::Uint(_) => true,
|
||||
ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings),
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
|
|||
{
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let divisor = deref_sugg(
|
||||
Sugg::hir_with_applicability(cx, operand_right, "_", &mut app),
|
||||
Sugg::hir_with_context(cx, operand_right, expr.span.ctxt(), "_", &mut app),
|
||||
cx.typeck_results().expr_ty_adjusted(operand_right),
|
||||
);
|
||||
span_lint_and_sugg(
|
||||
|
|
@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
|
|||
format!(
|
||||
"{}{}.is_multiple_of({divisor})",
|
||||
if op == BinOpKind::Eq { "" } else { "!" },
|
||||
Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren()
|
||||
Sugg::hir_with_context(cx, operand_left, expr.span.ctxt(), "_", &mut app).maybe_paren()
|
||||
),
|
||||
app,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use clippy_config::types::MatchLintBehaviour;
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
use clippy_utils::usage::local_used_after_expr;
|
||||
|
|
@ -147,7 +147,8 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
|||
&& !span_contains_cfg(cx, els.span)
|
||||
{
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
|
||||
let init_expr_str =
|
||||
Sugg::hir_with_context(cx, init_expr, stmt.span.ctxt(), "..", &mut applicability).maybe_paren();
|
||||
// Take care when binding is `ref`
|
||||
let sugg = if let PatKind::Binding(
|
||||
BindingMode(ByRef::Yes(_, ref_mutability), binding_mutability),
|
||||
|
|
@ -295,7 +296,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
|
|||
&& (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block))
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
|
||||
let receiver_str = snippet_with_context(cx, caller.span, expr.span.ctxt(), "..", &mut applicability).0;
|
||||
let by_ref = !cx.type_is_copy_modulo_regions(caller_ty)
|
||||
&& !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
|
||||
let sugg = if let Some(else_inner) = r#else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::{
|
||||
SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym,
|
||||
};
|
||||
|
|
@ -273,6 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
|||
let string_expression = &expressions[0].0;
|
||||
|
||||
let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability);
|
||||
let (right_snip, _) = snippet_with_context(cx, right.span, e.span.ctxt(), "..", &mut applicability);
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
@ -280,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
|||
e.span,
|
||||
"calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
|
||||
"try",
|
||||
format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")),
|
||||
format!("Some(&{snippet_app}[{right_snip}])"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
|
@ -404,7 +405,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
|
|||
"`to_string()` called on a `&str`",
|
||||
|diag| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability);
|
||||
let (snippet, _) =
|
||||
snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability);
|
||||
diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ declare_clippy_lint! {
|
|||
/// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This avoids calling an unsafe `libc` function.
|
||||
/// Currently, it also avoids calculating the length.
|
||||
/// libc::strlen is an unsafe function, which we don't need to call
|
||||
/// if all we want to know is the length of the c-string.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust, ignore
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_integer_const;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{ConstBlock, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
@ -42,5 +42,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
|
|||
return true;
|
||||
}
|
||||
|
||||
// Catching:
|
||||
// `std::mem::transmute({ 0 as *const u64 })` and similar const blocks
|
||||
if let ExprKind::Block(block, _) = arg.kind
|
||||
&& block.stmts.is_empty()
|
||||
&& let Some(inner) = block.expr
|
||||
{
|
||||
// Run again with the inner expression
|
||||
return check(cx, expr, inner, to_ty);
|
||||
}
|
||||
|
||||
// Catching:
|
||||
// `std::mem::transmute(const { u64::MIN as *const u64 });`
|
||||
if let ExprKind::ConstBlock(ConstBlock { body, .. }) = arg.kind {
|
||||
// Strip out the const and run again
|
||||
let block = cx.tcx.hir_body(body).value;
|
||||
return check(cx, expr, block, to_ty);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -456,13 +456,25 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>)
|
|||
|
||||
fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String {
|
||||
let mut prefix = String::new();
|
||||
for adj in cx.typeck_results().expr_adjustments(expr) {
|
||||
|
||||
let adjustments = cx.typeck_results().expr_adjustments(expr);
|
||||
|
||||
let [.., last] = adjustments else { return prefix };
|
||||
let target = last.target;
|
||||
|
||||
for adj in adjustments {
|
||||
match adj.kind {
|
||||
Adjust::Deref(_) => prefix = format!("*{prefix}"),
|
||||
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"),
|
||||
Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// Stop once we reach the final target type.
|
||||
// This prevents over-adjusting (e.g. suggesting &**y instead of *y).
|
||||
if adj.target == target {
|
||||
break;
|
||||
}
|
||||
}
|
||||
prefix
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,8 +250,8 @@ pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<
|
|||
if let hir::Attribute::Unparsed(attr_kind) = &attr
|
||||
// Identify attribute
|
||||
&& let [tool_name, attr_name] = &attr_kind.path.segments[..]
|
||||
&& tool_name.name == sym::clippy
|
||||
&& attr_name.name == sym::version
|
||||
&& tool_name == &sym::clippy
|
||||
&& attr_name == &sym::version
|
||||
&& let Some(version) = attr.value_str()
|
||||
{
|
||||
Some(version)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri
|
|||
|
||||
<!-- REUSE-IgnoreStart -->
|
||||
|
||||
Copyright 2014-2025 The Rust Project Developers
|
||||
Copyright (c) The Rust Project Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0
|
||||
<[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
|
||||
|
|
|
|||
|
|
@ -976,7 +976,9 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
|
|||
l.style == r.style
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
|
||||
(Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args),
|
||||
(Normal(l), Normal(r)) => {
|
||||
eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>(
|
|||
if let [clippy, segment2] = &*attr.path()
|
||||
&& *clippy == sym::clippy
|
||||
{
|
||||
let path_span = attr.path_span().expect("Clippy attributes are unparsed and have a span");
|
||||
let path_span = attr
|
||||
.path_span()
|
||||
.expect("Clippy attributes are unparsed and have a span");
|
||||
let new_name = match *segment2 {
|
||||
sym::cyclomatic_complexity => Some("cognitive_complexity"),
|
||||
sym::author
|
||||
|
|
@ -48,7 +50,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>(
|
|||
.with_span_suggestion(
|
||||
path_span,
|
||||
"consider using",
|
||||
format!("clippy::{}", new_name),
|
||||
format!("clippy::{new_name}"),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
|
|
|||
|
|
@ -1140,9 +1140,11 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx
|
|||
ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value),
|
||||
ConstItemRhs::TypeConst(const_arg) => match const_arg.kind {
|
||||
ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value),
|
||||
ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
|
||||
None
|
||||
},
|
||||
ConstArgKind::Struct(..)
|
||||
| ConstArgKind::TupleCall(..)
|
||||
| ConstArgKind::Path(_)
|
||||
| ConstArgKind::Error(..)
|
||||
| ConstArgKind::Infer(..) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,12 +211,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
|
|||
|
||||
// Custom `Deref` impl might have side effects
|
||||
ExprKind::Unary(UnOp::Deref, e)
|
||||
if self
|
||||
.cx
|
||||
.typeck_results()
|
||||
.expr_ty(e)
|
||||
.builtin_deref(true)
|
||||
.is_none() =>
|
||||
if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() =>
|
||||
{
|
||||
self.eagerness |= NoChange;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -671,14 +671,14 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
.iter()
|
||||
.zip(*inits_b)
|
||||
.all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr))
|
||||
}
|
||||
},
|
||||
(ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => {
|
||||
self.eq_qpath(path_a, path_b)
|
||||
&& args_a
|
||||
.iter()
|
||||
.zip(*args_b)
|
||||
.all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b))
|
||||
}
|
||||
},
|
||||
// Use explicit match for now since ConstArg is undergoing flux.
|
||||
(
|
||||
ConstArgKind::Path(..)
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
|
|||
use itertools::Itertools;
|
||||
use rustc_abi::Integer;
|
||||
use rustc_ast::ast::{self, LitKind, RangeLimits};
|
||||
use rustc_ast::join_path_syms;
|
||||
use rustc_ast::{LitIntType, join_path_syms};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexmap;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_data_structures::unhash::UnindexMap;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::attrs::{AttributeKind, CfgEntry};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::definitions::{DefPath, DefPathData};
|
||||
|
|
@ -121,7 +121,6 @@ use rustc_middle::ty::{
|
|||
self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt,
|
||||
TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
|
||||
};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw};
|
||||
|
|
@ -1386,6 +1385,17 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
/// Checks whether the given expression is an untyped integer literal.
|
||||
pub fn is_integer_literal_untyped(expr: &Expr<'_>) -> bool {
|
||||
if let ExprKind::Lit(spanned) = expr.kind
|
||||
&& let LitKind::Int(_, suffix) = spanned.node
|
||||
{
|
||||
return suffix == LitIntType::Unsuffixed;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks whether the given expression is a constant literal of the given value.
|
||||
pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool {
|
||||
if let ExprKind::Lit(spanned) = expr.kind
|
||||
|
|
@ -2403,7 +2413,10 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool {
|
|||
/// use [`is_in_cfg_test`]
|
||||
pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
|
||||
if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs)
|
||||
&& cfgs.iter().any(|(cfg, _)| { matches!(cfg, CfgEntry::NameValue { name: sym::test, ..})}) {
|
||||
&& cfgs
|
||||
.iter()
|
||||
.any(|(cfg, _)| matches!(cfg, CfgEntry::NameValue { name: sym::test, .. }))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
@ -2423,9 +2436,11 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
|
|||
/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
|
||||
pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..))
|
||||
|| find_attr!(tcx
|
||||
.hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
|
||||
.flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), AttributeKind::CfgTrace(..))
|
||||
|| find_attr!(
|
||||
tcx.hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
|
||||
.flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)),
|
||||
AttributeKind::CfgTrace(..)
|
||||
)
|
||||
}
|
||||
|
||||
/// Walks up the HIR tree from the given expression in an attempt to find where the value is
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ impl<'tcx> MaybeQPath<'tcx> for &'tcx PatExpr<'_> {
|
|||
fn opt_qpath(self) -> Option<QPathId<'tcx>> {
|
||||
match &self.kind {
|
||||
PatExprKind::Path(qpath) => Some((qpath, self.hir_id)),
|
||||
_ => None,
|
||||
PatExprKind::Lit { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -419,7 +419,7 @@ impl<'a> MaybeResPath<'a> for &PatExpr<'a> {
|
|||
fn opt_res_path(self) -> OptResPath<'a> {
|
||||
match &self.kind {
|
||||
PatExprKind::Path(qpath) => qpath.opt_res_path(),
|
||||
_ => (None, None),
|
||||
PatExprKind::Lit { .. } => (None, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ impl<'a> Sugg<'a> {
|
|||
|
||||
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
|
||||
/// function variants of `Sugg`, since these use different snippet functions.
|
||||
fn hir_from_snippet(
|
||||
pub fn hir_from_snippet(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
mut get_snippet: impl FnMut(Span) -> Cow<'a, str>,
|
||||
|
|
|
|||
|
|
@ -248,6 +248,7 @@ generate! {
|
|||
next_back,
|
||||
next_if,
|
||||
next_if_eq,
|
||||
next_multiple_of,
|
||||
next_tuple,
|
||||
nth,
|
||||
ok,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under:
|
|||
|
||||
<!-- REUSE-IgnoreStart -->
|
||||
|
||||
Copyright 2014-2025 The Rust Project Developers
|
||||
Copyright (c) The Rust Project Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ enforced-import-renames = [
|
|||
{ path = "std::clone", rename = "foo" },
|
||||
{ path = "std::thread::sleep", rename = "thread_sleep" },
|
||||
{ path = "std::any::type_name", rename = "ident" },
|
||||
{ path = "std::sync::Mutex", rename = "StdMutie" }
|
||||
{ path = "std::sync::Mutex", rename = "StdMutie" },
|
||||
{ path = "std::io::Write", rename = "to_test_rename_as_underscore" }
|
||||
]
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use std::{
|
|||
sync :: Mutex as StdMutie,
|
||||
//~^ missing_enforced_import_renames
|
||||
};
|
||||
use std::io::Write as _;
|
||||
|
||||
fn main() {
|
||||
use std::collections::BTreeMap as Map;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use std::{
|
|||
sync :: Mutex,
|
||||
//~^ missing_enforced_import_renames
|
||||
};
|
||||
use std::io::Write as _;
|
||||
|
||||
fn main() {
|
||||
use std::collections::BTreeMap as OopsWrongRename;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ LL | sync :: Mutex,
|
|||
| ^^^^^^^^^^^^^ help: try: `sync :: Mutex as StdMutie`
|
||||
|
||||
error: this import should be renamed
|
||||
--> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:20:5
|
||||
--> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:21:5
|
||||
|
|
||||
LL | use std::collections::BTreeMap as OopsWrongRename;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::collections::BTreeMap as Map`
|
||||
|
|
|
|||
|
|
@ -216,3 +216,16 @@ fn main() {
|
|||
assert!(!(b + b));
|
||||
//~^ bool_assert_comparison
|
||||
}
|
||||
|
||||
fn issue16279() {
|
||||
macro_rules! is_empty {
|
||||
($x:expr) => {
|
||||
$x.is_empty()
|
||||
};
|
||||
}
|
||||
|
||||
assert!(!is_empty!("a"));
|
||||
//~^ bool_assert_comparison
|
||||
assert!(is_empty!(""));
|
||||
//~^ bool_assert_comparison
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,3 +216,16 @@ fn main() {
|
|||
assert_eq!(b + b, false);
|
||||
//~^ bool_assert_comparison
|
||||
}
|
||||
|
||||
fn issue16279() {
|
||||
macro_rules! is_empty {
|
||||
($x:expr) => {
|
||||
$x.is_empty()
|
||||
};
|
||||
}
|
||||
|
||||
assert_eq!(is_empty!("a"), false);
|
||||
//~^ bool_assert_comparison
|
||||
assert_eq!(is_empty!(""), true);
|
||||
//~^ bool_assert_comparison
|
||||
}
|
||||
|
|
|
|||
|
|
@ -444,5 +444,29 @@ LL - assert_eq!(b + b, false);
|
|||
LL + assert!(!(b + b));
|
||||
|
|
||||
|
||||
error: aborting due to 37 previous errors
|
||||
error: used `assert_eq!` with a literal bool
|
||||
--> tests/ui/bool_assert_comparison.rs:227:5
|
||||
|
|
||||
LL | assert_eq!(is_empty!("a"), false);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: replace it with `assert!(..)`
|
||||
|
|
||||
LL - assert_eq!(is_empty!("a"), false);
|
||||
LL + assert!(!is_empty!("a"));
|
||||
|
|
||||
|
||||
error: used `assert_eq!` with a literal bool
|
||||
--> tests/ui/bool_assert_comparison.rs:229:5
|
||||
|
|
||||
LL | assert_eq!(is_empty!(""), true);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: replace it with `assert!(..)`
|
||||
|
|
||||
LL - assert_eq!(is_empty!(""), true);
|
||||
LL + assert!(is_empty!(""));
|
||||
|
|
||||
|
||||
error: aborting due to 39 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(
|
||||
clippy::cast_lossless,
|
||||
clippy::legacy_numeric_constants,
|
||||
clippy::no_effect,
|
||||
unused,
|
||||
// Int::max_value will be deprecated in the future
|
||||
deprecated,
|
||||
|
|
@ -105,4 +106,19 @@ fn msrv_1_34() {
|
|||
//~^ checked_conversions
|
||||
}
|
||||
|
||||
fn issue16293() {
|
||||
struct Outer {
|
||||
inner: u32,
|
||||
}
|
||||
let outer = Outer { inner: 42 };
|
||||
macro_rules! dot_inner {
|
||||
($obj:expr) => {
|
||||
$obj.inner
|
||||
};
|
||||
}
|
||||
|
||||
i32::try_from(dot_inner!(outer)).is_ok();
|
||||
//~^ checked_conversions
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(
|
||||
clippy::cast_lossless,
|
||||
clippy::legacy_numeric_constants,
|
||||
clippy::no_effect,
|
||||
unused,
|
||||
// Int::max_value will be deprecated in the future
|
||||
deprecated,
|
||||
|
|
@ -105,4 +106,19 @@ fn msrv_1_34() {
|
|||
//~^ checked_conversions
|
||||
}
|
||||
|
||||
fn issue16293() {
|
||||
struct Outer {
|
||||
inner: u32,
|
||||
}
|
||||
let outer = Outer { inner: 42 };
|
||||
macro_rules! dot_inner {
|
||||
($obj:expr) => {
|
||||
$obj.inner
|
||||
};
|
||||
}
|
||||
|
||||
dot_inner!(outer) <= i32::MAX as u32;
|
||||
//~^ checked_conversions
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:15:13
|
||||
--> tests/ui/checked_conversions.rs:16:13
|
||||
|
|
||||
LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
|
||||
|
|
@ -8,100 +8,106 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:17:13
|
||||
--> tests/ui/checked_conversions.rs:18:13
|
||||
|
|
||||
LL | let _ = value <= (u32::MAX as i64) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:22:13
|
||||
--> tests/ui/checked_conversions.rs:23:13
|
||||
|
|
||||
LL | let _ = value <= i64::from(u16::max_value()) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:24:13
|
||||
--> tests/ui/checked_conversions.rs:25:13
|
||||
|
|
||||
LL | let _ = value <= i64::from(u16::MAX) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:29:13
|
||||
--> tests/ui/checked_conversions.rs:30:13
|
||||
|
|
||||
LL | let _ = value <= (u8::max_value() as isize) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:31:13
|
||||
--> tests/ui/checked_conversions.rs:32:13
|
||||
|
|
||||
LL | let _ = value <= (u8::MAX as isize) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:38:13
|
||||
--> tests/ui/checked_conversions.rs:39:13
|
||||
|
|
||||
LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:40:13
|
||||
--> tests/ui/checked_conversions.rs:41:13
|
||||
|
|
||||
LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:45:13
|
||||
--> tests/ui/checked_conversions.rs:46:13
|
||||
|
|
||||
LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:47:13
|
||||
--> tests/ui/checked_conversions.rs:48:13
|
||||
|
|
||||
LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:54:13
|
||||
--> tests/ui/checked_conversions.rs:55:13
|
||||
|
|
||||
LL | let _ = value <= i32::max_value() as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:56:13
|
||||
--> tests/ui/checked_conversions.rs:57:13
|
||||
|
|
||||
LL | let _ = value <= i32::MAX as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:61:13
|
||||
--> tests/ui/checked_conversions.rs:62:13
|
||||
|
|
||||
LL | let _ = value <= isize::max_value() as usize && value as i32 == 5;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:63:13
|
||||
--> tests/ui/checked_conversions.rs:64:13
|
||||
|
|
||||
LL | let _ = value <= isize::MAX as usize && value as i32 == 5;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:68:13
|
||||
--> tests/ui/checked_conversions.rs:69:13
|
||||
|
|
||||
LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:70:13
|
||||
--> tests/ui/checked_conversions.rs:71:13
|
||||
|
|
||||
LL | let _ = value <= u16::MAX as u32 && value as i32 == 5;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
|
||||
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:104:13
|
||||
--> tests/ui/checked_conversions.rs:105:13
|
||||
|
|
||||
LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: checked cast can be simplified
|
||||
--> tests/ui/checked_conversions.rs:120:5
|
||||
|
|
||||
LL | dot_inner!(outer) <= i32::MAX as u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(dot_inner!(outer)).is_ok()`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -83,3 +83,32 @@ fn issue_8103() {
|
|||
let _ = foo1 == foo2;
|
||||
//~^ cmp_owned
|
||||
}
|
||||
|
||||
macro_rules! issue16322_macro_generator {
|
||||
($locale:ident) => {
|
||||
mod $locale {
|
||||
macro_rules! _make {
|
||||
($token:tt) => {
|
||||
stringify!($token)
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use _make;
|
||||
}
|
||||
|
||||
macro_rules! t {
|
||||
($token:tt) => {
|
||||
crate::$locale::_make!($token)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
issue16322_macro_generator!(de);
|
||||
|
||||
fn issue16322(item: String) {
|
||||
if item == t!(frohes_neu_Jahr) {
|
||||
//~^ cmp_owned
|
||||
println!("Ja!");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,3 +83,32 @@ fn issue_8103() {
|
|||
let _ = foo1 == foo2.to_owned();
|
||||
//~^ cmp_owned
|
||||
}
|
||||
|
||||
macro_rules! issue16322_macro_generator {
|
||||
($locale:ident) => {
|
||||
mod $locale {
|
||||
macro_rules! _make {
|
||||
($token:tt) => {
|
||||
stringify!($token)
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use _make;
|
||||
}
|
||||
|
||||
macro_rules! t {
|
||||
($token:tt) => {
|
||||
crate::$locale::_make!($token)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
issue16322_macro_generator!(de);
|
||||
|
||||
fn issue16322(item: String) {
|
||||
if item == t!(frohes_neu_Jahr).to_string() {
|
||||
//~^ cmp_owned
|
||||
println!("Ja!");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,5 +49,11 @@ error: this creates an owned instance just for comparison
|
|||
LL | let _ = foo1 == foo2.to_owned();
|
||||
| ^^^^^^^^^^^^^^^ help: try: `foo2`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: this creates an owned instance just for comparison
|
||||
--> tests/ui/cmp_owned/with_suggestion.rs:110:16
|
||||
|
|
||||
LL | if item == t!(frohes_neu_Jahr).to_string() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -91,3 +91,17 @@ mod issue15708 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod issue16298 {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
|
||||
struct Normalized<S>(S);
|
||||
|
||||
impl<S: Eq> Eq for Normalized<S> {}
|
||||
|
||||
#[expect(clippy::derive_ord_xor_partial_ord)]
|
||||
impl<S: Eq + PartialOrd> Ord for Normalized<S> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,4 +161,20 @@ fn issue15940() {
|
|||
pub struct Person;
|
||||
}
|
||||
|
||||
fn issue16224() {
|
||||
fn test() -> i32 { 42 }
|
||||
|
||||
macro_rules! call {
|
||||
($matcher:pat $(=> $result:expr)?) => {
|
||||
match test() {
|
||||
$matcher => Result::Ok(($($result),*)),
|
||||
_ => Result::Err("No match".to_string()),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let _: Result<(), String> = call!(_);
|
||||
let _: Result<i32, String> = call!(_ => 42);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -161,4 +161,20 @@ fn issue15940() {
|
|||
pub struct Person;
|
||||
}
|
||||
|
||||
fn issue16224() {
|
||||
fn test() -> i32 { 42 }
|
||||
|
||||
macro_rules! call {
|
||||
($matcher:pat $(=> $result:expr)?) => {
|
||||
match test() {
|
||||
$matcher => Result::Ok(($($result),*)),
|
||||
_ => Result::Err("No match".to_string()),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let _: Result<(), String> = call!(_);
|
||||
let _: Result<i32, String> = call!(_ => 42);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -69,3 +69,20 @@ fn main() {
|
|||
let _v = v;
|
||||
}
|
||||
}
|
||||
|
||||
fn wrongly_unmangled_macros() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
macro_rules! test_map {
|
||||
($val:expr) => {
|
||||
&*$val
|
||||
};
|
||||
}
|
||||
|
||||
let m: HashMap<u64, u64> = HashMap::new();
|
||||
let wrapped = Rc::new(m);
|
||||
for v in test_map!(wrapped).values() {
|
||||
//~^ for_kv_map
|
||||
let _v = v;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,3 +69,20 @@ fn main() {
|
|||
let _v = v;
|
||||
}
|
||||
}
|
||||
|
||||
fn wrongly_unmangled_macros() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
macro_rules! test_map {
|
||||
($val:expr) => {
|
||||
&*$val
|
||||
};
|
||||
}
|
||||
|
||||
let m: HashMap<u64, u64> = HashMap::new();
|
||||
let wrapped = Rc::new(m);
|
||||
for (_, v) in test_map!(wrapped) {
|
||||
//~^ for_kv_map
|
||||
let _v = v;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,5 +72,17 @@ LL - 'label: for (k, _value) in rm {
|
|||
LL + 'label: for k in rm.keys() {
|
||||
|
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: you seem to want to iterate on a map's values
|
||||
--> tests/ui/for_kv_map.rs:84:19
|
||||
|
|
||||
LL | for (_, v) in test_map!(wrapped) {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use the corresponding method
|
||||
|
|
||||
LL - for (_, v) in test_map!(wrapped) {
|
||||
LL + for v in test_map!(wrapped).values() {
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ impl MyStruct {
|
|||
}
|
||||
|
||||
impl<'a> MyStruct {
|
||||
//~^ multiple_inherent_impl
|
||||
fn lifetimed() {}
|
||||
}
|
||||
|
||||
|
|
@ -90,10 +91,12 @@ struct Lifetime<'s> {
|
|||
}
|
||||
|
||||
impl Lifetime<'_> {}
|
||||
impl Lifetime<'_> {} // false negative
|
||||
impl Lifetime<'_> {}
|
||||
//~^ multiple_inherent_impl
|
||||
|
||||
impl<'a> Lifetime<'a> {}
|
||||
impl<'a> Lifetime<'a> {} // false negative
|
||||
impl<'a> Lifetime<'a> {}
|
||||
//~^ multiple_inherent_impl
|
||||
|
||||
impl<'b> Lifetime<'b> {} // false negative?
|
||||
|
||||
|
|
@ -104,6 +107,39 @@ struct Generic<G> {
|
|||
}
|
||||
|
||||
impl<G> Generic<G> {}
|
||||
impl<G> Generic<G> {} // false negative
|
||||
impl<G> Generic<G> {}
|
||||
//~^ multiple_inherent_impl
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GenericWithBounds<T: Debug>(T);
|
||||
|
||||
impl<T: Debug> GenericWithBounds<T> {
|
||||
fn make_one(_one: T) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> GenericWithBounds<T> {
|
||||
//~^ multiple_inherent_impl
|
||||
fn make_two(_two: T) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct MultipleTraitBounds<T>(T);
|
||||
|
||||
impl<T: Debug> MultipleTraitBounds<T> {
|
||||
fn debug_fn() {}
|
||||
}
|
||||
|
||||
impl<T: Clone> MultipleTraitBounds<T> {
|
||||
fn clone_fn() {}
|
||||
}
|
||||
|
||||
impl<T: Debug + Clone> MultipleTraitBounds<T> {
|
||||
fn debug_clone_fn() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,24 @@ LL | | }
|
|||
= help: to override `-D warnings` add `#[allow(clippy::multiple_inherent_impl)]`
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:26:5
|
||||
--> tests/ui/impl.rs:16:1
|
||||
|
|
||||
LL | / impl<'a> MyStruct {
|
||||
LL | |
|
||||
LL | | fn lifetimed() {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:6:1
|
||||
|
|
||||
LL | / impl MyStruct {
|
||||
LL | | fn first() {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:27:5
|
||||
|
|
||||
LL | / impl super::MyStruct {
|
||||
LL | |
|
||||
|
|
@ -37,7 +54,7 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:48:1
|
||||
--> tests/ui/impl.rs:49:1
|
||||
|
|
||||
LL | / impl WithArgs<u64> {
|
||||
LL | |
|
||||
|
|
@ -47,7 +64,7 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:45:1
|
||||
--> tests/ui/impl.rs:46:1
|
||||
|
|
||||
LL | / impl WithArgs<u64> {
|
||||
LL | | fn f2() {}
|
||||
|
|
@ -55,28 +72,85 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:71:1
|
||||
--> tests/ui/impl.rs:72:1
|
||||
|
|
||||
LL | impl OneAllowedImpl {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:68:1
|
||||
--> tests/ui/impl.rs:69:1
|
||||
|
|
||||
LL | impl OneAllowedImpl {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:84:1
|
||||
--> tests/ui/impl.rs:85:1
|
||||
|
|
||||
LL | impl OneExpected {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:81:1
|
||||
--> tests/ui/impl.rs:82:1
|
||||
|
|
||||
LL | impl OneExpected {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:94:1
|
||||
|
|
||||
LL | impl Lifetime<'_> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:93:1
|
||||
|
|
||||
LL | impl Lifetime<'_> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:98:1
|
||||
|
|
||||
LL | impl<'a> Lifetime<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:97:1
|
||||
|
|
||||
LL | impl<'a> Lifetime<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:110:1
|
||||
|
|
||||
LL | impl<G> Generic<G> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:109:1
|
||||
|
|
||||
LL | impl<G> Generic<G> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple implementations of this structure
|
||||
--> tests/ui/impl.rs:124:1
|
||||
|
|
||||
LL | / impl<T: Debug> GenericWithBounds<T> {
|
||||
LL | |
|
||||
LL | | fn make_two(_two: T) -> Self {
|
||||
LL | | todo!()
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: first implementation here
|
||||
--> tests/ui/impl.rs:118:1
|
||||
|
|
||||
LL | / impl<T: Debug> GenericWithBounds<T> {
|
||||
LL | | fn make_one(_one: T) -> Self {
|
||||
LL | | todo!()
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -252,3 +252,11 @@ fn arbitrary_expression() {
|
|||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn issue16307() {
|
||||
let x: u8 = 100;
|
||||
let y = 100_u8.saturating_sub(x);
|
||||
//~^ implicit_saturating_sub
|
||||
|
||||
println!("{y}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,3 +326,11 @@ fn arbitrary_expression() {
|
|||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn issue16307() {
|
||||
let x: u8 = 100;
|
||||
let y = if x >= 100 { 0 } else { 100 - x };
|
||||
//~^ implicit_saturating_sub
|
||||
|
||||
println!("{y}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,5 +238,11 @@ error: manual arithmetic check found
|
|||
LL | let _ = if a < b * 2 { 0 } else { a - b * 2 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b * 2)`
|
||||
|
||||
error: aborting due to 27 previous errors
|
||||
error: manual arithmetic check found
|
||||
--> tests/ui/implicit_saturating_sub.rs:332:13
|
||||
|
|
||||
LL | let y = if x >= 100 { 0 } else { 100 - x };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `100_u8.saturating_sub(x)`
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -189,3 +189,9 @@ fn issue14595() {
|
|||
let _ = map.as_ref().values().copied().collect::<Vec<_>>();
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
||||
fn issue16340() {
|
||||
let hm: HashMap<&str, &str> = HashMap::new();
|
||||
let _ = hm.keys().map(|key| vec![key]);
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,3 +193,9 @@ fn issue14595() {
|
|||
let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
||||
fn issue16340() {
|
||||
let hm: HashMap<&str, &str> = HashMap::new();
|
||||
let _ = hm.iter().map(|(key, _)| vec![key]);
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,5 +269,11 @@ error: iterating on a map's values
|
|||
LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()`
|
||||
|
||||
error: aborting due to 39 previous errors
|
||||
error: iterating on a map's keys
|
||||
--> tests/ui/iter_kv_map.rs:199:13
|
||||
|
|
||||
LL | let _ = hm.iter().map(|(key, _)| vec![key]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])`
|
||||
|
||||
error: aborting due to 40 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) {
|
|||
let _ = size.div_ceil(*c);
|
||||
//~^ manual_div_ceil
|
||||
}
|
||||
|
||||
struct MyStruct(u32);
|
||||
impl MyStruct {
|
||||
// Method matching name on different type should not trigger lint
|
||||
fn next_multiple_of(self, y: u32) -> u32 {
|
||||
self.0.next_multiple_of(y)
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_16219() {
|
||||
let x = 33u32;
|
||||
|
||||
// Lint.
|
||||
let _ = x.div_ceil(8);
|
||||
//~^ manual_div_ceil
|
||||
let _ = x.div_ceil(8);
|
||||
//~^ manual_div_ceil
|
||||
|
||||
let y = &x;
|
||||
let _ = y.div_ceil(8);
|
||||
//~^ manual_div_ceil
|
||||
|
||||
// No lint.
|
||||
let _ = x.next_multiple_of(8) / 7;
|
||||
let _ = x.next_multiple_of(7) / 8;
|
||||
|
||||
let z = MyStruct(x);
|
||||
let _ = z.next_multiple_of(8) / 8;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) {
|
|||
let _ = (size + c - 1) / c;
|
||||
//~^ manual_div_ceil
|
||||
}
|
||||
|
||||
struct MyStruct(u32);
|
||||
impl MyStruct {
|
||||
// Method matching name on different type should not trigger lint
|
||||
fn next_multiple_of(self, y: u32) -> u32 {
|
||||
self.0.next_multiple_of(y)
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_16219() {
|
||||
let x = 33u32;
|
||||
|
||||
// Lint.
|
||||
let _ = x.next_multiple_of(8) / 8;
|
||||
//~^ manual_div_ceil
|
||||
let _ = u32::next_multiple_of(x, 8) / 8;
|
||||
//~^ manual_div_ceil
|
||||
|
||||
let y = &x;
|
||||
let _ = y.next_multiple_of(8) / 8;
|
||||
//~^ manual_div_ceil
|
||||
|
||||
// No lint.
|
||||
let _ = x.next_multiple_of(8) / 7;
|
||||
let _ = x.next_multiple_of(7) / 8;
|
||||
|
||||
let z = MyStruct(x);
|
||||
let _ = z.next_multiple_of(8) / 8;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,5 +131,23 @@ error: manually reimplementing `div_ceil`
|
|||
LL | let _ = (size + c - 1) / c;
|
||||
| ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `size.div_ceil(*c)`
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: manually reimplementing `div_ceil`
|
||||
--> tests/ui/manual_div_ceil.rs:121:13
|
||||
|
|
||||
LL | let _ = x.next_multiple_of(8) / 8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
|
||||
|
||||
error: manually reimplementing `div_ceil`
|
||||
--> tests/ui/manual_div_ceil.rs:123:13
|
||||
|
|
||||
LL | let _ = u32::next_multiple_of(x, 8) / 8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
|
||||
|
||||
error: manually reimplementing `div_ceil`
|
||||
--> tests/ui/manual_div_ceil.rs:127:13
|
||||
|
|
||||
LL | let _ = y.next_multiple_of(8) / 8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)`
|
||||
|
||||
error: aborting due to 23 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -84,3 +84,32 @@ fn issue_13950() {
|
|||
let _ = y.div_ceil(-7);
|
||||
//~^ manual_div_ceil
|
||||
}
|
||||
|
||||
struct MyStruct(i32);
|
||||
impl MyStruct {
|
||||
// Method matching name on different type should not trigger lint
|
||||
fn next_multiple_of(self, y: i32) -> i32 {
|
||||
self.0.next_multiple_of(y)
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_16219() {
|
||||
let x = 33i32;
|
||||
|
||||
// Lint.
|
||||
let _ = x.div_ceil(8);
|
||||
//~^ manual_div_ceil
|
||||
let _ = x.div_ceil(8);
|
||||
//~^ manual_div_ceil
|
||||
|
||||
let y = &x;
|
||||
let _ = y.div_ceil(8);
|
||||
//~^ manual_div_ceil
|
||||
|
||||
// No lint.
|
||||
let _ = x.next_multiple_of(8) / 7;
|
||||
let _ = x.next_multiple_of(7) / 8;
|
||||
|
||||
let z = MyStruct(x);
|
||||
let _ = z.next_multiple_of(8) / 8;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,3 +84,32 @@ fn issue_13950() {
|
|||
let _ = (y - 8) / -7;
|
||||
//~^ manual_div_ceil
|
||||
}
|
||||
|
||||
struct MyStruct(i32);
|
||||
impl MyStruct {
|
||||
// Method matching name on different type should not trigger lint
|
||||
fn next_multiple_of(self, y: i32) -> i32 {
|
||||
self.0.next_multiple_of(y)
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_16219() {
|
||||
let x = 33i32;
|
||||
|
||||
// Lint.
|
||||
let _ = x.next_multiple_of(8) / 8;
|
||||
//~^ manual_div_ceil
|
||||
let _ = i32::next_multiple_of(x, 8) / 8;
|
||||
//~^ manual_div_ceil
|
||||
|
||||
let y = &x;
|
||||
let _ = y.next_multiple_of(8) / 8;
|
||||
//~^ manual_div_ceil
|
||||
|
||||
// No lint.
|
||||
let _ = x.next_multiple_of(8) / 7;
|
||||
let _ = x.next_multiple_of(7) / 8;
|
||||
|
||||
let z = MyStruct(x);
|
||||
let _ = z.next_multiple_of(8) / 8;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,5 +139,23 @@ error: manually reimplementing `div_ceil`
|
|||
LL | let _ = (y - 8) / -7;
|
||||
| ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)`
|
||||
|
||||
error: aborting due to 23 previous errors
|
||||
error: manually reimplementing `div_ceil`
|
||||
--> tests/ui/manual_div_ceil_with_feature.rs:100:13
|
||||
|
|
||||
LL | let _ = x.next_multiple_of(8) / 8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
|
||||
|
||||
error: manually reimplementing `div_ceil`
|
||||
--> tests/ui/manual_div_ceil_with_feature.rs:102:13
|
||||
|
|
||||
LL | let _ = i32::next_multiple_of(x, 8) / 8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
|
||||
|
||||
error: manually reimplementing `div_ceil`
|
||||
--> tests/ui/manual_div_ceil_with_feature.rs:106:13
|
||||
|
|
||||
LL | let _ = y.next_multiple_of(8) / 8;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)`
|
||||
|
||||
error: aborting due to 26 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) {
|
|||
b.eq_ignore_ascii_case(a);
|
||||
//~^ manual_ignore_case_cmp
|
||||
}
|
||||
|
||||
fn wrongly_unmangled_macros(a: &str, b: &str) -> bool {
|
||||
struct S<'a> {
|
||||
inner: &'a str,
|
||||
}
|
||||
|
||||
let a = S { inner: a };
|
||||
let b = S { inner: b };
|
||||
|
||||
macro_rules! dot_inner {
|
||||
($s:expr) => {
|
||||
$s.inner
|
||||
};
|
||||
}
|
||||
|
||||
dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b))
|
||||
//~^ manual_ignore_case_cmp
|
||||
|| dot_inner!(a).eq_ignore_ascii_case("abc")
|
||||
//~^ manual_ignore_case_cmp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) {
|
|||
b.to_ascii_lowercase() == a.to_ascii_lowercase();
|
||||
//~^ manual_ignore_case_cmp
|
||||
}
|
||||
|
||||
fn wrongly_unmangled_macros(a: &str, b: &str) -> bool {
|
||||
struct S<'a> {
|
||||
inner: &'a str,
|
||||
}
|
||||
|
||||
let a = S { inner: a };
|
||||
let b = S { inner: b };
|
||||
|
||||
macro_rules! dot_inner {
|
||||
($s:expr) => {
|
||||
$s.inner
|
||||
};
|
||||
}
|
||||
|
||||
dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase()
|
||||
//~^ manual_ignore_case_cmp
|
||||
|| dot_inner!(a).to_ascii_lowercase() == "abc"
|
||||
//~^ manual_ignore_case_cmp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -588,5 +588,29 @@ LL - b.to_ascii_lowercase() == a.to_ascii_lowercase();
|
|||
LL + b.eq_ignore_ascii_case(a);
|
||||
|
|
||||
|
||||
error: aborting due to 49 previous errors
|
||||
error: manual case-insensitive ASCII comparison
|
||||
--> tests/ui/manual_ignore_case_cmp.rs:178:5
|
||||
|
|
||||
LL | dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `.eq_ignore_ascii_case()` instead
|
||||
|
|
||||
LL - dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase()
|
||||
LL + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b))
|
||||
|
|
||||
|
||||
error: manual case-insensitive ASCII comparison
|
||||
--> tests/ui/manual_ignore_case_cmp.rs:180:12
|
||||
|
|
||||
LL | || dot_inner!(a).to_ascii_lowercase() == "abc"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `.eq_ignore_ascii_case()` instead
|
||||
|
|
||||
LL - || dot_inner!(a).to_ascii_lowercase() == "abc"
|
||||
LL + || dot_inner!(a).eq_ignore_ascii_case("abc")
|
||||
|
|
||||
|
||||
error: aborting due to 51 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) {
|
|||
external!($a.ilog(2));
|
||||
with_span!(span; a.ilog(2));
|
||||
}
|
||||
|
||||
fn wrongly_unmangled_macros() {
|
||||
struct S {
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
let x = S { inner: 42 };
|
||||
macro_rules! access {
|
||||
($s:expr) => {
|
||||
$s.inner
|
||||
};
|
||||
}
|
||||
let log = access!(x).ilog2();
|
||||
//~^ manual_ilog2
|
||||
let log = access!(x).ilog2();
|
||||
//~^ manual_ilog2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) {
|
|||
external!($a.ilog(2));
|
||||
with_span!(span; a.ilog(2));
|
||||
}
|
||||
|
||||
fn wrongly_unmangled_macros() {
|
||||
struct S {
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
let x = S { inner: 42 };
|
||||
macro_rules! access {
|
||||
($s:expr) => {
|
||||
$s.inner
|
||||
};
|
||||
}
|
||||
let log = 31 - access!(x).leading_zeros();
|
||||
//~^ manual_ilog2
|
||||
let log = access!(x).ilog(2);
|
||||
//~^ manual_ilog2
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue