Merge commit '03a5b6b976' into clippy-subtree-update

This commit is contained in:
Philipp Krones 2025-05-01 10:22:55 +02:00
parent 6d589103e9
commit dd5113daab
109 changed files with 1822 additions and 585 deletions

View file

@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym};
use rustc_errors::Applicability;
use rustc_hir::{self as hir, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir;
use rustc_middle::ty::{self, Instance, Mutability};
use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::{Span, SyntaxContext};
declare_clippy_lint! {
@ -86,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
&& ctxt.is_root()
&& let which_trait = match fn_name {
sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
_ if fn_name.as_str() == "to_owned"
&& is_diag_trait_item(cx, fn_id, sym::ToOwned)
&& self.msrv.meets(cx, msrvs::CLONE_INTO) =>
sym::to_owned
if is_diag_trait_item(cx, fn_id, sym::ToOwned)
&& self.msrv.meets(cx, msrvs::CLONE_INTO) =>
{
CloneTrait::ToOwned
},
@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
&& resolved_assoc_items.in_definition_order().any(|assoc|
match which_trait {
CloneTrait::Clone => assoc.name() == sym::clone_from,
CloneTrait::ToOwned => assoc.name().as_str() == "clone_into",
CloneTrait::ToOwned => assoc.name() == sym::clone_into,
}
)
&& !clone_source_borrows_from_dest(cx, lhs, rhs.span)

View file

@ -1,17 +1,15 @@
use super::BLANKET_CLIPPY_RESTRICTION_LINTS;
use super::utils::extract_clippy_lint;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::sym;
use rustc_ast::MetaItemInner;
use rustc_lint::{EarlyContext, Level, LintContext};
use rustc_span::DUMMY_SP;
use rustc_span::symbol::Symbol;
use rustc_span::{DUMMY_SP, sym};
pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) {
for lint in items {
if let Some(lint_name) = extract_clippy_lint(lint)
&& lint_name.as_str() == "restriction"
&& name != sym::allow
{
if name != sym::allow && extract_clippy_lint(lint) == Some(sym::restriction) {
span_lint_and_help(
cx,
BLANKET_CLIPPY_RESTRICTION_LINTS,

View file

@ -73,7 +73,7 @@ fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::Met
}
fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) {
if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") {
if item.has_name(sym::feature) && item.value_str() == Some(sym::cargo_clippy) {
span_lint_and_sugg(
cx,
DEPRECATED_CLIPPY_CFG_ATTR,

View file

@ -1,5 +1,6 @@
use super::DEPRECATED_SEMVER;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::sym;
use rustc_ast::{LitKind, MetaItemLit};
use rustc_lint::EarlyContext;
use rustc_span::Span;
@ -7,7 +8,7 @@ use semver::Version;
pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) {
if let LitKind::Str(is, _) = lit.kind
&& (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok())
&& (is == sym::TBD || Version::parse(is.as_str()).is_ok())
{
return;
}

View file

@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::sym;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
@ -19,7 +20,7 @@ pub(super) fn check(
if let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
&& let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind
&& method_path.ident.name.as_str() == "abs"
&& method_path.ident.name == sym::abs
&& msrv.meets(cx, msrvs::UNSIGNED_ABS)
{
let span = if from.bit_width() == to.bit_width() {

View file

@ -1,9 +1,9 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::expr_or_init;
use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
use clippy_utils::{expr_or_init, sym};
use rustc_abi::IntegerType;
use rustc_errors::{Applicability, Diag};
use rustc_hir::def::{DefKind, Res};
@ -73,7 +73,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
nbits
},
ExprKind::MethodCall(method, _value, [], _) => {
if method.ident.name.as_str() == "signum" {
if method.ident.name == sym::signum {
0 // do not lint if cast comes from a `signum` function
} else {
nbits

View file

@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_c_void;
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant};
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym};
use rustc_hir::{Expr, ExprKind, GenericArg};
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_span::sym;
use super::CAST_PTR_ALIGNMENT;
@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
);
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
} else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind
&& method_path.ident.name.as_str() == "cast"
&& method_path.ident.name == sym::cast
&& let Some(generic_args) = method_path.args
&& let [GenericArg::Type(cast_to)] = generic_args.args
// There probably is no obvious reason to do this, just to be consistent with `as` cases.

View file

@ -8,7 +8,9 @@ use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
use rustc_span::{Symbol, sym};
use std::ops::ControlFlow;
use super::UNNECESSARY_CAST;
@ -142,6 +144,33 @@ pub(super) fn check<'tcx>(
}
if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
enum MaybeParenOrBlock {
Paren,
Block,
Nothing,
}
fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(expr.kind, ExprKind::AddrOf(..))
|| cx
.typeck_results()
.expr_adjustments(expr)
.first()
.is_some_and(|adj| matches!(adj.kind, Adjust::Borrow(_)))
}
fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
const ALLOWED_MACROS: &[Symbol] = &[
sym::format_args_macro,
sym::assert_eq_macro,
sym::debug_assert_eq_macro,
sym::assert_ne_macro,
sym::debug_assert_ne_macro,
];
matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if
cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym)))
}
if let Some(id) = path_to_local(cast_expr)
&& !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span)
{
@ -150,15 +179,15 @@ pub(super) fn check<'tcx>(
return false;
}
// If the whole cast expression is a unary expression (`(*x as T)`) or an addressof
// expression (`(&x as T)`), then not surrounding the suggestion into a block risks us
// changing the precedence of operators if the cast expression is followed by an operation
// with higher precedence than the unary operator (`(*x as T).foo()` would become
// `*x.foo()`, which changes what the `*` applies on).
// The same is true if the expression encompassing the cast expression is a unary
// expression or an addressof expression.
let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))
|| get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
// Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates
// a reference to the temporary while the latter creates a reference to the original value.
let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) {
Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => {
MaybeParenOrBlock::Block
},
Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren,
_ => MaybeParenOrBlock::Nothing,
};
span_lint_and_sugg(
cx,
@ -166,10 +195,10 @@ pub(super) fn check<'tcx>(
expr.span,
format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
"try",
if needs_block {
format!("{{ {cast_str} }}")
} else {
cast_str
match surrounding {
MaybeParenOrBlock::Paren => format!("({cast_str})"),
MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"),
MaybeParenOrBlock::Nothing => cast_str,
},
Applicability::MachineApplicable,
);

View file

@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::sym;
use rustc_span::{Span, kw};
declare_clippy_lint! {
/// ### What it does
@ -105,12 +105,11 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
fn is_crate_keyword(tt: &TokenTree) -> Option<Span> {
if let TokenTree::Token(
Token {
kind: TokenKind::Ident(symbol, _),
kind: TokenKind::Ident(kw::Crate, _),
span,
},
_,
) = tt
&& symbol.as_str() == "crate"
{
Some(*span)
} else {

View file

@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
}
}
/// Check if the pattern has any type mismatch that would prevent it from being used in an equality
/// check. This can happen if the expr has a reference type and the corresponding pattern is a
/// literal.
fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
let mut result = false;
pat.walk(|p| {
if result {
return false;
}
if p.span.in_external_macro(cx.sess().source_map()) {
return true;
}
let adjust_pat = match p.kind {
PatKind::Or([p, ..]) => p,
_ => p,
};
if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id)
&& adjustments.first().is_some_and(|first| first.source.is_ref())
{
result = true;
return false;
}
true
});
result
}
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::Let(let_expr) = expr.kind
@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
let mut applicability = Applicability::MachineApplicable;
if is_structural_partial_eq(cx, exp_ty, pat_ty) {
if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) {
let pat_str = match let_expr.pat.kind {
PatKind::Struct(..) => format!(
"({})",

View file

@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{
eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
numeric_literal, peel_blocks, sugg,
numeric_literal, peel_blocks, sugg, sym,
};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@ -435,7 +435,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
rhs,
) = expr.kind
&& let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind
&& path.ident.name.as_str() == "exp"
&& path.ident.name == sym::exp
&& cx.typeck_results().expr_ty(lhs).is_floating_point()
&& let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
&& (F32(1.0) == value || F64(1.0) == value)

View file

@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::path_def_id;
use clippy_utils::ty::is_c_void;
use clippy_utils::{path_def_id, sym};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -41,7 +40,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
&& seg.ident.name.as_str() == "from_raw"
&& seg.ident.name == sym::from_raw
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
&& let ty::RawPtr(ty, _) = arg_kind

View file

@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::{is_in_const_context, is_integer_literal};
use clippy_utils::{is_in_const_context, is_integer_literal, sym};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
// check if the second part of the path indeed calls the associated
// function `from_str_radix`
&& pathseg.ident.name.as_str() == "from_str_radix"
&& pathseg.ident.name == sym::from_str_radix
// check if the first part of the path is some integer primitive
&& let TyKind::Path(ty_qpath) = &ty.kind

View file

@ -10,10 +10,10 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::sym;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
use clippy_utils::sym;
use clippy_utils::ty::is_type_diagnostic_item;
declare_clippy_lint! {
@ -326,6 +326,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
if let ExprKind::Call(fun, args) = e.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind
&& matches!(method.ident.name, sym::new | sym::with_capacity)
&& let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind
&& let Some(ty_did) = ty_path.res.opt_def_id()
{
@ -333,10 +334,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
return;
}
if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
if method.ident.name == sym::new {
match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) {
(Some(sym::HashMap), sym::new) => {
self.suggestions.insert(e.span, "HashMap::default()".to_string());
} else if method.ident.name.as_str() == "with_capacity" {
},
(Some(sym::HashMap), sym::with_capacity) => {
self.suggestions.insert(
e.span,
format!(
@ -344,11 +346,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
snippet(self.cx, args[0].span, "capacity"),
),
);
}
} else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
if method.ident.name == sym::new {
},
(Some(sym::HashSet), sym::new) => {
self.suggestions.insert(e.span, "HashSet::default()".to_string());
} else if method.ident.name.as_str() == "with_capacity" {
},
(Some(sym::HashSet), sym::with_capacity) => {
self.suggestions.insert(
e.span,
format!(
@ -356,7 +358,8 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
snippet(self.cx, args[0].span, "capacity"),
),
);
}
},
_ => {},
}
}

View file

@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::higher;
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
use clippy_utils::{higher, sym};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@ -156,7 +155,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
.and(cap);
}
}
if method.ident.name.as_str() == "flat_map"
if method.ident.name == sym::flat_map
&& args.len() == 1
&& let ExprKind::Closure(&Closure { body, .. }) = args[0].kind
{
@ -224,7 +223,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
return MaybeInfinite.and(is_infinite(cx, receiver));
}
}
if method.ident.name.as_str() == "last" && args.is_empty() {
if method.ident.name == sym::last && args.is_empty() {
let not_double_ended = cx
.tcx
.get_diagnostic_item(sym::DoubleEndedIterator)
@ -232,7 +231,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
if not_double_ended {
return is_infinite(cx, receiver);
}
} else if method.ident.name.as_str() == "collect" {
} else if method.ident.name == sym::collect {
let ty = cx.typeck_results().expr_ty(expr);
if matches!(
get_type_diagnostic_name(cx, ty),

View file

@ -1,14 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::get_parent_as_impl;
use clippy_utils::source::snippet;
use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection};
use clippy_utils::{get_parent_as_impl, sym};
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{self, Ty};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -141,7 +140,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some()
})
&& let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
if item.ident.name.as_str() == "IntoIter" {
if item.ident.name == sym::IntoIter {
Some(cx.tcx.hir_impl_item(item.id).expect_type().span)
} else {
None

View file

@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
use clippy_utils::source::{SpanRangeExt, snippet_with_context};
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
use clippy_utils::ty::implements_trait;
use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym};
use clippy_utils::{
fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym,
};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@ -533,9 +535,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
// check if we are in an is_empty() method
if let Some(name) = get_item_name(cx, method)
&& name.as_str() == "is_empty"
{
if parent_item_name(cx, method) == Some(sym::is_empty) {
return;
}

View file

@ -729,6 +729,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit));
store.register_late_pass(|_| Box::new(returns::Return));
store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf)));
store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));

View file

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{msrvs, path_to_local, std_or_core};
use clippy_utils::{msrvs, path_to_local, std_or_core, sym};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@ -11,7 +11,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::SyntaxContext;
use rustc_span::symbol::sym;
/// Detects for loop pushing the same item into a Vec
pub(super) fn check<'tcx>(
@ -187,8 +186,8 @@ fn get_vec_push<'tcx>(
// Extract method being called and figure out the parameters for the method call
&& let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
// Check that the method being called is push() on a Vec
&& path.ident.name == sym::push
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
&& path.ident.name.as_str() == "push"
{
return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
}

View file

@ -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::sugg::{Sugg, has_enclosing_paren};
use clippy_utils::{SpanlessEq, sym};
use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
@ -199,9 +199,9 @@ fn build_suggestion(
} else {
format!("{dividend_sugg_str}{type_suffix}")
};
let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability);
let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})");
let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0);
span_lint_and_sugg(
cx,

View file

@ -3,12 +3,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::visitors::{is_local_used, local_used_once};
use clippy_utils::{is_trait_method, path_to_local_id};
use clippy_utils::{is_trait_method, path_to_local_id, sym};
use rustc_errors::Applicability;
use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -66,7 +65,7 @@ impl LateLintPass<'_> for ManualHashOne {
&& let Some(init) = local.init
&& !init.span.from_expansion()
&& let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
&& seg.ident.name.as_str() == "build_hasher"
&& seg.ident.name == sym::build_hasher
&& let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id)
&& let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id)
@ -94,7 +93,7 @@ impl LateLintPass<'_> for ManualHashOne {
&& let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id)
&& !finish_expr.span.from_expansion()
&& let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
&& seg.ident.name.as_str() == "finish"
&& seg.ident.name == sym::finish
&& self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE)
{

View file

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym};
use rustc_ast::LitKind::{Byte, Char};
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind,
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym};
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
check_is_ascii(cx, macro_call.span, recv, &range, None);
}
} else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
&& path.ident.name.as_str() == "contains"
&& path.ident.name == sym::contains
&& let Some(higher::Range {
start: Some(start),
end: Some(end),

View file

@ -1,14 +1,14 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::msrvs::Msrv;
use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs};
use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@ -76,7 +76,7 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
}
},
ExprKind::MethodCall(seg, callee, [], _) => {
if seg.ident.name.as_str() == "unwrap_or_default" {
if seg.ident.name == sym::unwrap_or_default {
check_map(cx, callee, span, self.msrv);
}
},

View file

@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait};
use clippy_utils::{is_mutable, is_trait_method, path_to_local};
use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym};
use rustc_errors::Applicability;
use rustc_hir::{Expr, Node, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty::Instance;
use rustc_span::{Span, sym};
use rustc_span::Span;
use super::DOUBLE_ENDED_ITERATOR_LAST;
@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
&& let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
// find the provided definition of Iterator::last
&& let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last")
&& let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name() == sym::last)
// if the resolved method is the same as the provided definition
&& fn_def.def_id() == last_def.def_id
&& let self_ty = cx.typeck_results().expr_ty(self_expr)

View file

@ -233,12 +233,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
// the latter only calls `effect` once
let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" {
if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some {
Some(Self::IsSome {
receiver,
side_effect_expr_span,
})
} else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" {
} else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok {
Some(Self::IsOk {
receiver,
side_effect_expr_span,

View file

@ -4370,11 +4370,10 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
///
/// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead.
/// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using
/// the `?` operator instead.
///
/// ### Why is this bad?
///
/// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`.
/// This can be replaced with the `?` operator, which is more concise and idiomatic.
///

View file

@ -9,7 +9,7 @@ use super::utils::get_last_chain_binding_hir_id;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::paths::CHAR_IS_ASCII;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
use clippy_utils::{match_def_path, path_to_local_id, peel_blocks, sym};
fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
while let ExprKind::AddrOf(_, _, e) = expr.kind {
@ -32,7 +32,7 @@ fn handle_expr(
// If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
// `is_ascii`, then only `.all()` should warn.
if revert != is_all
&& method.ident.name.as_str() == "is_ascii"
&& method.ident.name == sym::is_ascii
&& path_to_local_id(receiver, first_param)
&& let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
&& *char_arg_ty.kind() == ty::Char
@ -102,7 +102,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
&& let body = cx.tcx.hir_body(body)
&& let Some(first_param) = body.params.first()
&& let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind
&& method.ident.name.as_str() == "chars"
&& method.ident.name == sym::chars
&& let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs()
&& *str_ty.kind() == ty::Str
{

View file

@ -9,7 +9,7 @@ use clippy_utils::ty::{
};
use clippy_utils::{
CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local,
path_to_local_id,
path_to_local_id, sym,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, MultiSpan};
@ -20,8 +20,8 @@ use rustc_hir::{
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
use rustc_span::Span;
use rustc_span::symbol::Ident;
use rustc_span::{Span, sym};
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
@ -339,7 +339,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
// Check function calls on our collection
if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
if args.is_empty()
&& method_name.ident.name.as_str() == "collect"
&& method_name.ident.name == sym::collect
&& is_trait_method(self.cx, expr, sym::Iterator)
{
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));

View file

@ -1,17 +1,16 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, sym};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
use rustc_span::sym;
use super::READ_LINE_WITHOUT_TRIM;
@ -44,7 +43,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
if let Some(parent) = get_parent_expr(cx, expr) {
let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind {
if args.is_empty()
&& segment.ident.name.as_str() == "parse"
&& segment.ident.name == sym::parse
&& let parse_result_ty = cx.typeck_results().expr_ty(parent)
&& is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
&& let ty::Adt(_, substs) = parse_result_ty.kind()
@ -58,7 +57,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
"calling `.parse()` on a string without trimming the trailing newline character",
"checking",
))
} else if segment.ident.name.as_str() == "ends_with"
} else if segment.ident.name == sym::ends_with
&& recv.span == expr.span
&& let [arg] = args
&& expr_is_string_literal_without_trailing_newline(arg)

View file

@ -55,7 +55,6 @@ pub(super) fn check<'tcx>(
None => &body_snip,
};
let msg = "use the question mark operator instead of an `and_then` call";
let sugg = format!(
"let {} = {}?;\n{}",
arg_snip,
@ -63,5 +62,13 @@ pub(super) fn check<'tcx>(
reindent_multiline(inner, false, indent_of(cx, expr.span))
);
span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability);
span_lint_and_sugg(
cx,
RETURN_AND_THEN,
expr.span,
"use the `?` operator instead of an `and_then` call",
"try",
sugg,
applicability,
);
}

View file

@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::sym;
use clippy_utils::visitors::is_const_evaluatable;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@ -19,7 +20,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'
&& !is_const_evaluatable(cx, trim_recv)
&& let ExprKind::Lit(split_lit) = split_arg.kind
&& (matches!(split_lit.node, LitKind::Char('\n'))
|| matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n")))
|| matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _)))
{
let mut app = Applicability::MaybeIncorrect;
span_lint_and_sugg(

View file

@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_copy;
use clippy_utils::usage::mutated_variables;
use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id};
use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym};
use core::ops::ControlFlow;
use rustc_hir as hir;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::sym;
use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
@ -95,7 +94,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
(true, true)
},
hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
if segment.ident.name.as_str() == "then_some"
if segment.ident.name == sym::then_some
&& cx.typeck_results().expr_ty(recv).is_bool()
&& path_to_local_id(arg, arg_id)
{

View file

@ -7,7 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_
use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{
fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs,
return_ty,
return_ty, sym,
};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{
self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
};
use rustc_span::{Symbol, sym};
use rustc_span::Symbol;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{Obligation, ObligationCause};
@ -312,8 +312,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>,
/// call of a `to_owned`-like function is unnecessary.
fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
if let Some(parent) = get_parent_expr(cx, expr)
&& let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent)
&& fn_name.as_str() == "split"
&& let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent)
&& let Some(receiver_snippet) = receiver.span.get_source_text(cx)
&& let Some(arg_snippet) = argument_expr.span.get_source_text(cx)
{
@ -614,8 +613,7 @@ fn has_lifetime(ty: Ty<'_>) -> bool {
/// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
(method_name.as_str() == "cloned" || method_name.as_str() == "copied")
&& is_diag_trait_item(cx, method_def_id, sym::Iterator)
matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator)
}
/// Returns true if the named method can be used to convert the receiver to its "owned"
@ -628,7 +626,7 @@ fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name:
/// Returns true if the named method is `Cow::into_owned`.
fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow)
}
/// Returns true if the named method is `ToString::to_string` and it's called on a type that

View file

@ -1,10 +1,9 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_trait_method;
use clippy_utils::{is_trait_method, sym};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
use std::cmp::Ordering::{Equal, Greater, Less};
declare_clippy_lint! {
@ -79,12 +78,10 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM
},
ExprKind::MethodCall(path, receiver, args @ [_], _) => {
if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) {
if path.ident.name.as_str() == "max" {
fetch_const(cx, Some(receiver), args, MinMax::Max)
} else if path.ident.name.as_str() == "min" {
fetch_const(cx, Some(receiver), args, MinMax::Min)
} else {
None
match path.ident.name {
sym::max => fetch_const(cx, Some(receiver), args, MinMax::Max),
sym::min => fetch_const(cx, Some(receiver), args, MinMax::Min),
_ => None,
}
} else {
None

View file

@ -1,9 +1,9 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_path_lang_item;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{Visitable, for_each_expr};
use clippy_utils::{is_path_lang_item, sym};
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
@ -13,7 +13,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::declare_lint_pass;
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@ -116,7 +116,7 @@ fn should_lint<'tcx>(
if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) {
has_debug_struct = true;
} else if path.ident.name.as_str() == "finish_non_exhaustive"
} else if path.ident.name == sym::finish_non_exhaustive
&& is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
{
has_finish_non_exhaustive = true;

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym};
use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
@ -136,7 +136,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> {
fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
if let Some(macro_call) = root_macro_call_first_node(self.cx, e)
&& self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo"
&& self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
{
return;
}

View file

@ -3,12 +3,12 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::{Span, sym};
use rustc_span::Span;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::has_iter_method;
use clippy_utils::{is_trait_method, sym};
declare_clippy_lint! {
/// ### What it does
@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
iter_recv.kind,
ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
)
&& method_name.ident.name.as_str() == "for_each"
&& method_name.ident.name == sym::for_each
&& is_trait_method(cx, expr, sym::Iterator)
// Checks the type of the `iter` method receiver is NOT a user defined type.
&& has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()

View file

@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::path_res;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
@ -9,52 +8,38 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Suggests alternatives for useless applications of `?` in terminating expressions
/// Suggests replacing `Ok(x?)` or `Some(x?)` with `x` in return positions where the `?` operator
/// is not needed to convert the type of `x`.
///
/// ### Why is this bad?
/// There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
///
/// ### Example
/// ```no_run
/// struct TO {
/// magic: Option<usize>,
/// # use std::num::ParseIntError;
/// fn f(s: &str) -> Option<usize> {
/// Some(s.find('x')?)
/// }
///
/// fn f(to: TO) -> Option<usize> {
/// Some(to.magic?)
/// fn g(s: &str) -> Result<usize, ParseIntError> {
/// Ok(s.parse()?)
/// }
///
/// struct TR {
/// magic: Result<usize, bool>,
/// }
///
/// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
/// tr.and_then(|t| Ok(t.magic?))
/// }
///
/// ```
/// Use instead:
/// ```no_run
/// struct TO {
/// magic: Option<usize>,
/// # use std::num::ParseIntError;
/// fn f(s: &str) -> Option<usize> {
/// s.find('x')
/// }
///
/// fn f(to: TO) -> Option<usize> {
/// to.magic
/// }
///
/// struct TR {
/// magic: Result<usize, bool>,
/// }
///
/// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
/// tr.and_then(|t| t.magic)
/// fn g(s: &str) -> Result<usize, ParseIntError> {
/// s.parse()
/// }
/// ```
#[clippy::version = "1.51.0"]
pub NEEDLESS_QUESTION_MARK,
complexity,
"Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
"using `Ok(x?)` or `Some(x?)` where `x` would be equivalent"
}
declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
@ -111,10 +96,10 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(path, [arg]) = expr.kind
&& let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path)
&& let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
&& let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
"Some()"
&& let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
"Some"
} else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) {
"Ok()"
"Ok"
} else {
return;
}
@ -126,14 +111,25 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
&& let inner_ty = cx.typeck_results().expr_ty(inner_expr)
&& expr_ty == inner_ty
{
span_lint_and_sugg(
span_lint_hir_and_then(
cx,
NEEDLESS_QUESTION_MARK,
expr.hir_id,
expr.span,
"question mark operator is useless here",
format!("try removing question mark and `{sugg_remove}`"),
format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
Applicability::MachineApplicable,
format!("enclosing `{variant}` and `?` operator are unneeded"),
|diag| {
diag.multipart_suggestion(
format!("remove the enclosing `{variant}` and `?` operator"),
vec![
(expr.span.until(inner_expr.span), String::new()),
(
inner_expr.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
String::new(),
),
],
Applicability::MachineApplicable,
);
},
);
}
}

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
use clippy_utils::sym;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
match &expr.kind {
ExprKind::MethodCall(path, func, [param], _) => {
if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def()
&& ((path.ident.name.as_str() == "mode"
&& ((path.ident.name == sym::mode
&& matches!(
cx.tcx.get_diagnostic_name(adt.did()),
Some(sym::FsOpenOptions | sym::DirBuilder)
))
|| (path.ident.name.as_str() == "set_mode"
|| (path.ident.name == sym::set_mode
&& cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
&& let ExprKind::Lit(_) = param.kind
&& param.span.eq_ctxt(expr.span)

View file

@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::sym;
use rustc_ast::ast::BinOpKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@ -72,7 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit
&& let ExprKind::Path(qpath) = &func.kind
&& let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
&& let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind
&& rcv_path.ident.name.as_str() == "get"
&& rcv_path.ident.name == sym::get
{
let fn_name = cx.tcx.item_name(def_id);
let target_ty = cx.typeck_results().expr_ty(expr);

View file

@ -1,7 +1,7 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::get_item_name;
use clippy_utils::sugg::Sugg;
use clippy_utils::{parent_item_name, sym};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::LateContext;
@ -34,7 +34,7 @@ pub(crate) fn check<'tcx>(
return;
}
if let Some(name) = get_item_name(cx, expr) {
if let Some(name) = parent_item_name(cx, expr) {
let name = name.as_str();
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") {
return;
@ -106,7 +106,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}
if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind
&& method_name.ident.name.as_str() == "signum"
&& method_name.ident.name == sym::signum
// Check that the receiver of the signum() is a float (expressions[0] is the receiver of
// the method call)
{

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sym;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
&& let ExprKind::Lit(lit) = &arg.kind
&& LitKind::Bool(false) == lit.node
&& path.ident.name.as_str() == "set_readonly"
&& path.ident.name == sym::set_readonly
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
{
span_lint_and_then(

View file

@ -743,9 +743,9 @@ fn check_ptr_eq<'tcx>(
}
// Remove one level of usize conversion if any
let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
(Some(lhs), Some(rhs)) => (lhs, rhs),
_ => (left, right),
let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
(Some(lhs), Some(rhs)) => (lhs, rhs, true),
_ => (left, right, false),
};
// This lint concerns raw pointers
@ -754,7 +754,12 @@ fn check_ptr_eq<'tcx>(
return;
}
let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) =
(peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
if !(usize_peeled || left_casts_peeled || right_casts_peeled) {
return;
}
let mut app = Applicability::MachineApplicable;
let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
@ -787,8 +792,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
}
}
// Peel raw casts if the remaining expression can be coerced to it
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been
// peeled or not.
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
if !expr.span.from_expansion()
&& let ExprKind::Cast(inner, _) = expr.kind
&& let ty::RawPtr(target_ty, _) = expr_ty.kind()
@ -796,8 +802,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty:
&& let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
&& target_ty == inner_target_ty
{
peel_raw_casts(cx, inner, inner_ty)
(peel_raw_casts(cx, inner, inner_ty).0, true)
} else {
expr
(expr, false)
}
}

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::sym;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
use std::fmt;
declare_clippy_lint! {
@ -97,7 +97,7 @@ fn expr_as_ptr_offset_call<'tcx>(
if path_segment.ident.name == sym::offset {
return Some((arg_0, arg_1, Method::Offset));
}
if path_segment.ident.name.as_str() == "wrapping_offset" {
if path_segment.ident.name == sym::wrapping_offset {
return Some((arg_0, arg_1, Method::WrappingOffset));
}
}

View file

@ -10,7 +10,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{
eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
span_contains_cfg, span_contains_comment,
span_contains_cfg, span_contains_comment, sym,
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@ -22,15 +22,14 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
/// ### What it does
/// Checks for expressions that could be replaced by the question mark operator.
/// Checks for expressions that could be replaced by the `?` operator.
///
/// ### Why is this bad?
/// Question mark usage is more idiomatic.
/// Using the `?` operator is shorter and more idiomatic.
///
/// ### Example
/// ```ignore
@ -47,7 +46,7 @@ declare_clippy_lint! {
#[clippy::version = "pre 1.29.0"]
pub QUESTION_MARK,
style,
"checks for expressions that could be replaced by the question mark operator"
"checks for expressions that could be replaced by the `?` operator"
}
pub struct QuestionMark {
@ -207,8 +206,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
is_type_diagnostic_item(cx, caller_ty, smbl)
&& expr_return_none_or_err(smbl, cx, if_then, caller, None)
&& match smbl {
sym::Option => call_sym.as_str() == "is_none",
sym::Result => call_sym.as_str() == "is_err",
sym::Option => call_sym == sym::is_none,
sym::Result => call_sym == sym::is_err,
_ => false,
}
},
@ -280,7 +279,7 @@ fn expr_return_none_or_err(
/// }
/// ```
///
/// If it matches, it will suggest to use the question mark operator instead
/// If it matches, it will suggest to use the `?` operator instead
fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr)
&& !is_else_clause(cx.tcx, expr)

View file

@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks for expressions that use the question mark operator and rejects them.
/// Checks for expressions that use the `?` operator and rejects them.
///
/// ### Why restrict this?
/// Sometimes code wants to avoid the question mark operator because for instance a local
/// Sometimes code wants to avoid the `?` operator because for instance a local
/// block requires a macro to re-throw errors to attach additional information to the
/// error.
///
@ -27,7 +27,7 @@ declare_clippy_lint! {
#[clippy::version = "1.69.0"]
pub QUESTION_MARK_USED,
restriction,
"complains if the question mark operator is used"
"checks if the `?` operator is used"
}
declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
@ -40,15 +40,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
}
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
span_lint_and_then(
cx,
QUESTION_MARK_USED,
expr.span,
"question mark operator was used",
|diag| {
diag.help("consider using a custom macro or match expression");
},
);
span_lint_and_then(cx, QUESTION_MARK_USED, expr.span, "the `?` operator was used", |diag| {
diag.help("consider using a custom macro or match expression");
});
}
}
}

View file

@ -3,14 +3,13 @@ use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::sugg::Sugg;
use clippy_utils::{
SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id,
span_contains_comment,
span_contains_comment, sym,
};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@ -248,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
if self.initialization_found
&& let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind
&& path_to_local_id(self_arg, self.vec_alloc.local_id)
&& path.ident.name.as_str() == "extend"
&& path.ident.name == sym::extend
&& self.is_repeat_take(extend_arg)
{
self.slow_expression = Some(InitializationType::Extend(expr));
@ -260,7 +259,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
if self.initialization_found
&& let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
&& path_to_local_id(self_arg, self.vec_alloc.local_id)
&& path.ident.name.as_str() == "resize"
&& path.ident.name == sym::resize
// Check that is filled with 0
&& is_integer_literal(fill_arg, 0)
{
@ -282,7 +281,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind
&& take_path.ident.name.as_str() == "take"
&& take_path.ident.name == sym::take
// Check that take is applied to `repeat(0)`
&& self.is_repeat_zero(recv)
{

View file

@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
if !e.span.in_external_macro(cx.sess().source_map())
&& let ExprKind::MethodCall(path, receiver, ..) = &e.kind
&& path.ident.name.as_str() == "as_bytes"
&& path.ident.name == sym::as_bytes
&& let ExprKind::Lit(lit) = &receiver.kind
&& let LitKind::Str(lit_content, _) = &lit.node
{
@ -332,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
}
if let ExprKind::MethodCall(path, recv, [], _) = &e.kind
&& path.ident.name.as_str() == "into_bytes"
&& path.ident.name == sym::into_bytes
&& let ExprKind::MethodCall(path, recv, [], _) = &recv.kind
&& matches!(path.ident.name.as_str(), "to_owned" | "to_string")
&& let ExprKind::Lit(lit) = &recv.kind
@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
let tyckres = cx.typeck_results();
if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind
&& path.ident.name.as_str() == "split_whitespace"
&& path.ident.name == sym::split_whitespace
&& let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id)
&& cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id)
&& let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::match_def_path;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{match_def_path, sym};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
@ -38,11 +38,11 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind
&& is_some_path.ident.name.as_str() == "is_some"
&& is_some_path.ident.name == sym::is_some
{
let match_result = match &to_digit_expr.kind {
hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
if to_digits_path.ident.name.as_str() == "to_digit"
if to_digits_path.ident.name == sym::to_digit
&& let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg)
&& *char_arg_ty.kind() == ty::Char
{

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_normalizable;
use clippy_utils::{eq_expr_value, path_to_local};
use clippy_utils::{eq_expr_value, path_to_local, sym};
use rustc_abi::WrappingRange;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Node};
@ -43,7 +43,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_
binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs)
},
ExprKind::MethodCall(path, receiver, [arg], _)
if path.ident.name.as_str() == "contains"
if path.ident.name == sym::contains
// ... `contains` called on some kind of range
&& let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
&& let lang_items = cx.tcx.lang_items()
@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(
if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr)
&& let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind
&& cx.typeck_results().expr_ty(receiver).is_bool()
&& path.ident.name.as_str() == "then_some"
&& path.ident.name == sym::then_some
&& is_local_with_projections(transmutable)
&& binops_with_local(cx, transmutable, receiver)
&& is_normalizable(cx, cx.param_env, from_ty)

View file

@ -19,61 +19,58 @@ pub(super) fn check<'tcx>(
def_id: DefId,
box_size_threshold: u64,
) -> bool {
if cx.tcx.is_diagnostic_item(sym::Vec, def_id) {
if let Some(last) = last_path_segment(qpath).args
// Get the _ part of Vec<_>
&& let Some(GenericArg::Type(ty)) = last.args.first()
// extract allocator from the Vec for later
&& let vec_alloc_ty = last.args.get(1)
// ty is now _ at this point
&& let TyKind::Path(ref ty_qpath) = ty.kind
&& let res = cx.qpath_res(ty_qpath, ty.hir_id)
&& let Some(def_id) = res.opt_def_id()
&& Some(def_id) == cx.tcx.lang_items().owned_box()
// At this point, we know ty is Box<T>, now get T
&& let Some(last) = last_path_segment(ty_qpath).args
&& let Some(GenericArg::Type(boxed_ty)) = last.args.first()
// extract allocator from the Box for later
&& let boxed_alloc_ty = last.args.get(1)
// we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
&& let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
&& !ty_ty.has_escaping_bound_vars()
&& ty_ty.is_sized(cx.tcx, cx.typing_env())
&& let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
&& ty_ty_size < box_size_threshold
// https://github.com/rust-lang/rust-clippy/issues/7114
&& match (vec_alloc_ty, boxed_alloc_ty) {
(None, None) => true,
// this is in the event that we have something like
// Vec<_, Global>, in which case is equivalent to
// Vec<_>
(None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
if let TyKind::Path(path) = inner.kind
&& let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did)
} else {
false
}
},
(Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
// we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
_ => false
}
{
span_lint_and_sugg(
cx,
VEC_BOX,
hir_ty.span,
"`Vec<T>` is already on the heap, the boxing is unnecessary",
"try",
format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
Applicability::Unspecified,
);
true
} else {
false
if cx.tcx.is_diagnostic_item(sym::Vec, def_id)
&& let Some(last) = last_path_segment(qpath).args
// Get the _ part of Vec<_>
&& let Some(GenericArg::Type(ty)) = last.args.first()
// extract allocator from the Vec for later
&& let vec_alloc_ty = last.args.get(1)
// ty is now _ at this point
&& let TyKind::Path(ref ty_qpath) = ty.kind
&& let res = cx.qpath_res(ty_qpath, ty.hir_id)
&& let Some(def_id) = res.opt_def_id()
&& Some(def_id) == cx.tcx.lang_items().owned_box()
// At this point, we know ty is Box<T>, now get T
&& let Some(last) = last_path_segment(ty_qpath).args
&& let Some(GenericArg::Type(boxed_ty)) = last.args.first()
// extract allocator from the Box for later
&& let boxed_alloc_ty = last.args.get(1)
// we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
&& let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
&& !ty_ty.has_escaping_bound_vars()
&& ty_ty.is_sized(cx.tcx, cx.typing_env())
&& let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
&& ty_ty_size < box_size_threshold
// https://github.com/rust-lang/rust-clippy/issues/7114
&& match (vec_alloc_ty, boxed_alloc_ty) {
(None, None) => true,
// this is in the event that we have something like
// Vec<_, Global>, in which case is equivalent to
// Vec<_>
(None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
if let TyKind::Path(path) = inner.kind
&& let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did)
} else {
false
}
},
(Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
// we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
_ => false
}
{
span_lint_and_sugg(
cx,
VEC_BOX,
hir_ty.span,
"`Vec<T>` is already on the heap, the boxing is unnecessary",
"try",
format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
Applicability::Unspecified,
);
true
} else {
false
}

View file

@ -1,12 +1,12 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while};
use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym};
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_span::{Span, sym};
use rustc_span::Span;
// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
declare_clippy_lint! {
@ -187,7 +187,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
&& path.ident.name.as_str() == "reserve"
&& path.ident.name == sym::reserve
}
/// Returns self if the expression is `Vec::set_len()`
@ -209,7 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
ExprKind::MethodCall(path, self_expr, [arg], _) => {
let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
if is_type_diagnostic_item(cx, self_type, sym::Vec)
&& path.ident.name.as_str() == "set_len"
&& path.ident.name == sym::set_len
&& !is_integer_literal(arg, 0)
{
Some((self_expr, expr.span))

View file

@ -1,6 +1,7 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::sym;
use clippy_utils::visitors::is_local_used;
use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
@ -61,12 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
let contains_todo = |cx, body: &'_ Body<'_>| -> bool {
clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| {
if let Some(macro_call) = root_macro_call_first_node(cx, e) {
if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
if let Some(macro_call) = root_macro_call_first_node(cx, e)
&& cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
{
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}

View file

@ -1,11 +1,18 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{SpanRangeExt, position_before_rarrow};
use rustc_ast::visit::FnKind;
use rustc_ast::{ClosureBinder, ast};
use clippy_utils::{is_never_expr, is_unit_expr};
use rustc_ast::{Block, StmtKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term,
Ty, TyKind,
};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Span};
use rustc_span::edition::Edition;
use rustc_span::{BytePos, Span, sym};
declare_clippy_lint! {
/// ### What it does
@ -34,27 +41,89 @@ declare_clippy_lint! {
declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]);
impl EarlyLintPass for UnusedUnit {
fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
if let ast::FnRetTy::Ty(ref ty) = kind.decl().output
&& let ast::TyKind::Tup(ref vals) = ty.kind
&& vals.is_empty()
&& !ty.span.from_expansion()
&& get_def(span) == get_def(ty.span)
impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx FnDecl<'tcx>,
body: &'tcx Body<'tcx>,
span: Span,
def_id: LocalDefId,
) {
if let FnRetTy::Return(hir_ty) = decl.output
&& is_unit_ty(hir_ty)
&& !hir_ty.span.from_expansion()
&& get_def(span) == get_def(hir_ty.span)
{
// implicit types in closure signatures are forbidden when `for<...>` is present
if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind {
if let FnKind::Closure = kind
&& let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id)
&& let ExprKind::Closure(closure) = expr.kind
&& !closure.bound_generic_params.is_empty()
{
return;
}
lint_unneeded_unit_return(cx, ty, span);
// unit never type fallback is no longer supported since Rust 2024. For more information,
// see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
if cx.tcx.sess.edition() >= Edition::Edition2024
&& let ExprKind::Block(block, _) = body.value.kind
&& let Some(expr) = block.expr
&& is_never_expr(cx, expr).is_some()
{
return;
}
lint_unneeded_unit_return(cx, hir_ty.span, span);
}
}
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
if let Some(stmt) = block.stmts.last()
&& let ast::StmtKind::Expr(ref expr) = stmt.kind
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::Ret(Some(expr)) | ExprKind::Break(_, Some(expr)) = expr.kind
&& is_unit_expr(expr)
&& !expr.span.from_expansion()
{
span_lint_and_sugg(
cx,
UNUSED_UNIT,
expr.span,
"unneeded `()`",
"remove the `()`",
String::new(),
Applicability::MachineApplicable,
);
}
}
fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) {
let segments = &poly.trait_ref.path.segments;
if segments.len() == 1
&& ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
&& let Some(args) = segments[0].args
&& args.parenthesized == GenericArgsParentheses::ParenSugar
&& let constraints = &args.constraints
&& constraints.len() == 1
&& constraints[0].ident.name == sym::Output
&& let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind
&& args.span_ext.hi() != poly.span.hi()
&& !hir_ty.span.from_expansion()
&& is_unit_ty(hir_ty)
{
lint_unneeded_unit_return(cx, hir_ty.span, poly.span);
}
}
}
impl EarlyLintPass for UnusedUnit {
/// Check for unit expressions in blocks. This is left in the early pass because some macros
/// expand its inputs as-is, making it invisible to the late pass. See #4076.
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
if let Some(stmt) = block.stmts.last()
&& let StmtKind::Expr(expr) = &stmt.kind
&& let rustc_ast::ExprKind::Tup(inner) = &expr.kind
&& inner.is_empty()
&& let ctxt = block.span.ctxt()
&& stmt.span.ctxt() == ctxt
&& expr.span.ctxt() == ctxt
@ -72,39 +141,10 @@ impl EarlyLintPass for UnusedUnit {
);
}
}
}
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
match e.kind {
ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
if is_unit_expr(expr) && !expr.span.from_expansion() {
span_lint_and_sugg(
cx,
UNUSED_UNIT,
expr.span,
"unneeded `()`",
"remove the `()`",
String::new(),
Applicability::MachineApplicable,
);
}
},
_ => (),
}
}
fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
let segments = &poly.trait_ref.path.segments;
if segments.len() == 1
&& ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
&& let Some(args) = &segments[0].args
&& let ast::GenericArgs::Parenthesized(generic_args) = &**args
&& let ast::FnRetTy::Ty(ty) = &generic_args.output
&& ty.kind.is_unit()
{
lint_unneeded_unit_return(cx, ty, generic_args.span);
}
}
fn is_unit_ty(ty: &Ty<'_>) -> bool {
matches!(ty.kind, TyKind::Tup([]))
}
// get the def site
@ -117,24 +157,15 @@ fn get_def(span: Span) -> Option<Span> {
}
}
// is this expr a `()` unit?
fn is_unit_expr(expr: &ast::Expr) -> bool {
if let ast::ExprKind::Tup(ref vals) = expr.kind {
vals.is_empty()
} else {
false
}
}
fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) {
let (ret_span, appl) =
span.with_hi(ty.span.hi())
span.with_hi(ty_span.hi())
.get_source_text(cx)
.map_or((ty.span, Applicability::MaybeIncorrect), |src| {
position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
.map_or((ty_span, Applicability::MaybeIncorrect), |src| {
position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| {
(
#[expect(clippy::cast_possible_truncation)]
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)),
Applicability::MachineApplicable,
)
})

View file

@ -208,7 +208,7 @@ fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
&& let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind
{
path.ident.name.as_str() == "as_mut"
path.ident.name == sym::as_mut
} else {
false
}
@ -278,7 +278,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt
if let ExprKind::MethodCall(path, recv, [], _) = expr.kind {
if path.ident.name == sym::as_ref {
(recv, Some(AsRefKind::AsRef))
} else if path.ident.name.as_str() == "as_mut" {
} else if path.ident.name == sym::as_mut {
(recv, Some(AsRefKind::AsMut))
} else {
(expr, None)

View file

@ -1,8 +1,8 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::is_in_test;
use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node};
use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma};
use clippy_utils::{is_in_test, sym};
use rustc_ast::token::LitKind;
use rustc_ast::{
FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
@ -12,7 +12,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Span, sym};
use rustc_span::{BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@ -359,7 +359,7 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
}
fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else {
let Some(&FormatArgsPiece::Literal(last)) = format_args.template.last() else {
return;
};
@ -401,7 +401,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
return;
};
if format_args.template.len() == 1 && last.as_str() == "\n" {
if format_args.template.len() == 1 && last == sym::LF {
// print!("\n"), write!(f, "\n")
diag.multipart_suggestion(
@ -427,9 +427,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
}
fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..]
&& literal.as_str() == "\n"
{
if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] {
let mut span = format_args.span;
let lint = if name == "writeln" {

View file

@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id};
use rustc_ast::Mutability;
use rustc_ast::visit::visit_opt;
use rustc_errors::Applicability;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
let mut vis = WaitFinder {
cx,
local_id,
body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id),
state: VisitorState::WalkUpToLocal,
early_return: None,
missing_wait_branch: None,
@ -129,6 +131,7 @@ struct MaybeWait(Span);
struct WaitFinder<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
local_id: HirId,
body_id: LocalDefId,
state: VisitorState,
early_return: Option<Span>,
// When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help
@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
}
} else {
match ex.kind {
ExprKind::Ret(e) => {
ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => {
visit_opt!(self, visit_expr, e);
if self.early_return.is_none() {
self.early_return = Some(ex.span);

View file

@ -2,6 +2,7 @@
#![allow(
clippy::missing_docs_in_private_items,
clippy::must_use_candidate,
clippy::symbol_as_str,
rustc::diagnostic_outside_of_impl,
rustc::untranslatable_diagnostic
)]
@ -31,12 +32,12 @@ extern crate rustc_span;
mod almost_standard_lint_formulation;
mod collapsible_calls;
mod interning_literals;
mod invalid_paths;
mod lint_without_lint_pass;
mod msrv_attr_impl;
mod outer_expn_data_pass;
mod produce_ice;
mod symbols;
mod unnecessary_def_path;
mod unsorted_clippy_utils_paths;
@ -45,7 +46,6 @@ use rustc_lint::{Lint, LintStore};
static LINTS: &[&Lint] = &[
almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION,
collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
interning_literals::INTERNING_LITERALS,
invalid_paths::INVALID_PATHS,
lint_without_lint_pass::DEFAULT_LINT,
lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
@ -54,6 +54,8 @@ static LINTS: &[&Lint] = &[
msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
produce_ice::PRODUCE_ICE,
symbols::INTERNING_LITERALS,
symbols::SYMBOL_AS_STR,
unnecessary_def_path::UNNECESSARY_DEF_PATH,
unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS,
];
@ -65,7 +67,7 @@ pub fn register_lints(store: &mut LintStore) {
store.register_early_pass(|| Box::new(produce_ice::ProduceIce));
store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls));
store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths));
store.register_late_pass(|_| Box::<interning_literals::InterningDefinedSymbol>::default());
store.register_late_pass(|_| Box::<symbols::Symbols>::default());
store.register_late_pass(|_| Box::<lint_without_lint_pass::LintWithoutLintPass>::default());
store.register_late_pass(|_| Box::<unnecessary_def_path::UnnecessaryDefPath>::default());
store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass));

View file

@ -1,7 +1,7 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::match_type;
use clippy_utils::{def_path_def_ids, paths};
use clippy_utils::{def_path_def_ids, match_def_path, paths};
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@ -11,8 +11,8 @@ use rustc_lint_defs::declare_tool_lint;
use rustc_middle::mir::ConstValue;
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, sym};
declare_tool_lint! {
/// ### What it does
@ -36,15 +36,37 @@ declare_tool_lint! {
report_in_external_macro: true
}
declare_tool_lint! {
/// ### What it does
/// Checks for calls to `Symbol::as_str`
///
/// ### Why is this bad?
/// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs`
///
/// ### Example
/// ```rust,ignore
/// symbol.as_str() == "foo"
/// ```
///
/// Use instead:
/// ```rust,ignore
/// symbol == sym::foo
/// ```
pub clippy::SYMBOL_AS_STR,
Warn,
"calls to `Symbol::as_str`",
report_in_external_macro: true
}
#[derive(Default)]
pub struct InterningDefinedSymbol {
pub struct Symbols {
// Maps the symbol to the import path
symbol_map: FxHashMap<u32, (&'static str, Symbol)>,
}
impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]);
impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]);
impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
impl<'tcx> LateLintPass<'tcx> for Symbols {
fn check_crate(&mut self, cx: &LateContext<'_>) {
let modules = [
("kw", &paths::KW_MODULE[..]),
@ -77,7 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
if let ExprKind::Call(func, [arg]) = &expr.kind
&& let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
&& cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
&& let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
&& let ExprKind::Lit(lit) = arg.kind
&& let LitKind::Str(name, _) = lit.node
{
span_lint_and_then(
cx,
@ -85,18 +108,62 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
expr.span,
"interning a string literal",
|diag| {
let value = Symbol::intern(&arg).as_u32();
let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) {
("use the preinterned symbol", format!("{prefix}::{name}"))
} else {
(
"add the symbol to `clippy_utils/src/sym.rs` and use it",
format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")),
)
};
let (message, path) = suggestion(&mut self.symbol_map, name);
diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect);
},
);
}
if let ExprKind::Binary(_, lhs, rhs) = expr.kind {
check_binary(cx, lhs, rhs, &mut self.symbol_map);
check_binary(cx, rhs, lhs, &mut self.symbol_map);
}
}
}
fn check_binary(
cx: &LateContext<'_>,
lhs: &Expr<'_>,
rhs: &Expr<'_>,
symbols: &mut FxHashMap<u32, (&'static str, Symbol)>,
) {
if let Some(removal_span) = as_str_span(cx, lhs)
&& let ExprKind::Lit(lit) = rhs.kind
&& let LitKind::Str(name, _) = lit.node
{
span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| {
let (message, path) = suggestion(symbols, name);
diag.multipart_suggestion_verbose(
message,
vec![(removal_span, String::new()), (rhs.span, path)],
Applicability::MachineApplicable,
);
});
}
}
fn suggestion(symbols: &mut FxHashMap<u32, (&'static str, Symbol)>, name: Symbol) -> (&'static str, String) {
if let Some((prefix, name)) = symbols.get(&name.as_u32()) {
("use the preinterned symbol", format!("{prefix}::{name}"))
} else {
(
"add the symbol to `clippy_utils/src/sym.rs` and use it",
format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")),
)
}
}
/// ```ignore
/// symbol.as_str()
/// // ^^^^^^^^
/// ```
fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
if let ExprKind::MethodCall(_, recv, [], _) = expr.kind
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& match_def_path(cx, method_def_id, &paths::SYMBOL_AS_STR)
{
Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi()))
} else {
None
}
}

View file

@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
<!-- begin autogenerated nightly -->
```
nightly-2025-04-22
nightly-2025-05-01
```
<!-- end autogenerated nightly -->

View file

@ -3,14 +3,14 @@
#![deny(clippy::missing_docs_in_private_items)]
use crate::consts::{ConstEvalCtxt, Constant};
use crate::is_expn_of;
use crate::ty::is_type_diagnostic_item;
use crate::{is_expn_of, sym};
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr};
use rustc_lint::LateContext;
use rustc_span::{Span, sym, symbol};
use rustc_span::{Span, symbol};
/// The essential nodes of a desugared for loop as well as the entire span:
/// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`.
@ -474,7 +474,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
return Some(VecInitKind::New);
} else if name.ident.name == symbol::kw::Default {
return Some(VecInitKind::Default);
} else if name.ident.name.as_str() == "with_capacity" {
} else if name.ident.name == sym::with_capacity {
let arg = args.first()?;
return match ConstEvalCtxt::new(cx).eval_simple(arg) {
Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),

View file

@ -1118,8 +1118,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_const_arg(e);
},
TyPatKind::Or(variants) => {
for variant in variants.iter() {
self.hash_ty_pat(variant)
for variant in variants {
self.hash_ty_pat(variant);
}
},
TyPatKind::Err(_) => {},

View file

@ -1412,7 +1412,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
}
/// Gets the name of the item the expression is in, if available.
pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id;
match cx.tcx.hir_node_by_def_id(parent_id) {
Node::Item(item) => item.kind.ident().map(|ident| ident.name),
@ -2088,7 +2088,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
let path = cx.get_def_path(did);
// libc is meant to be used as a flat list of names, but they're all actually defined in different
// modules based on the target platform. Ignore everything but crate name and the item name.
path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name)
path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name)
}
/// Returns the list of condition expressions and the list of blocks in a
@ -3101,7 +3101,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
}
/// Returns whether the given let pattern and else body can be turned into a question mark
/// Returns whether the given let pattern and else body can be turned into the `?` operator
///
/// For this example:
/// ```ignore
@ -3124,8 +3124,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
/// ```
///
/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
/// the question mark operator is applicable here. Callers have to check whether we are in a
/// constant or not.
/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not.
pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
cx: &LateContext<'_>,
pat: &'a Pat<'hir>,

View file

@ -30,33 +30,75 @@ macro_rules! generate {
}
generate! {
abs,
as_bytes,
as_deref_mut,
as_deref,
as_mut,
Binary,
build_hasher,
cargo_clippy: "cargo-clippy",
Cargo_toml: "Cargo.toml",
cast,
chars,
CLIPPY_ARGS,
CLIPPY_CONF_DIR,
clone_into,
cloned,
collect,
contains,
copied,
CRLF: "\r\n",
Current,
ends_with,
exp,
extend,
finish_non_exhaustive,
finish,
flat_map,
for_each,
from_raw,
from_str_radix,
get,
insert,
int_roundings,
into_bytes,
into_owned,
IntoIter,
is_ascii,
is_empty,
is_err,
is_none,
is_ok,
is_some,
last,
LF: "\n",
LowerExp,
LowerHex,
max,
min,
mode,
msrv,
Octal,
or_default,
parse,
push,
regex,
reserve,
resize,
restriction,
rustfmt_skip,
set_len,
set_mode,
set_readonly,
signum,
split_whitespace,
split,
Start,
take,
TBD,
then_some,
to_digit,
to_owned,
unused_extern_crates,
unwrap_err,
@ -66,4 +108,6 @@ generate! {
V4,
V6,
Weak,
with_capacity,
wrapping_offset,
}

View file

@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
channel = "nightly-2025-04-22"
channel = "nightly-2025-05-01"
# end autogenerated nightly
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
profile = "minimal"

View file

@ -0,0 +1,21 @@
#![feature(rustc_private)]
extern crate rustc_span;
use clippy_utils::sym;
use rustc_span::{Symbol, kw};
fn f(s: Symbol) {
s == sym::f32;
//~^ symbol_as_str
s == sym::proc_dash_macro;
//~^ symbol_as_str
s == kw::SelfLower;
//~^ symbol_as_str
s == sym::msrv;
//~^ symbol_as_str
s == sym::Cargo_toml;
//~^ symbol_as_str
sym::get == s;
//~^ symbol_as_str
}

View file

@ -0,0 +1,21 @@
#![feature(rustc_private)]
extern crate rustc_span;
use clippy_utils::sym;
use rustc_span::{Symbol, kw};
fn f(s: Symbol) {
s.as_str() == "f32";
//~^ symbol_as_str
s.as_str() == "proc-macro";
//~^ symbol_as_str
s.as_str() == "self";
//~^ symbol_as_str
s.as_str() == "msrv";
//~^ symbol_as_str
s.as_str() == "Cargo.toml";
//~^ symbol_as_str
"get" == s.as_str();
//~^ symbol_as_str
}

View file

@ -0,0 +1,76 @@
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str.rs:9:5
|
LL | s.as_str() == "f32";
| ^^^^^^^^^^
|
= note: `-D clippy::symbol-as-str` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
help: use the preinterned symbol
|
LL - s.as_str() == "f32";
LL + s == sym::f32;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str.rs:11:5
|
LL | s.as_str() == "proc-macro";
| ^^^^^^^^^^
|
help: use the preinterned symbol
|
LL - s.as_str() == "proc-macro";
LL + s == sym::proc_dash_macro;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str.rs:13:5
|
LL | s.as_str() == "self";
| ^^^^^^^^^^
|
help: use the preinterned symbol
|
LL - s.as_str() == "self";
LL + s == kw::SelfLower;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str.rs:15:5
|
LL | s.as_str() == "msrv";
| ^^^^^^^^^^
|
help: use the preinterned symbol
|
LL - s.as_str() == "msrv";
LL + s == sym::msrv;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str.rs:17:5
|
LL | s.as_str() == "Cargo.toml";
| ^^^^^^^^^^
|
help: use the preinterned symbol
|
LL - s.as_str() == "Cargo.toml";
LL + s == sym::Cargo_toml;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str.rs:19:14
|
LL | "get" == s.as_str();
| ^^^^^^^^^^
|
help: use the preinterned symbol
|
LL - "get" == s.as_str();
LL + sym::get == s;
|
error: aborting due to 6 previous errors

View file

@ -0,0 +1,15 @@
//@no-rustfix: paths that don't exist yet
#![feature(rustc_private)]
extern crate rustc_span;
use rustc_span::Symbol;
fn f(s: Symbol) {
s.as_str() == "xyz123";
//~^ symbol_as_str
s.as_str() == "with-dash";
//~^ symbol_as_str
s.as_str() == "with.dot";
//~^ symbol_as_str
}

View file

@ -0,0 +1,40 @@
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str_unfixable.rs:9:5
|
LL | s.as_str() == "xyz123";
| ^^^^^^^^^^
|
= note: `-D clippy::symbol-as-str` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
help: add the symbol to `clippy_utils/src/sym.rs` and use it
|
LL - s.as_str() == "xyz123";
LL + s == sym::xyz123;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str_unfixable.rs:11:5
|
LL | s.as_str() == "with-dash";
| ^^^^^^^^^^
|
help: add the symbol to `clippy_utils/src/sym.rs` and use it
|
LL - s.as_str() == "with-dash";
LL + s == sym::with_dash;
|
error: converting a Symbol to a string
--> tests/ui-internal/symbol_as_str_unfixable.rs:13:5
|
LL | s.as_str() == "with.dot";
| ^^^^^^^^^^
|
help: add the symbol to `clippy_utils/src/sym.rs` and use it
|
LL - s.as_str() == "with.dot";
LL + s == sym::with_dot;
|
error: aborting due to 3 previous errors

View file

@ -4,7 +4,6 @@
#![allow(
unused,
unnecessary_transmutes,
clippy::let_and_return,
clippy::needless_if,
clippy::missing_transmute_annotations
)]

View file

@ -4,7 +4,6 @@
#![allow(
unused,
unnecessary_transmutes,
clippy::let_and_return,
clippy::needless_if,
clippy::missing_transmute_annotations
)]

View file

@ -1,5 +1,5 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
--> tests/ui/blocks_in_conditions.rs:31:5
--> tests/ui/blocks_in_conditions.rs:30:5
|
LL | / if {
LL | |
@ -20,13 +20,13 @@ LL ~ }; if res {
|
error: omit braces around single expression condition
--> tests/ui/blocks_in_conditions.rs:43:8
--> tests/ui/blocks_in_conditions.rs:42:8
|
LL | if { true } { 6 } else { 10 }
| ^^^^^^^^ help: try: `true`
error: this boolean expression can be simplified
--> tests/ui/blocks_in_conditions.rs:49:8
--> tests/ui/blocks_in_conditions.rs:48:8
|
LL | if true && x == 3 { 6 } else { 10 }
| ^^^^^^^^^^^^^^ help: try: `x == 3`

View file

@ -103,3 +103,39 @@ fn main() {
external!({ if let 2 = $a {} });
}
mod issue8710 {
fn str_ref(cs: &[char]) {
if matches!(cs.iter().next(), Some('i')) {
//~^ equatable_if_let
} else {
todo!();
}
}
fn i32_ref(cs: &[i32]) {
if matches!(cs.iter().next(), Some(1)) {
//~^ equatable_if_let
} else {
todo!();
}
}
fn enum_ref() {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum MyEnum {
A(i32),
B,
}
fn get_enum() -> Option<&'static MyEnum> {
todo!()
}
if matches!(get_enum(), Some(MyEnum::B)) {
//~^ equatable_if_let
} else {
todo!();
}
}
}

View file

@ -103,3 +103,39 @@ fn main() {
external!({ if let 2 = $a {} });
}
mod issue8710 {
fn str_ref(cs: &[char]) {
if let Some('i') = cs.iter().next() {
//~^ equatable_if_let
} else {
todo!();
}
}
fn i32_ref(cs: &[i32]) {
if let Some(1) = cs.iter().next() {
//~^ equatable_if_let
} else {
todo!();
}
}
fn enum_ref() {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum MyEnum {
A(i32),
B,
}
fn get_enum() -> Option<&'static MyEnum> {
todo!()
}
if let Some(MyEnum::B) = get_enum() {
//~^ equatable_if_let
} else {
todo!();
}
}
}

View file

@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality
LL | if let inline!("abc") = "abc" {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
error: aborting due to 14 previous errors
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:109:12
|
LL | if let Some('i') = cs.iter().next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:117:12
|
LL | if let Some(1) = cs.iter().next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))`
error: this pattern matching can be expressed using `matches!`
--> tests/ui/equatable_if_let.rs:135:12
|
LL | if let Some(MyEnum::B) = get_enum() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))`
error: aborting due to 17 previous errors

View file

@ -1,5 +1,21 @@
#![warn(clippy::manual_div_ceil)]
macro_rules! y {
() => {
let x = 33u32;
let _ = x.div_ceil(8);
//~^ manual_div_ceil
let _ = x.div_ceil(8);
//~^ manual_div_ceil
};
}
macro_rules! eight {
() => {
8
};
}
fn main() {
let x = 7_u32;
let y = 4_u32;
@ -32,6 +48,13 @@ fn main() {
let _ = (z as i32 + (y_i - 1)) / y_i;
let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
let _ = (7_u32 as i32 + (4 - 1)) / 4;
// Test lint with macro
y!();
// Also test if RHS should be result of macro expansion
let _ = 33u32.div_ceil(eight!());
//~^ manual_div_ceil
}
fn issue_13843() {

View file

@ -1,5 +1,21 @@
#![warn(clippy::manual_div_ceil)]
macro_rules! y {
() => {
let x = 33u32;
let _ = (x + 7) / 8;
//~^ manual_div_ceil
let _ = (7 + x) / 8;
//~^ manual_div_ceil
};
}
macro_rules! eight {
() => {
8
};
}
fn main() {
let x = 7_u32;
let y = 4_u32;
@ -32,6 +48,13 @@ fn main() {
let _ = (z as i32 + (y_i - 1)) / y_i;
let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
let _ = (7_u32 as i32 + (4 - 1)) / 4;
// Test lint with macro
y!();
// Also test if RHS should be result of macro expansion
let _ = (33u32 + 7) / eight!();
//~^ manual_div_ceil
}
fn issue_13843() {

View file

@ -1,5 +1,5 @@
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:9:13
--> tests/ui/manual_div_ceil.rs:25:13
|
LL | let _ = (x + (y - 1)) / y;
| ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
@ -8,94 +8,122 @@ LL | let _ = (x + (y - 1)) / y;
= help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:11:13
--> tests/ui/manual_div_ceil.rs:27:13
|
LL | let _ = ((y - 1) + x) / y;
| ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:13:13
--> tests/ui/manual_div_ceil.rs:29:13
|
LL | let _ = (x + y - 1) / y;
| ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:16:13
--> tests/ui/manual_div_ceil.rs:32:13
|
LL | let _ = (7_u32 + (4 - 1)) / 4;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:18:13
--> tests/ui/manual_div_ceil.rs:34:13
|
LL | let _ = (7_i32 as u32 + (4 - 1)) / 4;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:39:13
--> tests/ui/manual_div_ceil.rs:6:17
|
LL | let _ = (x + 7) / 8;
| ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
...
LL | y!();
| ---- in this macro invocation
|
= note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:8:17
|
LL | let _ = (7 + x) / 8;
| ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
...
LL | y!();
| ---- in this macro invocation
|
= note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:56:13
|
LL | let _ = (33u32 + 7) / eight!();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `33u32.div_ceil(eight!())`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:62:13
|
LL | let _ = (2048 + x - 1) / x;
| ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:43:13
--> tests/ui/manual_div_ceil.rs:66:13
|
LL | let _ = (2048usize + x - 1) / x;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:47:13
--> tests/ui/manual_div_ceil.rs:70:13
|
LL | let _ = (2048_usize + x - 1) / x;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:51:13
--> tests/ui/manual_div_ceil.rs:74:13
|
LL | let _ = (x + 4 - 1) / 4;
| ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:54:18
--> tests/ui/manual_div_ceil.rs:77:18
|
LL | let _: u32 = (2048 + 6 - 1) / 6;
| ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:56:20
--> tests/ui/manual_div_ceil.rs:79:20
|
LL | let _: usize = (2048 + 6 - 1) / 6;
| ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:58:18
--> tests/ui/manual_div_ceil.rs:81:18
|
LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:61:13
--> tests/ui/manual_div_ceil.rs:84:13
|
LL | let _ = (2048 + 6u32 - 1) / 6u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:64:13
--> tests/ui/manual_div_ceil.rs:87:13
|
LL | let _ = (1_000_000 + 6u32 - 1) / 6u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:70:13
--> tests/ui/manual_div_ceil.rs:93:13
|
LL | let _ = (x + 7) / 8;
| ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
error: manually reimplementing `div_ceil`
--> tests/ui/manual_div_ceil.rs:72:13
--> tests/ui/manual_div_ceil.rs:95:13
|
LL | let _ = (7 + x) / 8;
| ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
error: aborting due to 16 previous errors
error: aborting due to 19 previous errors

View file

@ -46,9 +46,7 @@ fn main() {
if let true = true
&& true
{}
if true
&& let true = true
{}
if true && let true = true {}
// Can lint nested `if let`s
({
//~^ needless_if

View file

@ -46,9 +46,7 @@ fn main() {
if let true = true
&& true
{}
if true
&& let true = true
{}
if true && let true = true {}
// Can lint nested `if let`s
if {
//~^ needless_if

View file

@ -31,7 +31,7 @@ LL + });
|
error: this `if` branch is empty
--> tests/ui/needless_if.rs:53:5
--> tests/ui/needless_if.rs:51:5
|
LL | / if {
LL | |
@ -57,19 +57,19 @@ LL + } && true);
|
error: this `if` branch is empty
--> tests/ui/needless_if.rs:98:5
--> tests/ui/needless_if.rs:96:5
|
LL | if { maybe_side_effect() } {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
error: this `if` branch is empty
--> tests/ui/needless_if.rs:101:5
--> tests/ui/needless_if.rs:99:5
|
LL | if { maybe_side_effect() } && true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
error: this `if` branch is empty
--> tests/ui/needless_if.rs:106:5
--> tests/ui/needless_if.rs:104:5
|
LL | if true {}
| ^^^^^^^^^^ help: you can remove it: `true;`

View file

@ -246,9 +246,7 @@ fn does_not_lint() {
}
let x;
if true
&& let Some(n) = Some("let chains too")
{
if true && let Some(n) = Some("let chains too") {
x = 1;
} else {
x = 2;

View file

@ -246,9 +246,7 @@ fn does_not_lint() {
}
let x;
if true
&& let Some(n) = Some("let chains too")
{
if true && let Some(n) = Some("let chains too") {
x = 1;
} else {
x = 2;

View file

@ -276,7 +276,7 @@ LL ~ };
|
error: unneeded late initialization
--> tests/ui/needless_late_init.rs:302:5
--> tests/ui/needless_late_init.rs:300:5
|
LL | let r;
| ^^^^^^ created here

View file

@ -1,100 +1,188 @@
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:20:12
|
LL | return Some(to.magic?);
| ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
| ^^^^^^^^^^^^^^^
|
= note: `-D clippy::needless-question-mark` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]`
help: remove the enclosing `Some` and `?` operator
|
LL - return Some(to.magic?);
LL + return to.magic;
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:29:12
|
LL | return Some(to.magic?)
| ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
| ^^^^^^^^^^^^^^^
|
help: remove the enclosing `Some` and `?` operator
|
LL - return Some(to.magic?)
LL + return to.magic
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:35:5
|
LL | Some(to.magic?)
| ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
| ^^^^^^^^^^^^^^^
|
help: remove the enclosing `Some` and `?` operator
|
LL - Some(to.magic?)
LL + to.magic
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:41:21
|
LL | to.and_then(|t| Some(t.magic?))
| ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
| ^^^^^^^^^^^^^^
|
help: remove the enclosing `Some` and `?` operator
|
LL - to.and_then(|t| Some(t.magic?))
LL + to.and_then(|t| t.magic)
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:51:9
|
LL | Some(t.magic?)
| ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
| ^^^^^^^^^^^^^^
|
help: remove the enclosing `Some` and `?` operator
|
LL - Some(t.magic?)
LL + t.magic
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:57:12
|
LL | return Ok(tr.magic?);
| ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
| ^^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - return Ok(tr.magic?);
LL + return tr.magic;
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:65:12
|
LL | return Ok(tr.magic?)
| ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
| ^^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - return Ok(tr.magic?)
LL + return tr.magic
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:70:5
|
LL | Ok(tr.magic?)
| ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
| ^^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - Ok(tr.magic?)
LL + tr.magic
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:75:21
|
LL | tr.and_then(|t| Ok(t.magic?))
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
| ^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - tr.and_then(|t| Ok(t.magic?))
LL + tr.and_then(|t| t.magic)
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:84:9
|
LL | Ok(t.magic?)
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
| ^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - Ok(t.magic?)
LL + t.magic
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:92:16
|
LL | return Ok(t.magic?);
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
| ^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - return Ok(t.magic?);
LL + return t.magic;
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:128:27
|
LL | || -> Option<_> { Some(Some($expr)?) }()
| ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)`
| ^^^^^^^^^^^^^^^^^^
...
LL | let _x = some_and_qmark_in_macro!(x?);
| ---------------------------- in this macro invocation
|
= note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
help: remove the enclosing `Some` and `?` operator
|
LL - || -> Option<_> { Some(Some($expr)?) }()
LL + || -> Option<_> { Some($expr) }()
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:140:5
|
LL | Some(to.magic?)
| ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
| ^^^^^^^^^^^^^^^
|
help: remove the enclosing `Some` and `?` operator
|
LL - Some(to.magic?)
LL + to.magic
|
error: question mark operator is useless here
error: enclosing `Ok` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:149:5
|
LL | Ok(s.magic?)
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
| ^^^^^^^^^^^^
|
help: remove the enclosing `Ok` and `?` operator
|
LL - Ok(s.magic?)
LL + s.magic
|
error: question mark operator is useless here
error: enclosing `Some` and `?` operator are unneeded
--> tests/ui/needless_question_mark.rs:154:7
|
LL | { Some(a?) }
| ^^^^^^^^ help: try removing question mark and `Some()`: `a`
| ^^^^^^^^
|
help: remove the enclosing `Some` and `?` operator
|
LL - { Some(a?) }
LL + { a }
|
error: aborting due to 15 previous errors

View file

@ -23,23 +23,25 @@ fn main() {
//~^ ptr_eq
let _ = std::ptr::eq(a, b);
//~^ ptr_eq
let _ = std::ptr::eq(a.as_ptr(), b as *const _);
//~^ ptr_eq
let _ = std::ptr::eq(a.as_ptr(), b.as_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
//~^ ptr_eq
let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
let _ = a == b;
let _ = core::ptr::eq(a, b);
@ -51,8 +53,12 @@ fn main() {
let _ = !std::ptr::eq(x, y);
//~^ ptr_eq
#[allow(clippy::eq_op)]
let _issue14337 = std::ptr::eq(main as *const (), main as *const ());
#[expect(clippy::eq_op)]
// Do not lint: casts are needed to not change type
let _issue14337 = main as *const () == main as *const ();
// Do not peel the content of macros
let _ = std::ptr::eq(mac!(cast a), mac!(cast b));
//~^ ptr_eq
// Do not peel the content of macros

View file

@ -23,23 +23,25 @@ fn main() {
//~^ ptr_eq
let _ = a as *const _ == b as *const _;
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
//~^ ptr_eq
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
//~^ ptr_eq
let _ = a == b;
let _ = core::ptr::eq(a, b);
@ -51,8 +53,12 @@ fn main() {
let _ = x as *const u32 != y as *mut u32 as *const u32;
//~^ ptr_eq
#[allow(clippy::eq_op)]
#[expect(clippy::eq_op)]
// Do not lint: casts are needed to not change type
let _issue14337 = main as *const () == main as *const ();
// Do not peel the content of macros
let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
//~^ ptr_eq
// Do not peel the content of macros

View file

@ -14,52 +14,28 @@ LL | let _ = a as *const _ == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:26:13
|
LL | let _ = a.as_ptr() == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:28:13
|
LL | let _ = a.as_ptr() == b.as_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:39:13
|
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:41:13
|
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:48:13
--> tests/ui/ptr_eq.rs:50:13
|
LL | let _ = x as *const u32 == y as *mut u32 as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:51:13
--> tests/ui/ptr_eq.rs:53:13
|
LL | let _ = x as *const u32 != y as *mut u32 as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:55:23
|
LL | let _issue14337 = main as *const () == main as *const ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:59:13
--> tests/ui/ptr_eq.rs:61:13
|
LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
error: aborting due to 10 previous errors
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:65:13
|
LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
error: aborting due to 6 previous errors

View file

@ -32,23 +32,25 @@ fn main() {
//~^ ptr_eq
let _ = core::ptr::eq(a, b);
//~^ ptr_eq
let _ = core::ptr::eq(a.as_ptr(), b as *const _);
//~^ ptr_eq
let _ = core::ptr::eq(a.as_ptr(), b.as_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
//~^ ptr_eq
let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
let _ = a == b;
let _ = core::ptr::eq(a, b);

View file

@ -32,23 +32,25 @@ fn main() {
//~^ ptr_eq
let _ = a as *const _ == b as *const _;
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
//~^ ptr_eq
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
//~^ ptr_eq
let _ = a == b;
let _ = core::ptr::eq(a, b);

View file

@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers
LL | let _ = a as *const _ == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:35:13
|
LL | let _ = a.as_ptr() == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:37:13
|
LL | let _ = a.as_ptr() == b.as_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:48:13
|
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:50:13
|
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
error: aborting due to 6 previous errors
error: aborting due to 2 previous errors

View file

@ -301,6 +301,11 @@ fn pattern() -> Result<(), PatternedError> {
res
}
fn expect_expr(a: Option<usize>) -> Option<usize> {
#[expect(clippy::needless_question_mark)]
Some(a?)
}
fn main() {}
// `?` is not the same as `return None;` if inside of a try block

View file

@ -371,6 +371,11 @@ fn pattern() -> Result<(), PatternedError> {
res
}
fn expect_expr(a: Option<usize>) -> Option<usize> {
#[expect(clippy::needless_question_mark)]
Some(a?)
}
fn main() {}
// `?` is not the same as `return None;` if inside of a try block

View file

@ -198,7 +198,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:390:13
--> tests/ui/question_mark.rs:395:13
|
LL | / if a.is_none() {
LL | |
@ -208,7 +208,7 @@ LL | | }
| |_____________^ help: replace it with: `a?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:451:5
--> tests/ui/question_mark.rs:456:5
|
LL | / let Some(v) = bar.foo.owned.clone() else {
LL | | return None;
@ -216,7 +216,7 @@ LL | | };
| |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:466:5
--> tests/ui/question_mark.rs:471:5
|
LL | / let Some(ref x) = foo.opt_x else {
LL | | return None;
@ -224,7 +224,7 @@ LL | | };
| |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:476:5
--> tests/ui/question_mark.rs:481:5
|
LL | / let Some(ref mut x) = foo.opt_x else {
LL | | return None;
@ -232,7 +232,7 @@ LL | | };
| |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:487:5
--> tests/ui/question_mark.rs:492:5
|
LL | / let Some(ref x @ ref y) = foo.opt_x else {
LL | | return None;
@ -240,7 +240,7 @@ LL | | };
| |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:491:5
--> tests/ui/question_mark.rs:496:5
|
LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else {
LL | | return None;
@ -248,7 +248,7 @@ LL | | };
| |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:495:5
--> tests/ui/question_mark.rs:500:5
|
LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
LL | | return None;
@ -256,7 +256,7 @@ LL | | };
| |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:517:5
--> tests/ui/question_mark.rs:522:5
|
LL | / if arg.is_none() {
LL | |
@ -265,7 +265,7 @@ LL | | }
| |_____^ help: replace it with: `arg?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:521:15
--> tests/ui/question_mark.rs:526:15
|
LL | let val = match arg {
| _______________^
@ -276,7 +276,7 @@ LL | | };
| |_____^ help: try instead: `arg?`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:531:5
--> tests/ui/question_mark.rs:536:5
|
LL | / let Some(a) = *a else {
LL | | return None;

View file

@ -1,4 +1,4 @@
error: question mark operator was used
error: the `?` operator was used
--> tests/ui/question_mark_used.rs:11:5
|
LL | other_function()?;

View file

@ -1,4 +1,4 @@
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:5:9
|
LL | / opt.and_then(|n| {
@ -20,7 +20,7 @@ LL + ret += n;
LL + if n > 1 { Some(ret) } else { None }
|
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:14:9
|
LL | opt.and_then(|n| test_opt_block(Some(n)))
@ -32,7 +32,7 @@ LL ~ let n = opt?;
LL + test_opt_block(Some(n))
|
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:19:9
|
LL | gen_option(1).and_then(|n| test_opt_block(Some(n)))
@ -44,7 +44,7 @@ LL ~ let n = gen_option(1)?;
LL + test_opt_block(Some(n))
|
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:24:9
|
LL | opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
@ -56,7 +56,7 @@ LL ~ let n = opt?;
LL + if n > 1 { Ok(n + 1) } else { Err(n) }
|
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:29:9
|
LL | opt.and_then(|n| test_res_block(Ok(n)))
@ -68,7 +68,7 @@ LL ~ let n = opt?;
LL + test_res_block(Ok(n))
|
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:35:9
|
LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
@ -80,7 +80,7 @@ LL ~ let x = Some("")?;
LL + if x.len() > 2 { Some(3) } else { None }
|
error: use the question mark operator instead of an `and_then` call
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:41:9
|
LL | / Some(match (vec![1, 2, 3], vec![1, 2, 4]) {

View file

@ -266,7 +266,21 @@ mod fixable {
// Issue #11968: The suggestion for this lint removes the parentheses and leave the code as
// `*x.pow(2)` which tries to dereference the return value rather than `x`.
fn issue_11968(x: &usize) -> usize {
{ *x }.pow(2)
(*x).pow(2)
//~^ unnecessary_cast
}
#[allow(clippy::cast_lossless)]
fn issue_14640() {
let x = 5usize;
let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
assert_eq!(vec.len(), x);
//~^ unnecessary_cast
let _ = (5i32 as i64).abs();
//~^ unnecessary_cast
let _ = 5i32 as i64;
//~^ unnecessary_cast
}
}

View file

@ -269,4 +269,18 @@ mod fixable {
(*x as usize).pow(2)
//~^ unnecessary_cast
}
#[allow(clippy::cast_lossless)]
fn issue_14640() {
let x = 5usize;
let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
assert_eq!(vec.len(), x as usize);
//~^ unnecessary_cast
let _ = (5i32 as i64 as i64).abs();
//~^ unnecessary_cast
let _ = 5i32 as i64 as i64;
//~^ unnecessary_cast
}
}

View file

@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`)
--> tests/ui/unnecessary_cast.rs:269:9
|
LL | (*x as usize).pow(2)
| ^^^^^^^^^^^^^ help: try: `{ *x }`
| ^^^^^^^^^^^^^ help: try: `(*x)`
error: aborting due to 41 previous errors
error: casting to the same type is unnecessary (`usize` -> `usize`)
--> tests/ui/unnecessary_cast.rs:277:31
|
LL | assert_eq!(vec.len(), x as usize);
| ^^^^^^^^^^ help: try: `x`
error: casting to the same type is unnecessary (`i64` -> `i64`)
--> tests/ui/unnecessary_cast.rs:280:17
|
LL | let _ = (5i32 as i64 as i64).abs();
| ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)`
error: casting to the same type is unnecessary (`i64` -> `i64`)
--> tests/ui/unnecessary_cast.rs:283:17
|
LL | let _ = 5i32 as i64 as i64;
| ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
error: aborting due to 44 previous errors

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