Use interned symbols instead of strings in more places (#14840)

This patch series makes heavy use of interned symbols when matching
against known method names:

- the first commit reorders the current list of symbols in
`clippy_utils::sym`
- the second commit adds symbol reordering and order checking to `clippy
dev fmt` / `clippy dev fmt --check`
- the third commit converts many uses of string matching during linting
to symbols matching

The symbols are kept as-is (not rendered as strings) as much as possible
to avoid needing locking the interner as much as possible. Static
strings have been kept when they are only used when emitting a
diagnostic, as there is no benefit in using interned strings for
de-interning them right after.

changelog: none

r? @Alexendoo
This commit is contained in:
Jason Newcomb
2025-05-19 21:07:29 +00:00
committed by GitHub
87 changed files with 951 additions and 708 deletions

View File

@@ -1,6 +1,9 @@
use crate::utils::{ClippyInfo, ErrAction, UpdateMode, panic_action, run_with_args_split, run_with_output}; use crate::utils::{
ClippyInfo, ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_args_split, run_with_output,
};
use itertools::Itertools; use itertools::Itertools;
use rustc_lexer::{TokenKind, tokenize}; use rustc_lexer::{TokenKind, tokenize};
use std::fmt::Write;
use std::fs; use std::fs;
use std::io::{self, Read}; use std::io::{self, Read};
use std::ops::ControlFlow; use std::ops::ControlFlow;
@@ -225,6 +228,38 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Format the symbols list
fn fmt_syms(update_mode: UpdateMode) {
FileUpdater::default().update_file_checked(
"cargo dev fmt",
update_mode,
"clippy_utils/src/sym.rs",
&mut |_, text: &str, new_text: &mut String| {
let (pre, conf) = text.split_once("generate! {\n").expect("can't find generate! call");
let (conf, post) = conf.split_once("\n}\n").expect("can't find end of generate! call");
let mut lines = conf
.lines()
.map(|line| {
let line = line.trim();
line.strip_suffix(',').unwrap_or(line).trim_end()
})
.collect::<Vec<_>>();
lines.sort_unstable();
write!(
new_text,
"{pre}generate! {{\n {},\n}}\n{post}",
lines.join(",\n "),
)
.unwrap();
if text == new_text {
UpdateStatus::Unchanged
} else {
UpdateStatus::Changed
}
},
);
}
fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) {
let mut rustfmt_path = String::from_utf8(run_with_output( let mut rustfmt_path = String::from_utf8(run_with_output(
"rustup which rustfmt", "rustup which rustfmt",
@@ -337,7 +372,7 @@ pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) {
return; return;
} }
run_rustfmt(clippy, update_mode); run_rustfmt(clippy, update_mode);
fmt_syms(update_mode);
if let Err(e) = fmt_conf(update_mode.is_check()) { if let Err(e) = fmt_conf(update_mode.is_check()) {
e.display(); e.display();
process::exit(1); process::exit(1);

View File

@@ -3,14 +3,13 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
use clippy_utils::usage::local_used_after_expr; use clippy_utils::usage::local_used_after_expr;
use clippy_utils::{is_expr_final_block_expr, path_res}; use clippy_utils::{is_expr_final_block_expr, path_res, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -68,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
return; return;
} }
} }
let (message, replacement) = match method_segment.ident.as_str() { let (message, replacement) = match method_segment.ident.name {
"is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => { sym::is_ok if type_suitable_to_unwrap(cx, args.type_at(1)) => {
("called `assert!` with `Result::is_ok`", "unwrap") ("called `assert!` with `Result::is_ok`", "unwrap")
}, },
"is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => { sym::is_err if type_suitable_to_unwrap(cx, args.type_at(0)) => {
("called `assert!` with `Result::is_err`", "unwrap_err") ("called `assert!` with `Result::is_err`", "unwrap_err")
}, },
_ => return, _ => return,

View File

@@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
if signed { if signed {
return nbits; return nbits;
} }
let max_bits = if method.ident.as_str() == "min" { let max_bits = if method.ident.name == sym::min {
get_constant_bits(cx, right) get_constant_bits(cx, right)
} else { } else {
None None
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
}, },
ExprKind::MethodCall(method, _, [lo, hi], _) => { ExprKind::MethodCall(method, _, [lo, hi], _) => {
if method.ident.as_str() == "clamp" if method.ident.name == sym::clamp
//FIXME: make this a diagnostic item //FIXME: make this a diagnostic item
&& let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi))
{ {

View File

@@ -4,10 +4,11 @@ use std::ops::ControlFlow;
use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
use clippy_utils::{method_chain_args, sext}; use clippy_utils::{method_chain_args, sext, sym};
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::Symbol;
use super::CAST_SIGN_LOSS; use super::CAST_SIGN_LOSS;
@@ -16,24 +17,24 @@ use super::CAST_SIGN_LOSS;
/// ///
/// Methods that can overflow and return a negative value must not be included in this list, /// Methods that can overflow and return a negative value must not be included in this list,
/// because casting their return values can still result in sign loss. /// because casting their return values can still result in sign loss.
const METHODS_RET_POSITIVE: &[&str] = &[ const METHODS_RET_POSITIVE: &[Symbol] = &[
"checked_abs", sym::checked_abs,
"saturating_abs", sym::saturating_abs,
"isqrt", sym::isqrt,
"checked_isqrt", sym::checked_isqrt,
"rem_euclid", sym::rem_euclid,
"checked_rem_euclid", sym::checked_rem_euclid,
"wrapping_rem_euclid", sym::wrapping_rem_euclid,
]; ];
/// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details. /// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details.
/// ///
/// Methods that can overflow and return a negative value must not be included in this list, /// Methods that can overflow and return a negative value must not be included in this list,
/// because casting their return values can still result in sign loss. /// because casting their return values can still result in sign loss.
const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"]; const METHODS_POW: &[Symbol] = &[sym::pow, sym::saturating_pow, sym::checked_pow];
/// A list of methods that act like `unwrap()`, and don't change the sign of the inner value. /// A list of methods that act like `unwrap()`, and don't change the sign of the inner value.
const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"]; const METHODS_UNWRAP: &[Symbol] = &[sym::unwrap, sym::unwrap_unchecked, sym::expect, sym::into_ok];
pub(super) fn check<'cx>( pub(super) fn check<'cx>(
cx: &LateContext<'cx>, cx: &LateContext<'cx>,
@@ -129,7 +130,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i
// Calling on methods that always return non-negative values. // Calling on methods that always return non-negative values.
if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind { if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind {
let mut method_name = path.ident.name.as_str(); let mut method_name = path.ident.name;
// Peel unwrap(), expect(), etc. // Peel unwrap(), expect(), etc.
while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name) while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
@@ -138,7 +139,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i
{ {
// The original type has changed, but we can't use `ty` here anyway, because it has been // The original type has changed, but we can't use `ty` here anyway, because it has been
// moved. // moved.
method_name = inner_path.ident.name.as_str(); method_name = inner_path.ident.name;
expr = recv; expr = recv;
} }

View File

@@ -1,11 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sym;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArg, Ty}; use rustc_middle::ty::{self, GenericArg, Ty};
use rustc_span::Symbol;
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::{Symbol, sym};
use super::CONFUSING_METHOD_TO_NUMERIC_CAST; use super::CONFUSING_METHOD_TO_NUMERIC_CAST;
@@ -25,7 +26,6 @@ fn get_const_name_and_ty_name(
method_def_id: DefId, method_def_id: DefId,
generics: &[GenericArg<'_>], generics: &[GenericArg<'_>],
) -> Option<(&'static str, &'static str)> { ) -> Option<(&'static str, &'static str)> {
let method_name = method_name.as_str();
let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id); let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id);
let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) { let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) {
@@ -39,14 +39,21 @@ fn get_const_name_and_ty_name(
} }
} else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id) } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id)
&& let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity()) && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity())
&& ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name) && matches!(
method_name,
sym::min | sym::max | sym::minimum | sym::maximum | sym::min_value | sym::max_value
)
{ {
ty_name ty_name
} else { } else {
return None; return None;
}; };
let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" }; let const_name = if matches!(method_name, sym::max | sym::maximum | sym::max_value) {
"MAX"
} else {
"MIN"
};
Some((const_name, ty_name)) Some((const_name, ty_name))
} }

View File

@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::std_or_core;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{std_or_core, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_hir::{Expr, ExprKind, Mutability, QPath};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_span::sym;
use super::PTR_CAST_CONSTNESS; use super::PTR_CAST_CONSTNESS;
@@ -78,9 +77,9 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>)
&& let ExprKind::Call(func, []) = cast_expr.kind && let ExprKind::Call(func, []) = cast_expr.kind
&& let ExprKind::Path(QPath::Resolved(None, path)) = func.kind && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
&& let Some(defid) = path.res.opt_def_id() && let Some(defid) = path.res.opt_def_id()
&& let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) { && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) {
(Some(sym::ptr_null), "cast_mut") => "null_mut", (Some(sym::ptr_null), sym::cast_mut) => "null_mut",
(Some(sym::ptr_null_mut), "cast_const") => "null", (Some(sym::ptr_null_mut), sym::cast_const) => "null",
_ => return, _ => return,
} }
&& let Some(prefix) = std_or_core(cx) && let Some(prefix) = std_or_core(cx)

View File

@@ -3,14 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl}; use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{Span, sym};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -157,9 +157,9 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
} }
fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity"); self.limit.push_attrs(cx.sess(), attrs, sym::cognitive_complexity);
} }
fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity"); self.limit.pop_attrs(cx.sess(), attrs, sym::cognitive_complexity);
} }
} }

View File

@@ -113,7 +113,8 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
} }
// check for `unwrap` and `expect` for both `Option` and `Result` // check for `unwrap` and `expect` for both `Option` and `Result`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"])) if let Some(arglists) =
method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect]))
&& let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs() && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
&& matches!( && matches!(
get_type_diagnostic_name(cx, receiver_ty), get_type_diagnostic_name(cx, receiver_ty),

View File

@@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span}; use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span};
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_expn_of, path_def_id}; use clippy_utils::{is_expn_of, path_def_id, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{ExpnId, sym}; use rustc_span::ExpnId;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -72,9 +72,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
}; };
// ordering is important here, since `writeln!` uses `write!` internally // ordering is important here, since `writeln!` uses `write!` internally
let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() {
Some("writeln") Some("writeln")
} else if is_expn_of(write_call.span, "write").is_some() { } else if is_expn_of(write_call.span, sym::write).is_some() {
Some("write") Some("write")
} else { } else {
None None

View File

@@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
} }
// check for `unwrap` // check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) {
let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)

View File

@@ -294,8 +294,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
&& let Some(parent) = get_parent_expr(cx, expr) && let Some(parent) = get_parent_expr(cx, expr)
{ {
if let Some(grandparent) = get_parent_expr(cx, parent) if let Some(grandparent) = get_parent_expr(cx, parent)
&& let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind
&& method_name.as_str() == "sqrt" && method.name == sym::sqrt
&& detect_hypot(cx, receiver).is_some() && detect_hypot(cx, receiver).is_some()
{ {
return; return;
@@ -375,24 +375,10 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
} }
// check if expression of the form x.powi(2) + y.powi(2) // check if expression of the form x.powi(2) + y.powi(2)
if let ExprKind::MethodCall( if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = &add_lhs.kind
PathSegment { && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = &add_rhs.kind
ident: lmethod_name, .. && lmethod.name == sym::powi
}, && rmethod.name == sym::powi
largs_0,
[largs_1, ..],
_,
) = &add_lhs.kind
&& let ExprKind::MethodCall(
PathSegment {
ident: rmethod_name, ..
},
rargs_0,
[rargs_1, ..],
_,
) = &add_rhs.kind
&& lmethod_name.as_str() == "powi"
&& rmethod_name.as_str() == "powi"
&& let ecx = ConstEvalCtxt::new(cx) && let ecx = ConstEvalCtxt::new(cx)
&& let Some(lvalue) = ecx.eval(largs_1) && let Some(lvalue) = ecx.eval(largs_1)
&& let Some(rvalue) = ecx.eval(rargs_1) && let Some(rvalue) = ecx.eval(rargs_1)
@@ -482,8 +468,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
) = &expr.kind ) = &expr.kind
{ {
if let Some(parent) = get_parent_expr(cx, expr) if let Some(parent) = get_parent_expr(cx, expr)
&& let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind
&& method_name.as_str() == "sqrt" && method.name == sym::sqrt
&& detect_hypot(cx, receiver).is_some() && detect_hypot(cx, receiver).is_some()
{ {
return; return;
@@ -623,27 +609,13 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
} }
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
if let ExprKind::MethodCall( if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind
PathSegment { && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind
ident: method_name_a, ..
},
_,
args_a,
_,
) = expr_a.kind
&& let ExprKind::MethodCall(
PathSegment {
ident: method_name_b, ..
},
_,
args_b,
_,
) = expr_b.kind
{ {
return method_name_a.as_str() == method_name_b.as_str() return method_a.name == method_b.name
&& args_a.len() == args_b.len() && args_a.len() == args_b.len()
&& (["ln", "log2", "log10"].contains(&method_name_a.as_str()) && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10)
|| method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
} }
false false

View File

@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet; use clippy_utils::higher::IfLet;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_copy; use clippy_utils::ty::is_copy;
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local, sym};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@@ -72,7 +72,7 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
&& (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) && (!expr.span.from_expansion() || is_expn_of(expr.span, sym::if_chain).is_some())
&& !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
&& let found_slices = find_slice_values(cx, let_pat) && let found_slices = find_slice_values(cx, let_pat)
&& !found_slices.is_empty() && !found_slices.is_empty()

View File

@@ -1,13 +1,13 @@
use crate::methods::method_call; use crate::methods::method_call;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::peel_blocks; use clippy_utils::{peel_blocks, sym};
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Span, sym}; use rustc_span::{BytePos, Span};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -57,7 +57,7 @@ fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> {
impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else { let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else {
return; return;
}; };
let receiver_ty = cx.typeck_results().expr_ty(receiver); let receiver_ty = cx.typeck_results().expr_ty(receiver);
@@ -70,9 +70,9 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
let mut write = None; let mut write = None;
while let Some((name, recv, args, _, span)) = method_call(receiver) { while let Some((name, recv, args, _, span)) = method_call(receiver) {
if name == "append" { if name == sym::append {
append = index_if_arg_is_boolean(args, span); append = index_if_arg_is_boolean(args, span);
} else if name == "write" { } else if name == sym::write {
write = index_if_arg_is_boolean(args, span); write = index_if_arg_is_boolean(args, span);
} }
receiver = recv; receiver = recv;

View File

@@ -4,6 +4,7 @@ use clippy_utils::{higher, sym};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::Symbol;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -119,33 +120,33 @@ use self::Heuristic::{All, Always, Any, First};
/// returns an infinite or possibly infinite iterator. The finiteness /// returns an infinite or possibly infinite iterator. The finiteness
/// is an upper bound, e.g., some methods can return a possibly /// is an upper bound, e.g., some methods can return a possibly
/// infinite iterator at worst, e.g., `take_while`. /// infinite iterator at worst, e.g., `take_while`.
const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ const HEURISTICS: [(Symbol, usize, Heuristic, Finiteness); 19] = [
("zip", 1, All, Infinite), (sym::zip, 1, All, Infinite),
("chain", 1, Any, Infinite), (sym::chain, 1, Any, Infinite),
("cycle", 0, Always, Infinite), (sym::cycle, 0, Always, Infinite),
("map", 1, First, Infinite), (sym::map, 1, First, Infinite),
("by_ref", 0, First, Infinite), (sym::by_ref, 0, First, Infinite),
("cloned", 0, First, Infinite), (sym::cloned, 0, First, Infinite),
("rev", 0, First, Infinite), (sym::rev, 0, First, Infinite),
("inspect", 0, First, Infinite), (sym::inspect, 0, First, Infinite),
("enumerate", 0, First, Infinite), (sym::enumerate, 0, First, Infinite),
("peekable", 1, First, Infinite), (sym::peekable, 1, First, Infinite),
("fuse", 0, First, Infinite), (sym::fuse, 0, First, Infinite),
("skip", 1, First, Infinite), (sym::skip, 1, First, Infinite),
("skip_while", 0, First, Infinite), (sym::skip_while, 0, First, Infinite),
("filter", 1, First, Infinite), (sym::filter, 1, First, Infinite),
("filter_map", 1, First, Infinite), (sym::filter_map, 1, First, Infinite),
("flat_map", 1, First, Infinite), (sym::flat_map, 1, First, Infinite),
("unzip", 0, First, Infinite), (sym::unzip, 0, First, Infinite),
("take_while", 1, First, MaybeInfinite), (sym::take_while, 1, First, MaybeInfinite),
("scan", 2, First, MaybeInfinite), (sym::scan, 2, First, MaybeInfinite),
]; ];
fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind { match expr.kind {
ExprKind::MethodCall(method, receiver, args, _) => { ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len, heuristic, cap) in &HEURISTICS { for &(name, len, heuristic, cap) in &HEURISTICS {
if method.ident.name.as_str() == name && args.len() == len { if method.ident.name == name && args.len() == len {
return (match heuristic { return (match heuristic {
Always => Infinite, Always => Infinite,
First => is_infinite(cx, receiver), First => is_infinite(cx, receiver),
@@ -183,36 +184,36 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
/// the names and argument lengths of methods that *may* exhaust their /// the names and argument lengths of methods that *may* exhaust their
/// iterators /// iterators
const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [ const POSSIBLY_COMPLETING_METHODS: [(Symbol, usize); 6] = [
("find", 1), (sym::find, 1),
("rfind", 1), (sym::rfind, 1),
("position", 1), (sym::position, 1),
("rposition", 1), (sym::rposition, 1),
("any", 1), (sym::any, 1),
("all", 1), (sym::all, 1),
]; ];
/// the names and argument lengths of methods that *always* exhaust /// the names and argument lengths of methods that *always* exhaust
/// their iterators /// their iterators
const COMPLETING_METHODS: [(&str, usize); 12] = [ const COMPLETING_METHODS: [(Symbol, usize); 12] = [
("count", 0), (sym::count, 0),
("fold", 2), (sym::fold, 2),
("for_each", 1), (sym::for_each, 1),
("partition", 1), (sym::partition, 1),
("max", 0), (sym::max, 0),
("max_by", 1), (sym::max_by, 1),
("max_by_key", 1), (sym::max_by_key, 1),
("min", 0), (sym::min, 0),
("min_by", 1), (sym::min_by, 1),
("min_by_key", 1), (sym::min_by_key, 1),
("sum", 0), (sym::sum, 0),
("product", 0), (sym::product, 0),
]; ];
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind { match expr.kind {
ExprKind::MethodCall(method, receiver, args, _) => { ExprKind::MethodCall(method, receiver, args, _) => {
let method_str = method.ident.name.as_str(); let method_str = method.ident.name;
for &(name, len) in &COMPLETING_METHODS { for &(name, len) in &COMPLETING_METHODS {
if method_str == name && args.len() == len { if method_str == name && args.len() == len {
return is_infinite(cx, receiver); return is_infinite(cx, receiver);

View File

@@ -2,12 +2,12 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id}; use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_hir::{Body, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::sym; use rustc_span::Symbol;
pub struct LinesFilterMapOk { pub struct LinesFilterMapOk {
msrv: Msrv, msrv: Msrv,
@@ -74,17 +74,17 @@ impl LateLintPass<'_> for LinesFilterMapOk {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
&& is_trait_method(cx, expr, sym::Iterator) && is_trait_method(cx, expr, sym::Iterator)
&& let fm_method_str = fm_method.ident.as_str() && let fm_method_name = fm_method.ident.name
&& matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") && matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
&& should_lint(cx, fm_args, fm_method_str) && should_lint(cx, fm_args, fm_method_name)
&& self.msrv.meets(cx, msrvs::MAP_WHILE) && self.msrv.meets(cx, msrvs::MAP_WHILE)
{ {
span_lint_and_then( span_lint_and_then(
cx, cx,
LINES_FILTER_MAP_OK, LINES_FILTER_MAP_OK,
fm_span, fm_span,
format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), format!("`{fm_method_name}()` will run forever if the iterator repeatedly produces an `Err`",),
|diag| { |diag| {
diag.span_note( diag.span_note(
fm_receiver.span, fm_receiver.span,
@@ -101,9 +101,9 @@ impl LateLintPass<'_> for LinesFilterMapOk {
} }
} }
fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool { fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) -> bool {
match args { match args {
[] => method_str == "flatten", [] => method_name == sym::flatten,
[fm_arg] => { [fm_arg] => {
match &fm_arg.kind { match &fm_arg.kind {
// Detect `Result::ok` // Detect `Result::ok`
@@ -120,7 +120,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
&& path_to_local_id(receiver, param.pat.hir_id) && path_to_local_id(receiver, param.pat.hir_id)
&& let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
{ {
is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok
} else { } else {
false false
} }

View File

@@ -3,12 +3,12 @@ use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::ty::is_type_lang_item; use clippy_utils::ty::is_type_lang_item;
use clippy_utils::visitors::for_each_expr; use clippy_utils::visitors::for_each_expr;
use clippy_utils::{eq_expr_value, higher, path_to_local_id}; use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym};
use rustc_errors::{Applicability, MultiSpan}; use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind}; use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol};
use super::CHAR_INDICES_AS_BYTE_INDICES; use super::CHAR_INDICES_AS_BYTE_INDICES;
@@ -16,22 +16,22 @@ use super::CHAR_INDICES_AS_BYTE_INDICES;
// Note: `String` also has methods that work with byte indices, // Note: `String` also has methods that work with byte indices,
// but they all take `&mut self` and aren't worth considering since the user couldn't have called // but they all take `&mut self` and aren't worth considering since the user couldn't have called
// them while the chars iterator is live anyway. // them while the chars iterator is live anyway.
const BYTE_INDEX_METHODS: &[&str] = &[ const BYTE_INDEX_METHODS: &[Symbol] = &[
"is_char_boundary", sym::ceil_char_boundary,
"floor_char_boundary", sym::floor_char_boundary,
"ceil_char_boundary", sym::get,
"get", sym::get_mut,
"index", sym::get_unchecked,
"index_mut", sym::get_unchecked_mut,
"get_mut", sym::index,
"get_unchecked", sym::index_mut,
"get_unchecked_mut", sym::is_char_boundary,
"slice_unchecked", sym::slice_mut_unchecked,
"slice_mut_unchecked", sym::slice_unchecked,
"split_at", sym::split_at,
"split_at_mut", sym::split_at_checked,
"split_at_checked", sym::split_at_mut,
"split_at_mut_checked", sym::split_at_mut_checked,
]; ];
const CONTINUE: ControlFlow<!, ()> = ControlFlow::Continue(()); const CONTINUE: ControlFlow<!, ()> = ControlFlow::Continue(());
@@ -88,7 +88,7 @@ fn check_index_usage<'tcx>(
// (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements
// `Index` directly and no deref to `str` would happen in that case). // `Index` directly and no deref to `str` would happen in that case).
if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str() if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str()
&& BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str()) && BYTE_INDEX_METHODS.contains(&segment.ident.name)
&& eq_expr_value(cx, chars_recv, recv) => && eq_expr_value(cx, chars_recv, recv) =>
{ {
"passing a character position to a method that expects a byte index" "passing a character position to a method that expects a byte index"

View File

@@ -25,8 +25,8 @@ mod while_let_loop;
mod while_let_on_iterator; mod while_let_on_iterator;
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::higher;
use clippy_utils::msrvs::Msrv; use clippy_utils::msrvs::Msrv;
use clippy_utils::{higher, sym};
use rustc_ast::Label; use rustc_ast::Label;
use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@@ -910,14 +910,14 @@ impl Loops {
fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
match method.ident.as_str() { match method.ident.name {
"iter" | "iter_mut" => { sym::iter | sym::iter_mut => {
explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow); explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow);
}, },
"into_iter" => { sym::into_iter => {
explicit_into_iter_loop::check(cx, self_arg, arg); explicit_into_iter_loop::check(cx, self_arg, arg);
}, },
"next" => { sym::next => {
iter_next_loop::check(cx, arg); iter_next_loop::check(cx, arg);
}, },
_ => {}, _ => {},

View File

@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::ty::ty_from_hir_ty; use clippy_utils::ty::ty_from_hir_ty;
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@@ -103,7 +103,7 @@ fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio
} else { } else {
return None; return None;
}; };
(method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) (method.ident.name == sym::count_ones && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
} }
/// Return `greater` if `smaller == greater - 1` /// Return `greater` if `smaller == greater - 1`

View File

@@ -255,7 +255,7 @@ impl LateLintPass<'_> for MapUnit {
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
if let hir::StmtKind::Semi(expr) = stmt.kind if let hir::StmtKind::Semi(expr) = stmt.kind
&& !stmt.span.from_expansion() && !stmt.span.from_expansion()
&& let Some(arglists) = method_chain_args(expr, &["map"]) && let Some(arglists) = method_chain_args(expr, &[sym::map])
{ {
lint_map_unit_fn(cx, stmt, expr, arglists[0]); lint_map_unit_fn(cx, stmt, expr, arglists[0]);
} }

View File

@@ -28,7 +28,7 @@ use clippy_config::Conf;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::walk_span_to_context; use clippy_utils::source::walk_span_to_context;
use clippy_utils::{ use clippy_utils::{
higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym,
}; };
use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -1053,13 +1053,13 @@ impl_lint_pass!(Matches => [
impl<'tcx> LateLintPass<'tcx> for Matches { impl<'tcx> LateLintPass<'tcx> for Matches {
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) { if is_direct_expn_of(expr.span, sym::matches).is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
return; return;
} }
let from_expansion = expr.span.from_expansion(); let from_expansion = expr.span.from_expansion();
if let ExprKind::Match(ex, arms, source) = expr.kind { if let ExprKind::Match(ex, arms, source) = expr.kind {
if is_direct_expn_of(expr.span, "matches").is_some() if is_direct_expn_of(expr.span, sym::matches).is_some()
&& let [arm, _] = arms && let [arm, _] = arms
{ {
redundant_pattern_match::check_match(cx, expr, ex, arms); redundant_pattern_match::check_match(cx, expr, ex, arms);

View File

@@ -3,14 +3,14 @@ use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::msrvs::Msrv; use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
use clippy_utils::{is_in_const_context, path_to_local}; use clippy_utils::{is_in_const_context, path_to_local, sym};
use rustc_ast::{BorrowKind, LitKind}; use rustc_ast::{BorrowKind, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol};
use std::borrow::Cow; use std::borrow::Cow;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
} else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind
&& let Some(binding) = get_pat_binding(cx, recv, outer_arm) && let Some(binding) = get_pat_binding(cx, recv, outer_arm)
{ {
check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding); check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding);
} }
} }
} }
@@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
fn check_method_calls<'tcx>( fn check_method_calls<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
arm: &Arm<'tcx>, arm: &Arm<'tcx>,
method: &str, method: Symbol,
recv: &Expr<'_>, recv: &Expr<'_>,
args: &[Expr<'_>], args: &[Expr<'_>],
if_expr: &Expr<'_>, if_expr: &Expr<'_>,
@@ -112,7 +112,7 @@ fn check_method_calls<'tcx>(
let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let ty = cx.typeck_results().expr_ty(recv).peel_refs();
let slice_like = ty.is_slice() || ty.is_array(); let slice_like = ty.is_slice() || ty.is_array();
let sugg = if method == "is_empty" { let sugg = if method == sym::is_empty {
// `s if s.is_empty()` becomes "" // `s if s.is_empty()` becomes ""
// `arr if arr.is_empty()` becomes [] // `arr if arr.is_empty()` becomes []
@@ -137,9 +137,9 @@ fn check_method_calls<'tcx>(
if needles.is_empty() { if needles.is_empty() {
sugg.insert_str(1, ".."); sugg.insert_str(1, "..");
} else if method == "starts_with" { } else if method == sym::starts_with {
sugg.insert_str(sugg.len() - 1, ", .."); sugg.insert_str(sugg.len() - 1, ", ..");
} else if method == "ends_with" { } else if method == sym::ends_with {
sugg.insert_str(1, ".., "); sugg.insert_str(1, ".., ");
} else { } else {
return; return;

View File

@@ -273,7 +273,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) { if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span)); let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
let result_expr = match &op.kind { let result_expr = match &op.kind {
ExprKind::AddrOf(_, _, borrowed) => borrowed, ExprKind::AddrOf(_, _, borrowed) => borrowed,
_ => op, _ => op,

View File

@@ -4,7 +4,7 @@ use crate::FxHashSet;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{first_line_of_span, indent_of, snippet}; use clippy_utils::source::{first_line_of_span, indent_of, snippet};
use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
use clippy_utils::{get_attr, is_lint_allowed}; use clippy_utils::{get_attr, is_lint_allowed, sym};
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
@@ -186,7 +186,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
&& get_attr( && get_attr(
self.cx.sess(), self.cx.sess(),
self.cx.tcx.get_attrs_unchecked(adt.did()), self.cx.tcx.get_attrs_unchecked(adt.did()),
"has_significant_drop", sym::has_significant_drop,
) )
.count() .count()
> 0 > 0

View File

@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sym;
use clippy_utils::ty::is_type_lang_item; use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, LangItem}; use rustc_hir::{Expr, LangItem};
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
&& let Some((name, _, _, _, _)) = method_call(parent) && let Some((name, _, _, _, _)) = method_call(parent)
&& name == "unwrap" && name == sym::unwrap
{ {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,

View File

@@ -5,12 +5,13 @@ use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, Lint}; use rustc_lint::{LateContext, Lint};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::Symbol;
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
pub(super) fn check( pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
info: &crate::methods::BinaryExprInfo<'_>, info: &crate::methods::BinaryExprInfo<'_>,
chain_methods: &[&str], chain_methods: &[Symbol],
lint: &'static Lint, lint: &'static Lint,
suggest: &str, suggest: &str,
) -> bool { ) -> bool {

View File

@@ -5,12 +5,13 @@ use rustc_ast::ast;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, Lint}; use rustc_lint::{LateContext, Lint};
use rustc_span::Symbol;
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
pub(super) fn check( pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
info: &crate::methods::BinaryExprInfo<'_>, info: &crate::methods::BinaryExprInfo<'_>,
chain_methods: &[&str], chain_methods: &[Symbol],
lint: &'static Lint, lint: &'static Lint,
suggest: &str, suggest: &str,
) -> bool { ) -> bool {

View File

@@ -1,13 +1,14 @@
use crate::methods::chars_cmp; use crate::methods::chars_cmp;
use clippy_utils::sym;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use super::CHARS_LAST_CMP; use super::CHARS_LAST_CMP;
/// Checks for the `CHARS_LAST_CMP` lint. /// Checks for the `CHARS_LAST_CMP` lint.
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { if chars_cmp::check(cx, info, &[sym::chars, sym::last], CHARS_LAST_CMP, "ends_with") {
true true
} else { } else {
chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") chars_cmp::check(cx, info, &[sym::chars, sym::next_back], CHARS_LAST_CMP, "ends_with")
} }
} }

View File

@@ -1,13 +1,26 @@
use crate::methods::chars_cmp_with_unwrap; use crate::methods::chars_cmp_with_unwrap;
use clippy_utils::sym;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use super::CHARS_LAST_CMP; use super::CHARS_LAST_CMP;
/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { if chars_cmp_with_unwrap::check(
cx,
info,
&[sym::chars, sym::last, sym::unwrap],
CHARS_LAST_CMP,
"ends_with",
) {
true true
} else { } else {
chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") chars_cmp_with_unwrap::check(
cx,
info,
&[sym::chars, sym::next_back, sym::unwrap],
CHARS_LAST_CMP,
"ends_with",
)
} }
} }

View File

@@ -1,8 +1,9 @@
use clippy_utils::sym;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use super::CHARS_NEXT_CMP; use super::CHARS_NEXT_CMP;
/// Checks for the `CHARS_NEXT_CMP` lint. /// Checks for the `CHARS_NEXT_CMP` lint.
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") crate::methods::chars_cmp::check(cx, info, &[sym::chars, sym::next], CHARS_NEXT_CMP, "starts_with")
} }

View File

@@ -1,8 +1,15 @@
use clippy_utils::sym;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use super::CHARS_NEXT_CMP; use super::CHARS_NEXT_CMP;
/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") crate::methods::chars_cmp_with_unwrap::check(
cx,
info,
&[sym::chars, sym::next, sym::unwrap],
CHARS_NEXT_CMP,
"starts_with",
)
} }

View File

@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{eq_expr_value, get_parent_expr}; use clippy_utils::{eq_expr_value, get_parent_expr, sym};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
// If the parent node's `to` argument is the same as the `to` argument // If the parent node's `to` argument is the same as the `to` argument
// of the last replace call in the current chain, don't lint as it was already linted // of the last replace call in the current chain, don't lint as it was already linted
if let Some(parent) = get_parent_expr(cx, expr) if let Some(parent) = get_parent_expr(cx, expr)
&& let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent) && let Some((sym::replace, _, [current_from, current_to], _, _)) = method_call(parent)
&& eq_expr_value(cx, to, current_to) && eq_expr_value(cx, to, current_to)
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
{ {
@@ -47,7 +47,7 @@ fn collect_replace_calls<'tcx>(
let mut from_args = VecDeque::new(); let mut from_args = VecDeque::new();
let _: Option<()> = for_each_expr_without_closures(expr, |e| { let _: Option<()> = for_each_expr_without_closures(expr, |e| {
if let Some(("replace", _, [from, to], _, _)) = method_call(e) { if let Some((sym::replace, _, [from, to], _, _)) = method_call(e) {
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
methods.push_front(e); methods.push_front(e);
from_args.push_front(from); from_args.push_front(from);

View File

@@ -6,8 +6,8 @@ use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::Span;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use std::borrow::Cow; use std::borrow::Cow;
use super::EXPECT_FUN_CALL; use super::EXPECT_FUN_CALL;
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
format_args_storage: &FormatArgsStorage, format_args_storage: &FormatArgsStorage,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
method_span: Span, method_span: Span,
name: &str, name: Symbol,
receiver: &'tcx hir::Expr<'tcx>, receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>], args: &'tcx [hir::Expr<'tcx>],
) { ) {
@@ -114,7 +114,7 @@ pub(super) fn check<'tcx>(
} }
} }
if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) { if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) {
return; return;
} }

View File

@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sym;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use super::EXTEND_WITH_DRAIN; use super::EXTEND_WITH_DRAIN;
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
if is_type_diagnostic_item(cx, ty, sym::Vec) if is_type_diagnostic_item(cx, ty, sym::Vec)
//check source object //check source object
&& let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind
&& src_method.ident.as_str() == "drain" && src_method.ident.name == sym::drain
&& let src_ty = cx.typeck_results().expr_ty(drain_vec) && let src_ty = cx.typeck_results().expr_ty(drain_vec)
//check if actual src type is mutable for code suggestion //check if actual src type is mutable for code suggestion
&& let immutable = src_ty.is_mutable_ptr() && let immutable = src_ty.is_mutable_ptr()

View File

@@ -1,15 +1,15 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::implements_trait; use clippy_utils::ty::implements_trait;
use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs}; use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::Symbol;
use super::IMPLICIT_CLONE; use super::IMPLICIT_CLONE;
pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& is_clone_like(cx, method_name, method_def_id) && is_clone_like(cx, method_name, method_def_id)
&& let return_type = cx.typeck_results().expr_ty(expr) && let return_type = cx.typeck_results().expr_ty(expr)
@@ -43,12 +43,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call /// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g., /// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
/// `is_to_owned_like` in `unnecessary_to_owned.rs`. /// `is_to_owned_like` in `unnecessary_to_owned.rs`.
pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool { pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool {
match method_name { match method_name {
"to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr),
"to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
"to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path),
"to_vec" => cx sym::to_vec => cx
.tcx .tcx
.impl_of_method(method_def_id) .impl_of_method(method_def_id)
.filter(|&impl_did| { .filter(|&impl_did| {

View File

@@ -5,11 +5,16 @@ use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::sym; use rustc_span::{Symbol, sym};
use super::ITER_CLONED_COLLECT; use super::ITER_CLONED_COLLECT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
method_name: Symbol,
expr: &hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>,
) {
let expr_ty = cx.typeck_results().expr_ty(expr); let expr_ty = cx.typeck_results().expr_ty(expr);
if is_type_diagnostic_item(cx, expr_ty, sym::Vec) if is_type_diagnostic_item(cx, expr_ty, sym::Vec)
&& let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)) && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))

View File

@@ -5,11 +5,11 @@ use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::{Symbol, sym};
use super::ITER_COUNT; use super::ITER_COUNT;
pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) { pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) {
let ty = cx.typeck_results().expr_ty(recv); let ty = cx.typeck_results().expr_ty(recv);
let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { let caller_type = if derefs_to_slice(cx, recv, ty).is_some() {
"slice" "slice"

View File

@@ -1,12 +1,12 @@
use super::ITER_KV_MAP; use super::ITER_KV_MAP;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::pat_is_wild;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{pat_is_wild, sym};
use rustc_hir::{Body, Expr, ExprKind, PatKind}; use rustc_hir::{Body, Expr, ExprKind, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::Symbol;
/// lint use of: /// lint use of:
/// ///
@@ -16,13 +16,13 @@ use rustc_span::sym;
/// on `HashMaps` and `BTreeMaps` in std /// on `HashMaps` and `BTreeMaps` in std
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
map_type: &'tcx str, // iter / into_iter map_type: Symbol, // iter / into_iter
expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v))
recv: &'tcx Expr<'tcx>, // hashmap recv: &'tcx Expr<'tcx>, // hashmap
m_arg: &'tcx Expr<'tcx>, // |(_, v)| v m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
msrv: Msrv, msrv: Msrv,
) { ) {
if map_type == "into_iter" && !msrv.meets(cx, msrvs::INTO_KEYS) { if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) {
return; return;
} }
if !expr.span.from_expansion() if !expr.span.from_expansion()
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(
{ {
let mut applicability = rustc_errors::Applicability::MachineApplicable; let mut applicability = rustc_errors::Applicability::MachineApplicable;
let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
let into_prefix = if map_type == "into_iter" { "into_" } else { "" }; let into_prefix = if map_type == sym::into_iter { "into_" } else { "" };
if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind
&& let [local_ident] = path.segments && let [local_ident] = path.segments

View File

@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sym;
use clippy_utils::ty::get_type_diagnostic_name; use clippy_utils::ty::get_type_diagnostic_name;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Span; use rustc_span::{Span, Symbol};
use rustc_span::symbol::sym;
use super::ITER_NTH; use super::ITER_NTH;
@@ -12,7 +12,7 @@ pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
iter_recv: &'tcx hir::Expr<'tcx>, iter_recv: &'tcx hir::Expr<'tcx>,
iter_method: &str, iter_method: Symbol,
iter_span: Span, iter_span: Span,
nth_span: Span, nth_span: Span,
) -> bool { ) -> bool {
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
expr.span, expr.span,
format!("called `.{iter_method}().nth()` on a {caller_type}"), format!("called `.{iter_method}().nth()` on a {caller_type}"),
|diag| { |diag| {
let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" }; let get_method = if iter_method == sym::iter_mut { "get_mut" } else { "get" };
diag.span_suggestion_verbose( diag.span_suggestion_verbose(
iter_span.to(nth_span), iter_span.to(nth_span),
format!("`{get_method}` is equivalent but more concise"), format!("`{get_method}` is equivalent but more concise"),

View File

@@ -2,7 +2,7 @@ use std::iter::once;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirId; use rustc_hir::hir_id::HirId;
use rustc_hir::{Expr, ExprKind, Node}; use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Symbol;
use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
@@ -51,7 +52,7 @@ fn is_arg_ty_unified_in_fn<'tcx>(
.any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args))) .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args)))
} }
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, recv: &'tcx Expr<'tcx>) {
let item = match recv.kind { let item = match recv.kind {
ExprKind::Array([]) => None, ExprKind::Array([]) => None,
ExprKind::Array([e]) => Some(e), ExprKind::Array([e]) => Some(e),
@@ -60,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method
_ => return, _ => return,
}; };
let iter_type = match method_name { let iter_type = match method_name {
"iter" => IterType::Iter, sym::iter => IterType::Iter,
"iter_mut" => IterType::IterMut, sym::iter_mut => IterType::IterMut,
"into_iter" => IterType::IntoIter, sym::into_iter => IterType::IntoIter,
_ => return, _ => return,
}; };

View File

@@ -8,7 +8,7 @@ use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, Pl
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::mir::{FakeReadCause, Mutability};
use rustc_middle::ty::{self, BorrowKind}; use rustc_middle::ty::{self, BorrowKind};
use rustc_span::sym; use rustc_span::{Symbol, sym};
use super::ITER_OVEREAGER_CLONED; use super::ITER_OVEREAGER_CLONED;
use crate::redundant_clone::REDUNDANT_CLONE; use crate::redundant_clone::REDUNDANT_CLONE;
@@ -26,7 +26,7 @@ pub(super) enum Op<'a> {
// later `.cloned()` // later `.cloned()`
// and add `&` to the parameter of closure parameter // and add `&` to the parameter of closure parameter
// e.g. `find` `filter` // e.g. `find` `filter`
FixClosure(&'a str, &'a Expr<'a>), FixClosure(Symbol, &'a Expr<'a>),
// later `.cloned()` // later `.cloned()`
// e.g. `skip` `take` // e.g. `skip` `take`

View File

@@ -168,7 +168,7 @@ fn rewrite_as_cstr(cx: &LateContext<'_>, span: Span) -> Option<String> {
fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
match &e.kind { match &e.kind {
ExprKind::MethodCall(method, receiver, [], _) if method.ident.as_str() == "cast" => Some(receiver), ExprKind::MethodCall(method, receiver, [], _) if method.ident.name == sym::cast => Some(receiver),
ExprKind::Cast(expr, _) => Some(expr), ExprKind::Cast(expr, _) => Some(expr),
_ => None, _ => None,
} }

View File

@@ -3,18 +3,18 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::get_field_by_name; use clippy_utils::ty::get_field_by_name;
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id}; use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_span::{DUMMY_SP, Span, Symbol};
use super::MANUAL_INSPECT; use super::MANUAL_INSPECT;
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: Msrv) { pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: Symbol, name_span: Span, msrv: Msrv) {
if let ExprKind::Closure(c) = arg.kind if let ExprKind::Closure(c) = arg.kind
&& matches!(c.kind, ClosureKind::Closure) && matches!(c.kind, ClosureKind::Closure)
&& let typeck = cx.typeck_results() && let typeck = cx.typeck_results()
@@ -168,8 +168,8 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
edits.extend(addr_of_edits); edits.extend(addr_of_edits);
} }
let edit = match name { let edit = match name {
"map" => "inspect", sym::map => "inspect",
"map_err" => "inspect_err", sym::map_err => "inspect_err",
_ => return, _ => return,
}; };
edits.push((name_span, edit.to_string())); edits.push((name_span, edit.to_string()));

View File

@@ -5,7 +5,7 @@ use rustc_ast::BindingMode;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{self as hir, Node, PatKind}; use rustc_hir::{self as hir, Node, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol, sym};
use super::MAP_IDENTITY; use super::MAP_IDENTITY;
@@ -14,7 +14,7 @@ pub(super) fn check(
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
caller: &hir::Expr<'_>, caller: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>,
name: &str, name: Symbol,
_map_span: Span, _map_span: Span,
) { ) {
let caller_ty = cx.typeck_results().expr_ty(caller); let caller_ty = cx.typeck_results().expr_ty(caller);

View File

@@ -150,7 +150,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::macros::FormatArgsStorage; use clippy_utils::macros::FormatArgsStorage;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym};
pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
use rustc_abi::ExternAbi; use rustc_abi::ExternAbi;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
@@ -159,7 +159,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_middle::ty::{self, TraitRef, Ty};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol, kw};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -4711,17 +4711,15 @@ impl_lint_pass!(Methods => [
/// Extracts a method call name, args, and `Span` of the method name. /// Extracts a method call name, args, and `Span` of the method name.
/// This ensures that neither the receiver nor any of the arguments /// This ensures that neither the receiver nor any of the arguments
/// come from expansion. /// come from expansion.
pub fn method_call<'tcx>( pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
recv: &'tcx Expr<'tcx>,
) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind
&& !args.iter().any(|e| e.span.from_expansion()) && !args.iter().any(|e| e.span.from_expansion())
&& !receiver.span.from_expansion() && !receiver.span.from_expansion()
{ {
let name = path.ident.name.as_str(); Some((path.ident.name, receiver, args, path.ident.span, call_span))
return Some((name, receiver, args, path.ident.span, call_span)); } else {
}
None None
}
} }
impl<'tcx> LateLintPass<'tcx> for Methods { impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -4743,13 +4741,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
}, },
ExprKind::MethodCall(method_call, receiver, args, _) => { ExprKind::MethodCall(method_call, receiver, args, _) => {
let method_span = method_call.ident.span; let method_span = method_call.ident.span;
or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); or_fun_call::check(cx, expr, method_span, method_call.ident.name, receiver, args);
expect_fun_call::check( expect_fun_call::check(
cx, cx,
&self.format_args, &self.format_args,
expr, expr,
method_span, method_span,
method_call.ident.as_str(), method_call.ident.name,
receiver, receiver,
args, args,
); );
@@ -4778,7 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if impl_item.span.in_external_macro(cx.sess().source_map()) { if impl_item.span.in_external_macro(cx.sess().source_map()) {
return; return;
} }
let name = impl_item.ident.name.as_str(); let name = impl_item.ident.name;
let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir_expect_item(parent); let item = cx.tcx.hir_expect_item(parent);
let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
@@ -4851,7 +4849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return; return;
} }
if name == "new" && ret_ty != self_ty { if name == sym::new && ret_ty != self_ty {
span_lint( span_lint(
cx, cx,
NEW_RET_NO_SELF, NEW_RET_NO_SELF,
@@ -4881,7 +4879,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
wrong_self_convention::check( wrong_self_convention::check(
cx, cx,
item.ident.name.as_str(), item.ident.name,
self_ty, self_ty,
first_arg_ty, first_arg_ty,
first_arg_hir_ty.span, first_arg_hir_ty.span,
@@ -4912,14 +4910,17 @@ impl Methods {
// Handle method calls whose receiver and arguments may not come from expansion // Handle method calls whose receiver and arguments may not come from expansion
if let Some((name, recv, args, span, call_span)) = method_call(expr) { if let Some((name, recv, args, span, call_span)) = method_call(expr) {
match (name, args) { match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { (
sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub,
[_arg],
) => {
zst_offset::check(cx, expr, recv); zst_offset::check(cx, expr, recv);
}, },
("all", [arg]) => { (sym::all, [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg); unused_enumerate_index::check(cx, expr, recv, arg);
needless_character_iteration::check(cx, expr, recv, arg, true); needless_character_iteration::check(cx, expr, recv, arg, true);
match method_call(recv) { match method_call(recv) {
Some(("cloned", recv2, [], _, _)) => { Some((sym::cloned, recv2, [], _, _)) => {
iter_overeager_cloned::check( iter_overeager_cloned::check(
cx, cx,
expr, expr,
@@ -4929,13 +4930,13 @@ impl Methods {
false, false,
); );
}, },
Some(("map", _, [map_arg], _, map_call_span)) => { Some((sym::map, _, [map_arg], _, map_call_span)) => {
map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all"); map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all");
}, },
_ => {}, _ => {},
} }
}, },
("and_then", [arg]) => { (sym::and_then, [arg]) => {
let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
if !biom_option_linted && !biom_result_linted { if !biom_option_linted && !biom_result_linted {
@@ -4945,11 +4946,11 @@ impl Methods {
} }
} }
}, },
("any", [arg]) => { (sym::any, [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg); unused_enumerate_index::check(cx, expr, recv, arg);
needless_character_iteration::check(cx, expr, recv, arg, false); needless_character_iteration::check(cx, expr, recv, arg, false);
match method_call(recv) { match method_call(recv) {
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
cx, cx,
expr, expr,
recv, recv,
@@ -4957,80 +4958,79 @@ impl Methods {
iter_overeager_cloned::Op::NeedlessMove(arg), iter_overeager_cloned::Op::NeedlessMove(arg),
false, false,
), ),
Some(("chars", recv, _, _, _)) Some((sym::chars, recv, _, _, _))
if let ExprKind::Closure(arg) = arg.kind if let ExprKind::Closure(arg) = arg.kind
&& let body = cx.tcx.hir_body(arg.body) && let body = cx.tcx.hir_body(arg.body)
&& let [param] = body.params => && let [param] = body.params =>
{ {
string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv); string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv);
}, },
Some(("map", _, [map_arg], _, map_call_span)) => { Some((sym::map, _, [map_arg], _, map_call_span)) => {
map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any"); map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any");
}, },
Some(("iter", iter_recv, ..)) => { Some((sym::iter, iter_recv, ..)) => {
manual_contains::check(cx, expr, iter_recv, arg); manual_contains::check(cx, expr, iter_recv, arg);
}, },
_ => {}, _ => {},
} }
}, },
("arg", [arg]) => { (sym::arg, [arg]) => {
suspicious_command_arg_space::check(cx, recv, arg, span); suspicious_command_arg_space::check(cx, recv, arg, span);
}, },
("as_deref" | "as_deref_mut", []) => { (sym::as_deref | sym::as_deref_mut, []) => {
needless_option_as_deref::check(cx, expr, recv, name); needless_option_as_deref::check(cx, expr, recv, name);
}, },
("as_bytes", []) => { (sym::as_bytes, []) => {
if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { if let Some((sym::as_str, recv, [], as_str_span, _)) = method_call(recv) {
redundant_as_str::check(cx, expr, recv, as_str_span, span); redundant_as_str::check(cx, expr, recv, as_str_span, span);
} }
sliced_string_as_bytes::check(cx, expr, recv); sliced_string_as_bytes::check(cx, expr, recv);
}, },
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), (sym::as_mut | sym::as_ref, []) => useless_asref::check(cx, expr, name, recv),
("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv), (sym::as_ptr, []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), (sym::assume_init, []) => uninit_assumed_init::check(cx, expr, recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), (sym::bytes, []) => unbuffered_bytes::check(cx, expr, recv),
("bytes", []) => unbuffered_bytes::check(cx, expr, recv), (sym::cloned, []) => {
("cloned", []) => {
cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv); cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv);
option_as_ref_cloned::check(cx, recv, span); option_as_ref_cloned::check(cx, recv, span);
}, },
("collect", []) if is_trait_method(cx, expr, sym::Iterator) => { (sym::collect, []) if is_trait_method(cx, expr, sym::Iterator) => {
needless_collect::check(cx, span, expr, recv, call_span); needless_collect::check(cx, span, expr, recv, call_span);
match method_call(recv) { match method_call(recv) {
Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => { Some((name @ (sym::cloned | sym::copied), recv2, [], _, _)) => {
iter_cloned_collect::check(cx, name, expr, recv2); iter_cloned_collect::check(cx, name, expr, recv2);
}, },
Some(("map", m_recv, [m_arg], m_ident_span, _)) => { Some((sym::map, m_recv, [m_arg], m_ident_span, _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg); map_collect_result_unit::check(cx, expr, m_recv, m_arg);
format_collect::check(cx, expr, m_arg, m_ident_span); format_collect::check(cx, expr, m_arg, m_ident_span);
}, },
Some(("take", take_self_arg, [take_arg], _, _)) => { Some((sym::take, take_self_arg, [take_arg], _, _)) => {
if self.msrv.meets(cx, msrvs::STR_REPEAT) { if self.msrv.meets(cx, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
} }
}, },
Some(("drain", recv, args, ..)) => { Some((sym::drain, recv, args, ..)) => {
drain_collect::check(cx, args, expr, recv); drain_collect::check(cx, args, expr, recv);
}, },
_ => {}, _ => {},
} }
}, },
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { (sym::count, []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
Some(("cloned", recv2, [], _, _)) => { Some((sym::cloned, recv2, [], _, _)) => {
iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false); iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false);
}, },
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => {
iter_count::check(cx, expr, recv2, name2); iter_count::check(cx, expr, recv2, name2);
}, },
Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg), Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg), Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {}, _ => {},
}, },
("min" | "max", [arg]) => { (sym::min | sym::max, [arg]) => {
unnecessary_min_or_max::check(cx, expr, name, recv, arg); unnecessary_min_or_max::check(cx, expr, name, recv, arg);
}, },
("drain", ..) => { (sym::drain, ..) => {
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id) if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
&& matches!(kind, StmtKind::Semi(_)) && matches!(kind, StmtKind::Semi(_))
&& args.len() <= 1 && args.len() <= 1
@@ -5040,31 +5040,31 @@ impl Methods {
iter_with_drain::check(cx, expr, recv, span, arg); iter_with_drain::check(cx, expr, recv, span, arg);
} }
}, },
("ends_with", [arg]) => { (sym::ends_with, [arg]) => {
if let ExprKind::MethodCall(.., span) = expr.kind { if let ExprKind::MethodCall(.., span) = expr.kind {
case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv); case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv);
} }
path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles); path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles);
}, },
("expect", [_]) => { (sym::expect, [_]) => {
match method_call(recv) { match method_call(recv) {
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), Some((sym::ok, recv, [], _, _)) => ok_expect::check(cx, expr, recv),
Some(("err", recv, [], err_span, _)) => { Some((sym::err, recv, [], err_span, _)) => {
err_expect::check(cx, expr, recv, span, err_span, self.msrv); err_expect::check(cx, expr, recv, span, err_span, self.msrv);
}, },
_ => {}, _ => {},
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("extend", [arg]) => { (sym::extend, [arg]) => {
string_extend_chars::check(cx, expr, recv, arg); string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg);
}, },
("filter", [arg]) => { (sym::filter, [arg]) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
// if `arg` has side-effect, the semantic will change // if `arg` has side-effect, the semantic will change
iter_overeager_cloned::check( iter_overeager_cloned::check(
cx, cx,
@@ -5080,8 +5080,8 @@ impl Methods {
iter_filter::check(cx, expr, arg, span); iter_filter::check(cx, expr, arg, span);
} }
}, },
("find", [arg]) => { (sym::find, [arg]) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
// if `arg` has side-effect, the semantic will change // if `arg` has side-effect, the semantic will change
iter_overeager_cloned::check( iter_overeager_cloned::check(
cx, cx,
@@ -5093,26 +5093,26 @@ impl Methods {
); );
} }
}, },
("filter_map", [arg]) => { (sym::filter_map, [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg); unused_enumerate_index::check(cx, expr, recv, arg);
unnecessary_filter_map::check(cx, expr, arg, name); unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_bool_then::check(cx, expr, arg, call_span); filter_map_bool_then::check(cx, expr, arg, call_span);
filter_map_identity::check(cx, expr, arg, span); filter_map_identity::check(cx, expr, arg, span);
}, },
("find_map", [arg]) => { (sym::find_map, [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg); unused_enumerate_index::check(cx, expr, recv, arg);
unnecessary_filter_map::check(cx, expr, arg, name); unnecessary_filter_map::check(cx, expr, arg, name);
}, },
("flat_map", [arg]) => { (sym::flat_map, [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg); unused_enumerate_index::check(cx, expr, recv, arg);
flat_map_identity::check(cx, expr, arg, span); flat_map_identity::check(cx, expr, arg, span);
flat_map_option::check(cx, expr, arg, span); flat_map_option::check(cx, expr, arg, span);
}, },
("flatten", []) => match method_call(recv) { (sym::flatten, []) => match method_call(recv) {
Some(("map", recv, [map_arg], map_span, _)) => { Some((sym::map, recv, [map_arg], map_span, _)) => {
map_flatten::check(cx, expr, recv, map_arg, map_span); map_flatten::check(cx, expr, recv, map_arg, map_span);
}, },
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
cx, cx,
expr, expr,
recv, recv,
@@ -5122,15 +5122,15 @@ impl Methods {
), ),
_ => {}, _ => {},
}, },
("fold", [init, acc]) => { (sym::fold, [init, acc]) => {
manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv); manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv);
unnecessary_fold::check(cx, expr, init, acc, span); unnecessary_fold::check(cx, expr, init, acc, span);
}, },
("for_each", [arg]) => { (sym::for_each, [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg); unused_enumerate_index::check(cx, expr, recv, arg);
match method_call(recv) { match method_call(recv) {
Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
cx, cx,
expr, expr,
recv, recv,
@@ -5141,44 +5141,44 @@ impl Methods {
_ => {}, _ => {},
} }
}, },
("get", [arg]) => { (sym::get, [arg]) => {
get_first::check(cx, expr, recv, arg); get_first::check(cx, expr, recv, arg);
get_last_with_len::check(cx, expr, recv, arg); get_last_with_len::check(cx, expr, recv, arg);
}, },
("get_or_insert_with", [arg]) => { (sym::get_or_insert_with, [arg]) => {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"); unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert");
}, },
("hash", [arg]) => { (sym::hash, [arg]) => {
unit_hash::check(cx, expr, recv, arg); unit_hash::check(cx, expr, recv, arg);
}, },
("is_empty", []) => { (sym::is_empty, []) => {
match method_call(recv) { match method_call(recv) {
Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) => { Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) => {
needless_as_bytes::check(cx, prev_method, "is_empty", prev_recv, expr.span); needless_as_bytes::check(cx, prev_method, name, prev_recv, expr.span);
}, },
Some(("as_str", recv, [], as_str_span, _)) => { Some((sym::as_str, recv, [], as_str_span, _)) => {
redundant_as_str::check(cx, expr, recv, as_str_span, span); redundant_as_str::check(cx, expr, recv, as_str_span, span);
}, },
_ => {}, _ => {},
} }
is_empty::check(cx, expr, recv); is_empty::check(cx, expr, recv);
}, },
("is_file", []) => filetype_is_file::check(cx, expr, recv), (sym::is_file, []) => filetype_is_file::check(cx, expr, recv),
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), (sym::is_digit, [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false), (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, call_span, true), (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true),
("iter" | "iter_mut" | "into_iter", []) => { (sym::iter | sym::iter_mut | sym::into_iter, []) => {
iter_on_single_or_empty_collections::check(cx, expr, name, recv); iter_on_single_or_empty_collections::check(cx, expr, name, recv);
}, },
("join", [join_arg]) => { (sym::join, [join_arg]) => {
if let Some(("collect", _, _, span, _)) = method_call(recv) { if let Some((sym::collect, _, _, span, _)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span); unnecessary_join::check(cx, expr, recv, join_arg, span);
} else { } else {
join_absolute_paths::check(cx, recv, join_arg, expr.span); join_absolute_paths::check(cx, recv, join_arg, expr.span);
} }
}, },
("last", []) => { (sym::last, []) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
iter_overeager_cloned::check( iter_overeager_cloned::check(
cx, cx,
expr, expr,
@@ -5190,24 +5190,24 @@ impl Methods {
} }
double_ended_iterator_last::check(cx, expr, recv, call_span); double_ended_iterator_last::check(cx, expr, recv, call_span);
}, },
("len", []) => { (sym::len, []) => {
if let Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) = method_call(recv) { if let Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) = method_call(recv) {
needless_as_bytes::check(cx, prev_method, "len", prev_recv, expr.span); needless_as_bytes::check(cx, prev_method, sym::len, prev_recv, expr.span);
} }
}, },
("lock", []) => { (sym::lock, []) => {
mut_mutex_lock::check(cx, expr, recv, span); mut_mutex_lock::check(cx, expr, recv, span);
}, },
(name @ ("map" | "map_err"), [m_arg]) => { (name @ (sym::map | sym::map_err), [m_arg]) => {
if name == "map" { if name == sym::map {
unused_enumerate_index::check(cx, expr, recv, m_arg); unused_enumerate_index::check(cx, expr, recv, m_arg);
map_clone::check(cx, expr, recv, m_arg, self.msrv); map_clone::check(cx, expr, recv, m_arg, self.msrv);
map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span); map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span);
match method_call(recv) { match method_call(recv) {
Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv); iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv);
}, },
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
cx, cx,
expr, expr,
recv, recv,
@@ -5222,12 +5222,12 @@ impl Methods {
} }
if let Some((name, recv2, args, span2, _)) = method_call(recv) { if let Some((name, recv2, args, span2, _)) = method_call(recv) {
match (name, args) { match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), (sym::as_mut, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), (sym::as_ref, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
("filter", [f_arg]) => { (sym::filter, [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
}, },
("find", [f_arg]) => { (sym::find, [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true); filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
}, },
_ => {}, _ => {},
@@ -5237,22 +5237,22 @@ impl Methods {
manual_inspect::check(cx, expr, m_arg, name, span, self.msrv); manual_inspect::check(cx, expr, m_arg, name, span, self.msrv);
crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
}, },
("map_break" | "map_continue", [m_arg]) => { (sym::map_break | sym::map_continue, [m_arg]) => {
crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
}, },
("map_or", [def, map]) => { (sym::map_or, [def, map]) => {
option_map_or_none::check(cx, expr, recv, def, map); option_map_or_none::check(cx, expr, recv, def, map);
manual_ok_or::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map);
unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv); unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv);
}, },
("map_or_else", [def, map]) => { (sym::map_or_else, [def, map]) => {
result_map_or_else_none::check(cx, expr, recv, def, map); result_map_or_else_none::check(cx, expr, recv, def, map);
unnecessary_result_map_or_else::check(cx, expr, recv, def, map); unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
}, },
("next", []) => { (sym::next, []) => {
if let Some((name2, recv2, args2, _, _)) = method_call(recv) { if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) { match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check( (sym::cloned, []) => iter_overeager_cloned::check(
cx, cx,
expr, expr,
recv, recv,
@@ -5260,19 +5260,19 @@ impl Methods {
iter_overeager_cloned::Op::LaterCloned, iter_overeager_cloned::Op::LaterCloned,
false, false,
), ),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), (sym::filter, [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), (sym::filter_map, [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2), (sym::iter, []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), (sym::skip, [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr), (sym::skip_while, [_]) => skip_while_next::check(cx, expr),
("rev", []) => manual_next_back::check(cx, expr, recv, recv2), (sym::rev, []) => manual_next_back::check(cx, expr, recv, recv2),
_ => {}, _ => {},
} }
} }
}, },
("nth", [n_arg]) => match method_call(recv) { (sym::nth, [n_arg]) => match method_call(recv) {
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), Some((sym::bytes, recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
cx, cx,
expr, expr,
recv, recv,
@@ -5280,54 +5280,54 @@ impl Methods {
iter_overeager_cloned::Op::LaterCloned, iter_overeager_cloned::Op::LaterCloned,
false, false,
), ),
Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => { Some((iter_method @ (sym::iter | sym::iter_mut), iter_recv, [], iter_span, _)) => {
if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) { if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) {
iter_nth_zero::check(cx, expr, recv, n_arg); iter_nth_zero::check(cx, expr, recv, n_arg);
} }
}, },
_ => iter_nth_zero::check(cx, expr, recv, n_arg), _ => iter_nth_zero::check(cx, expr, recv, n_arg),
}, },
("ok_or_else", [arg]) => { (sym::ok_or_else, [arg]) => {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
}, },
("open", [_]) => { (sym::open, [_]) => {
open_options::check(cx, expr, recv); open_options::check(cx, expr, recv);
}, },
("or_else", [arg]) => { (sym::or_else, [arg]) => {
if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) { if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
} }
}, },
("push", [arg]) => { (sym::push, [arg]) => {
path_buf_push_overwrite::check(cx, expr, arg); path_buf_push_overwrite::check(cx, expr, arg);
}, },
("read_to_end", [_]) => { (sym::read_to_end, [_]) => {
verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG); verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
}, },
("read_to_string", [_]) => { (sym::read_to_string, [_]) => {
verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
}, },
("read_line", [arg]) => { (sym::read_line, [arg]) => {
read_line_without_trim::check(cx, expr, recv, arg); read_line_without_trim::check(cx, expr, recv, arg);
}, },
("repeat", [arg]) => { (sym::repeat, [arg]) => {
repeat_once::check(cx, expr, recv, arg); repeat_once::check(cx, expr, recv, arg);
}, },
(name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => { (name @ (sym::replace | sym::replacen), [arg1, arg2] | [arg1, arg2, _]) => {
no_effect_replace::check(cx, expr, arg1, arg2); no_effect_replace::check(cx, expr, arg1, arg2);
// Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY)
&& name == "replace" && name == sym::replace
&& let Some(("replace", ..)) = method_call(recv) && let Some((sym::replace, ..)) = method_call(recv)
{ {
collapsible_str_replace::check(cx, expr, arg1, arg2); collapsible_str_replace::check(cx, expr, arg1, arg2);
} }
}, },
("resize", [count_arg, default_arg]) => { (sym::resize, [count_arg, default_arg]) => {
vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
}, },
("seek", [arg]) => { (sym::seek, [arg]) => {
if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) { if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) {
seek_from_current::check(cx, expr, recv, arg); seek_from_current::check(cx, expr, recv, arg);
} }
@@ -5335,11 +5335,11 @@ impl Methods {
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
} }
}, },
("skip", [arg]) => { (sym::skip, [arg]) => {
iter_skip_zero::check(cx, expr, arg); iter_skip_zero::check(cx, expr, arg);
iter_out_of_bounds::check_skip(cx, expr, recv, arg); iter_out_of_bounds::check_skip(cx, expr, recv, arg);
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
iter_overeager_cloned::check( iter_overeager_cloned::check(
cx, cx,
expr, expr,
@@ -5350,34 +5350,34 @@ impl Methods {
); );
} }
}, },
("sort", []) => { (sym::sort, []) => {
stable_sort_primitive::check(cx, expr, recv); stable_sort_primitive::check(cx, expr, recv);
}, },
("sort_by", [arg]) => { (sym::sort_by, [arg]) => {
unnecessary_sort_by::check(cx, expr, recv, arg, false); unnecessary_sort_by::check(cx, expr, recv, arg, false);
}, },
("sort_unstable_by", [arg]) => { (sym::sort_unstable_by, [arg]) => {
unnecessary_sort_by::check(cx, expr, recv, arg, true); unnecessary_sort_by::check(cx, expr, recv, arg, true);
}, },
("split", [arg]) => { (sym::split, [arg]) => {
str_split::check(cx, expr, recv, arg); str_split::check(cx, expr, recv, arg);
}, },
("splitn" | "rsplitn", [count_arg, pat_arg]) => { (sym::splitn | sym::rsplitn, [count_arg, pat_arg]) => {
if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count); suspicious_splitn::check(cx, name, expr, recv, count);
str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv); str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
} }
}, },
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { (sym::splitn_mut | sym::rsplitn_mut, [count_arg, _]) => {
if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count); suspicious_splitn::check(cx, name, expr, recv, count);
} }
}, },
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), (sym::step_by, [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [arg]) => { (sym::take, [arg]) => {
iter_out_of_bounds::check_take(cx, expr, recv, arg); iter_out_of_bounds::check_take(cx, expr, recv, arg);
manual_repeat_n::check(cx, expr, recv, arg, self.msrv); manual_repeat_n::check(cx, expr, recv, arg, self.msrv);
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
iter_overeager_cloned::check( iter_overeager_cloned::check(
cx, cx,
expr, expr,
@@ -5388,74 +5388,89 @@ impl Methods {
); );
} }
}, },
("take", []) => needless_option_take::check(cx, expr, recv), (sym::take, []) => needless_option_take::check(cx, expr, recv),
("then", [arg]) => { (sym::then, [arg]) => {
if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) {
return; return;
} }
unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
}, },
("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { (sym::try_into, []) if is_trait_method(cx, expr, sym::TryInto) => {
unnecessary_fallible_conversions::check_method(cx, expr); unnecessary_fallible_conversions::check_method(cx, expr);
}, },
("to_owned", []) => { (sym::to_owned, []) => {
if !suspicious_to_owned::check(cx, expr, recv) { if !suspicious_to_owned::check(cx, expr, recv) {
implicit_clone::check(cx, name, expr, recv); implicit_clone::check(cx, name, expr, recv);
} }
}, },
("to_os_string" | "to_path_buf" | "to_vec", []) => { (sym::to_os_string | sym::to_path_buf | sym::to_vec, []) => {
implicit_clone::check(cx, name, expr, recv); implicit_clone::check(cx, name, expr, recv);
}, },
("type_id", []) => { (sym::type_id, []) => {
type_id_on_box::check(cx, recv, expr.span); type_id_on_box::check(cx, recv, expr.span);
}, },
("unwrap", []) => { (sym::unwrap, []) => {
match method_call(recv) { match method_call(recv) {
Some(("get", recv, [get_arg], _, _)) => { Some((sym::get, recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false); get_unwrap::check(cx, expr, recv, get_arg, false);
}, },
Some(("get_mut", recv, [get_arg], _, _)) => { Some((sym::get_mut, recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true); get_unwrap::check(cx, expr, recv, get_arg, true);
}, },
Some(("or", recv, [or_arg], or_span, _)) => { Some((sym::or, recv, [or_arg], or_span, _)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span); or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
}, },
_ => {}, _ => {},
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("unwrap_or", [u_arg]) => { (sym::unwrap_or, [u_arg]) => {
match method_call(recv) { match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => { Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); manual_saturating_arithmetic::check(
cx,
expr,
lhs,
rhs,
u_arg,
&arith.as_str()[const { "checked_".len() }..],
);
}, },
Some(("map", m_recv, [m_arg], span, _)) => { Some((sym::map, m_recv, [m_arg], span, _)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv);
}, },
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or"); obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name);
}, },
_ => {}, _ => {},
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("unwrap_or_default", []) => { (sym::unwrap_or_default, []) => {
match method_call(recv) { match method_call(recv) {
Some(("map", m_recv, [arg], span, _)) => { Some((sym::map, m_recv, [arg], span, _)) => {
manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv);
}, },
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default"); obfuscated_if_else::check(
cx,
expr,
t_recv,
t_arg,
None,
then_method,
sym::unwrap_or_default,
);
}, },
_ => {}, _ => {},
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("unwrap_or_else", [u_arg]) => { (sym::unwrap_or_else, [u_arg]) => {
match method_call(recv) { match method_call(recv) {
Some(("map", recv, [map_arg], _, _)) Some((sym::map, recv, [map_arg], _, _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check( obfuscated_if_else::check(
cx, cx,
expr, expr,
@@ -5463,7 +5478,7 @@ impl Methods {
t_arg, t_arg,
Some(u_arg), Some(u_arg),
then_method, then_method,
"unwrap_or_else", sym::unwrap_or_else,
); );
}, },
_ => { _ => {
@@ -5472,13 +5487,13 @@ impl Methods {
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("wake", []) => { (sym::wake, []) => {
waker_clone_wake::check(cx, expr, recv); waker_clone_wake::check(cx, expr, recv);
}, },
("write", []) => { (sym::write, []) => {
readonly_write_lock::check(cx, expr, recv); readonly_write_lock::check(cx, expr, recv);
}, },
("zip", [arg]) => { (sym::zip, [arg]) => {
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
&& name.ident.name == sym::iter && name.ident.name == sym::iter
{ {
@@ -5490,8 +5505,8 @@ impl Methods {
} }
// Handle method calls whose receiver and arguments may come from expansion // Handle method calls whose receiver and arguments may come from expansion
if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
match (path.ident.name.as_str(), args) { match (path.ident.name, args) {
("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => { (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => {
unwrap_expect_used::check( unwrap_expect_used::check(
cx, cx,
expr, expr,
@@ -5502,7 +5517,7 @@ impl Methods {
unwrap_expect_used::Variant::Expect, unwrap_expect_used::Variant::Expect,
); );
}, },
("expect_err", [_]) => { (sym::expect_err, [_]) => {
unwrap_expect_used::check( unwrap_expect_used::check(
cx, cx,
expr, expr,
@@ -5513,7 +5528,7 @@ impl Methods {
unwrap_expect_used::Variant::Expect, unwrap_expect_used::Variant::Expect,
); );
}, },
("unwrap", []) => { (sym::unwrap, []) => {
unwrap_expect_used::check( unwrap_expect_used::check(
cx, cx,
expr, expr,
@@ -5524,7 +5539,7 @@ impl Methods {
unwrap_expect_used::Variant::Unwrap, unwrap_expect_used::Variant::Unwrap,
); );
}, },
("unwrap_err", []) => { (sym::unwrap_err, []) => {
unwrap_expect_used::check( unwrap_expect_used::check(
cx, cx,
expr, expr,
@@ -5543,13 +5558,13 @@ impl Methods {
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) { fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) {
match method_call(recv) { match method_call(recv) {
Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) => { Some((name @ (sym::find | sym::position | sym::rposition), f_recv, [arg], span, _)) => {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}, },
Some(("get", f_recv, [arg], _, _)) => { Some((sym::get, f_recv, [arg], _, _)) => {
unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some); unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some);
}, },
Some(("first", f_recv, [], _, _)) => { Some((sym::first, f_recv, [], _, _)) => {
unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some);
}, },
_ => {}, _ => {},
@@ -5593,7 +5608,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
struct ShouldImplTraitCase { struct ShouldImplTraitCase {
trait_name: &'static str, trait_name: &'static str,
method_name: &'static str, method_name: Symbol,
param_count: usize, param_count: usize,
fn_header: hir::FnHeader, fn_header: hir::FnHeader,
// implicit self kind expected (none, self, &self, ...) // implicit self kind expected (none, self, &self, ...)
@@ -5606,7 +5621,7 @@ struct ShouldImplTraitCase {
impl ShouldImplTraitCase { impl ShouldImplTraitCase {
const fn new( const fn new(
trait_name: &'static str, trait_name: &'static str,
method_name: &'static str, method_name: Symbol,
param_count: usize, param_count: usize,
fn_header: hir::FnHeader, fn_header: hir::FnHeader,
self_kind: SelfKind, self_kind: SelfKind,
@@ -5639,36 +5654,36 @@ impl ShouldImplTraitCase {
#[rustfmt::skip] #[rustfmt::skip]
const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Add", sym::add, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::convert::AsMut", sym::as_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), ShouldImplTraitCase::new("std::convert::AsRef", sym::as_ref, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::BitAnd", sym::bitand, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::BitOr", sym::bitor, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::BitXor", sym::bitxor, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), ShouldImplTraitCase::new("std::borrow::Borrow", sym::borrow, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::borrow::BorrowMut", sym::borrow_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), ShouldImplTraitCase::new("std::clone::Clone", sym::clone, 1, FN_HEADER, SelfKind::Ref, OutType::Any, true),
ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp, 2, FN_HEADER, SelfKind::Ref, OutType::Any, true),
ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), ShouldImplTraitCase::new("std::default::Default", kw::Default, 0, FN_HEADER, SelfKind::No, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), ShouldImplTraitCase::new("std::ops::Deref", sym::deref, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Div", sym::div, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), ShouldImplTraitCase::new("std::ops::Drop", sym::drop, 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true),
ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), ShouldImplTraitCase::new("std::cmp::PartialEq", sym::eq, 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true),
ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true), ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter, 1, FN_HEADER, SelfKind::No, OutType::Any, true),
ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true), ShouldImplTraitCase::new("std::str::FromStr", sym::from_str, 1, FN_HEADER, SelfKind::No, OutType::Any, true),
ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), ShouldImplTraitCase::new("std::hash::Hash", sym::hash, 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true),
ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), ShouldImplTraitCase::new("std::ops::Index", sym::index, 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::ops::IndexMut", sym::index_mut, 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter, 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Mul", sym::mul, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Neg", sym::neg, 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), ShouldImplTraitCase::new("std::iter::Iterator", sym::next, 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false),
ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Not", sym::not, 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Rem", sym::rem, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Shl", sym::shl, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Shr", sym::shr, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Sub", sym::sub, 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
]; ];
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]

View File

@@ -4,11 +4,11 @@ use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, LangItem}; use rustc_hir::{Expr, LangItem};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Span; use rustc_span::{Span, Symbol};
use super::NEEDLESS_AS_BYTES; use super::NEEDLESS_AS_BYTES;
pub fn check(cx: &LateContext<'_>, prev_method: &str, method: &str, prev_recv: &Expr<'_>, span: Span) { pub fn check(cx: &LateContext<'_>, prev_method: Symbol, method: Symbol, prev_recv: &Expr<'_>, span: Span) {
let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs(); let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs();
if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() { if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() {
let mut app = Applicability::MachineApplicable; let mut app = Applicability::MachineApplicable;

View File

@@ -1,22 +1,22 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::path_res;
use clippy_utils::source::SpanRangeExt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::local_used_after_expr; use clippy_utils::usage::local_used_after_expr;
use clippy_utils::{path_res, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::Symbol;
use super::NEEDLESS_OPTION_AS_DEREF; use super::NEEDLESS_OPTION_AS_DEREF;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: Symbol) {
let typeck = cx.typeck_results(); let typeck = cx.typeck_results();
let outer_ty = typeck.expr_ty(expr); let outer_ty = typeck.expr_ty(expr);
if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) { if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
if name == "as_deref_mut" && recv.is_syntactic_place_expr() { if name == sym::as_deref_mut && recv.is_syntactic_place_expr() {
let Res::Local(binding_id) = path_res(cx, recv) else { let Res::Local(binding_id) = path_res(cx, recv) else {
return; return;
}; };

View File

@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath}; use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::{Symbol, sym};
use super::NEEDLESS_OPTION_TAKE; use super::NEEDLESS_OPTION_TAKE;
@@ -42,20 +42,20 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// When this function is called, we are reasonably certain that the `ExprKind` is either /// When this function is called, we are reasonably certain that the `ExprKind` is either
/// `Call` or `MethodCall` because we already checked that the expression is not /// `Call` or `MethodCall` because we already checked that the expression is not
/// `is_syntactic_place_expr()`. /// `is_syntactic_place_expr()`.
fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> { fn source_of_temporary_value(expr: &Expr<'_>) -> Option<Symbol> {
match expr.peel_borrows().kind { match expr.peel_borrows().kind {
ExprKind::Call(function, _) => { ExprKind::Call(function, _) => {
if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind
&& !func_path.segments.is_empty() && !func_path.segments.is_empty()
{ {
return Some(func_path.segments[0].ident.name.as_str()); return Some(func_path.segments[0].ident.name);
} }
if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind { if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind {
return Some(func_path_segment.ident.name.as_str()); return Some(func_path_segment.ident.name);
} }
None None
}, },
ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name.as_str()), ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name),
_ => None, _ => None,
} }
} }

View File

@@ -1,13 +1,14 @@
use super::OBFUSCATED_IF_ELSE; use super::OBFUSCATED_IF_ELSE;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::ExprKind; use rustc_hir::ExprKind;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Symbol;
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
@@ -15,8 +16,8 @@ pub(super) fn check<'tcx>(
then_recv: &'tcx hir::Expr<'_>, then_recv: &'tcx hir::Expr<'_>,
then_arg: &'tcx hir::Expr<'_>, then_arg: &'tcx hir::Expr<'_>,
unwrap_arg: Option<&'tcx hir::Expr<'_>>, unwrap_arg: Option<&'tcx hir::Expr<'_>>,
then_method_name: &str, then_method_name: Symbol,
unwrap_method_name: &str, unwrap_method_name: Symbol,
) { ) {
let recv_ty = cx.typeck_results().expr_ty(then_recv); let recv_ty = cx.typeck_results().expr_ty(then_recv);
@@ -31,25 +32,25 @@ pub(super) fn check<'tcx>(
}; };
let if_then = match then_method_name { let if_then = match then_method_name {
"then" if let ExprKind::Closure(closure) = then_arg.kind => { sym::then if let ExprKind::Closure(closure) = then_arg.kind => {
let body = cx.tcx.hir_body(closure.body); let body = cx.tcx.hir_body(closure.body);
snippet_with_applicability(cx, body.value.span, "..", &mut applicability) snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
}, },
"then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
_ => return, _ => return,
}; };
// FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
let els = match unwrap_method_name { let els = match unwrap_method_name {
"unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability), sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
"unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => { sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
let body = cx.tcx.hir_body(closure.body); let body = cx.tcx.hir_body(closure.body);
snippet_with_applicability(cx, body.value.span, "..", &mut applicability) snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
}, },
"unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => { sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()" snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
}, },
"unwrap_or_default" => "Default::default()".into(), sym::unwrap_or_default => "Default::default()".into(),
_ => return, _ => return,
}; };

View File

@@ -1,14 +1,16 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sym;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::{Span, sym}; use rustc_span::Span;
use super::{OPTION_AS_REF_CLONED, method_call}; use super::{OPTION_AS_REF_CLONED, method_call};
pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) {
if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) if let Some((method @ (sym::as_ref | sym::as_mut), as_ref_recv, [], as_ref_ident_span, _)) =
method_call(cloned_recv)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option)
{ {
span_lint_and_sugg( span_lint_and_sugg(

View File

@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
method_span: Span, method_span: Span,
name: &str, name: Symbol,
receiver: &'tcx hir::Expr<'_>, receiver: &'tcx hir::Expr<'_>,
args: &'tcx [hir::Expr<'_>], args: &'tcx [hir::Expr<'_>],
) { ) {
@@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
/// `or_insert_with(T::new)` or `or_insert_with(T::default)`. /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
fn check_unwrap_or_default( fn check_unwrap_or_default(
cx: &LateContext<'_>, cx: &LateContext<'_>,
name: &str, name: Symbol,
receiver: &hir::Expr<'_>, receiver: &hir::Expr<'_>,
fun: &hir::Expr<'_>, fun: &hir::Expr<'_>,
call_expr: Option<&hir::Expr<'_>>, call_expr: Option<&hir::Expr<'_>>,
@@ -66,8 +66,8 @@ pub(super) fn check<'tcx>(
}; };
let sugg = match (name, call_expr.is_some()) { let sugg = match (name, call_expr.is_some()) {
("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default, (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default,
("or_insert", true) | ("or_insert_with", false) => sym::or_default, (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default,
_ => return false, _ => return false,
}; };
@@ -126,7 +126,7 @@ pub(super) fn check<'tcx>(
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
fn check_or_fn_call<'tcx>( fn check_or_fn_call<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
name: &str, name: Symbol,
method_span: Span, method_span: Span,
self_expr: &hir::Expr<'_>, self_expr: &hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>,
@@ -137,11 +137,16 @@ pub(super) fn check<'tcx>(
fun_span: Option<Span>, fun_span: Option<Span>,
) -> bool { ) -> bool {
// (path, fn_has_argument, methods, suffix) // (path, fn_has_argument, methods, suffix)
const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [ const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [
(sym::BTreeEntry, false, &["or_insert"], "with"), (sym::BTreeEntry, false, &[sym::or_insert], "with"),
(sym::HashMapEntry, false, &["or_insert"], "with"), (sym::HashMapEntry, false, &[sym::or_insert], "with"),
(sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), (
(sym::Result, true, &["or", "unwrap_or"], "else"), sym::Option,
false,
&[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or],
"else",
),
(sym::Result, true, &[sym::or, sym::unwrap_or], "else"),
]; ];
if KNOW_TYPES.iter().any(|k| k.2.contains(&name)) if KNOW_TYPES.iter().any(|k| k.2.contains(&name))

View File

@@ -2,14 +2,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::deref_closure_args; use clippy_utils::sugg::deref_closure_args;
use clippy_utils::ty::is_type_lang_item; use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs}; use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs, sym};
use hir::ExprKind; use hir::ExprKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::PatKind; use rustc_hir::PatKind;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Span; use rustc_span::{Span, Symbol};
use rustc_span::symbol::sym;
use super::SEARCH_IS_SOME; use super::SEARCH_IS_SOME;
@@ -19,7 +18,7 @@ use super::SEARCH_IS_SOME;
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'_>, cx: &LateContext<'_>,
expr: &'tcx hir::Expr<'_>, expr: &'tcx hir::Expr<'_>,
search_method: &str, search_method: Symbol,
is_some: bool, is_some: bool,
search_recv: &hir::Expr<'_>, search_recv: &hir::Expr<'_>,
search_arg: &'tcx hir::Expr<'_>, search_arg: &'tcx hir::Expr<'_>,
@@ -35,7 +34,7 @@ pub(super) fn check<'tcx>(
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let any_search_snippet = if search_method == "find" let any_search_snippet = if search_method == sym::find
&& let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
&& let closure_body = cx.tcx.hir_body(body) && let closure_body = cx.tcx.hir_body(body)
&& let Some(closure_arg) = closure_body.params.first() && let Some(closure_arg) = closure_body.params.first()
@@ -107,7 +106,7 @@ pub(super) fn check<'tcx>(
} }
} }
// lint if `find()` is called by `String` or `&str` // lint if `find()` is called by `String` or `&str`
else if search_method == "find" { else if search_method == sym::find {
let is_string_or_str_slice = |e| { let is_string_or_str_slice = |e| {
let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
if is_type_lang_item(cx, self_ty, hir::LangItem::String) { if is_type_lang_item(cx, self_ty, hir::LangItem::String) {

View File

@@ -15,7 +15,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'
// or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most
// basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind
&& trim_method_name.ident.as_str() == "trim" && trim_method_name.ident.name == sym::trim
&& cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str() && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str()
&& !is_const_evaluatable(cx, trim_recv) && !is_const_evaluatable(cx, trim_recv)
&& let ExprKind::Lit(split_lit) = split_arg.kind && let ExprKind::Lit(split_lit) = split_arg.kind

View File

@@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::usage::local_used_after_expr; use clippy_utils::usage::local_used_after_expr;
use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::visitors::{Descend, for_each_expr};
use clippy_utils::{is_diag_item_method, path_to_local_id, paths}; use clippy_utils::{is_diag_item_method, path_to_local_id, paths, sym};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{ use rustc_hir::{
@@ -12,13 +12,13 @@ use rustc_hir::{
}; };
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::{Span, Symbol, SyntaxContext, sym}; use rustc_span::{Span, Symbol, SyntaxContext};
use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
pub(super) fn check( pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
method_name: &str, method_name: Symbol,
expr: &Expr<'_>, expr: &Expr<'_>,
self_arg: &Expr<'_>, self_arg: &Expr<'_>,
pat_arg: &Expr<'_>, pat_arg: &Expr<'_>,
@@ -45,9 +45,9 @@ pub(super) fn check(
} }
} }
fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { fn lint_needless(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
let mut app = Applicability::MachineApplicable; let mut app = Applicability::MachineApplicable;
let r = if method_name == "splitn" { "" } else { "r" }; let r = if method_name == sym::splitn { "" } else { "r" };
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@@ -66,14 +66,14 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_
fn check_manual_split_once( fn check_manual_split_once(
cx: &LateContext<'_>, cx: &LateContext<'_>,
method_name: &str, method_name: Symbol,
expr: &Expr<'_>, expr: &Expr<'_>,
self_arg: &Expr<'_>, self_arg: &Expr<'_>,
pat_arg: &Expr<'_>, pat_arg: &Expr<'_>,
usage: &IterUsage, usage: &IterUsage,
) { ) {
let ctxt = expr.span.ctxt(); let ctxt = expr.span.ctxt();
let (msg, reverse) = if method_name == "splitn" { let (msg, reverse) = if method_name == sym::splitn {
("manual implementation of `split_once`", false) ("manual implementation of `split_once`", false)
} else { } else {
("manual implementation of `rsplit_once`", true) ("manual implementation of `rsplit_once`", true)
@@ -121,7 +121,7 @@ fn check_manual_split_once(
/// ``` /// ```
fn check_manual_split_once_indirect( fn check_manual_split_once_indirect(
cx: &LateContext<'_>, cx: &LateContext<'_>,
method_name: &str, method_name: Symbol,
expr: &Expr<'_>, expr: &Expr<'_>,
self_arg: &Expr<'_>, self_arg: &Expr<'_>,
pat_arg: &Expr<'_>, pat_arg: &Expr<'_>,
@@ -143,7 +143,7 @@ fn check_manual_split_once_indirect(
&& first.name != second.name && first.name != second.name
&& !local_used_after_expr(cx, iter_binding_id, second.init_expr) && !local_used_after_expr(cx, iter_binding_id, second.init_expr)
{ {
let (r, lhs, rhs) = if method_name == "splitn" { let (r, lhs, rhs) = if method_name == sym::splitn {
("", first.name, second.name) ("", first.name, second.name)
} else { } else {
("r", second.name, first.name) ("r", second.name, first.name)

View File

@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_lang_item; use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{method_chain_args, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) { if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) {
return; return;
} }
if let Some(arglists) = method_chain_args(arg, &["chars"]) { if let Some(arglists) = method_chain_args(arg, &[sym::chars]) {
let target = &arglists[0].0; let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if self_ty.is_str() { let ref_str = if self_ty.is_str() {

View File

@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_note;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Symbol;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use super::SUSPICIOUS_SPLITN; use super::SUSPICIOUS_SPLITN;
pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
if count <= 1 if count <= 1
&& let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(call_id) && let Some(impl_id) = cx.tcx.impl_of_method(call_id)

View File

@@ -9,10 +9,16 @@ use rustc_hir as hir;
use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::Symbol;
use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) { pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
arg: &'tcx hir::Expr<'tcx>,
name: Symbol,
) {
if !is_trait_method(cx, expr, sym::Iterator) { if !is_trait_method(cx, expr, sym::Iterator) {
return; return;
} }
@@ -38,7 +44,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
let sugg = if !found_filtering { let sugg = if !found_filtering {
// Check if the closure is .filter_map(|x| Some(x)) // Check if the closure is .filter_map(|x| Some(x))
if name == "filter_map" if name == sym::filter_map
&& let hir::ExprKind::Call(expr, args) = body.value.kind && let hir::ExprKind::Call(expr, args) = body.value.kind
&& is_res_lang_ctor(cx, path_res(cx, expr), OptionSome) && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome)
&& let hir::ExprKind::Path(_) = args[0].kind && let hir::ExprKind::Path(_) = args[0].kind
@@ -51,7 +57,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
); );
return; return;
} }
if name == "filter_map" { if name == sym::filter_map {
"map(..)" "map(..)"
} else { } else {
"map(..).next()" "map(..).next()"
@@ -61,7 +67,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
ty::Adt(adt, subst) ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
{ {
if name == "filter_map" { "filter(..)" } else { "find(..)" } if name == sym::filter_map {
"filter(..)"
} else {
"find(..)"
}
}, },
_ => return, _ => return,
} }
@@ -70,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
}; };
span_lint( span_lint(
cx, cx,
if name == "filter_map" { if name == sym::filter_map {
UNNECESSARY_FILTER_MAP UNNECESSARY_FILTER_MAP
} else { } else {
UNNECESSARY_FIND_MAP UNNECESSARY_FIND_MAP

View File

@@ -1,10 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res}; use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{self as hir, AmbigArg}; use rustc_hir::{self as hir, AmbigArg};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_span::Symbol;
use super::UNNECESSARY_LITERAL_UNWRAP; use super::UNNECESSARY_LITERAL_UNWRAP;
@@ -25,7 +26,7 @@ pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
recv: &hir::Expr<'_>, recv: &hir::Expr<'_>,
method: &str, method: Symbol,
args: &[hir::Expr<'_>], args: &[hir::Expr<'_>],
) { ) {
let init = clippy_utils::expr_or_init(cx, recv); let init = clippy_utils::expr_or_init(cx, recv);
@@ -42,17 +43,17 @@ pub(super) fn check(
let res = cx.qpath_res(qpath, call.hir_id()); let res = cx.qpath_res(qpath, call.hir_id());
if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) { if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) {
("Some", call_args, get_ty_from_args(args, 0)) (sym::Some, call_args, get_ty_from_args(args, 0))
} else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) { } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) {
("Ok", call_args, get_ty_from_args(args, 0)) (sym::Ok, call_args, get_ty_from_args(args, 0))
} else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) { } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) {
("Err", call_args, get_ty_from_args(args, 1)) (sym::Err, call_args, get_ty_from_args(args, 1))
} else { } else {
return; return;
} }
} else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) { } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) {
let call_args: &[hir::Expr<'_>] = &[]; let call_args: &[hir::Expr<'_>] = &[];
("None", call_args, None) (sym::None, call_args, None)
} else { } else {
return; return;
}; };
@@ -62,12 +63,12 @@ pub(super) fn check(
span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| { span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| {
let suggestions = match (constructor, method, ty) { let suggestions = match (constructor, method, ty) {
("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), (sym::None, sym::unwrap, _) => Some(vec![(expr.span, "panic!()".to_string())]),
("None", "expect", _) => Some(vec![ (sym::None, sym::expect, _) => Some(vec![
(expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
(expr.span.with_lo(args[0].span.hi()), ")".to_string()), (expr.span.with_lo(args[0].span.hi()), ")".to_string()),
]), ]),
("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => { (sym::Some | sym::Ok, sym::unwrap_unchecked, _) | (sym::Err, sym::unwrap_err_unchecked, _) => {
let mut suggs = vec![ let mut suggs = vec![
(recv.span.with_hi(call_args[0].span.lo()), String::new()), (recv.span.with_hi(call_args[0].span.lo()), String::new()),
(expr.span.with_lo(call_args[0].span.hi()), String::new()), (expr.span.with_lo(call_args[0].span.hi()), String::new()),
@@ -83,7 +84,7 @@ pub(super) fn check(
} }
Some(suggs) Some(suggs)
}, },
("None", "unwrap_or_default", _) => { (sym::None, sym::unwrap_or_default, _) => {
let ty = cx.typeck_results().expr_ty(expr); let ty = cx.typeck_results().expr_ty(expr);
let default_ty_string = if let ty::Adt(def, ..) = ty.kind() { let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did()))) with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
@@ -92,11 +93,11 @@ pub(super) fn check(
}; };
Some(vec![(expr.span, format!("{default_ty_string}::default()"))]) Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
}, },
("None", "unwrap_or", _) => Some(vec![ (sym::None, sym::unwrap_or, _) => Some(vec![
(expr.span.with_hi(args[0].span.lo()), String::new()), (expr.span.with_hi(args[0].span.lo()), String::new()),
(expr.span.with_lo(args[0].span.hi()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()),
]), ]),
("None", "unwrap_or_else", _) => match args[0].kind { (sym::None, sym::unwrap_or_else, _) => match args[0].kind {
hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
(expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()), (expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()),
(expr.span.with_lo(args[0].span.hi()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()),
@@ -105,14 +106,14 @@ pub(super) fn check(
}, },
_ if call_args.is_empty() => None, _ if call_args.is_empty() => None,
(_, _, Some(_)) => None, (_, _, Some(_)) => None,
("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ (sym::Ok, sym::unwrap_err, None) | (sym::Err, sym::unwrap, None) => Some(vec![
( (
recv.span.with_hi(call_args[0].span.lo()), recv.span.with_hi(call_args[0].span.lo()),
"panic!(\"{:?}\", ".to_string(), "panic!(\"{:?}\", ".to_string(),
), ),
(expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()),
]), ]),
("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![ (sym::Ok, sym::expect_err, None) | (sym::Err, sym::expect, None) => Some(vec![
( (
recv.span.with_hi(call_args[0].span.lo()), recv.span.with_hi(call_args[0].span.lo()),
"panic!(\"{1}: {:?}\", ".to_string(), "panic!(\"{1}: {:?}\", ".to_string(),

View File

@@ -5,16 +5,17 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::sym;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol};
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>,
name: &str, name: Symbol,
recv: &'tcx Expr<'_>, recv: &'tcx Expr<'_>,
arg: &'tcx Expr<'_>, arg: &'tcx Expr<'_>,
) { ) {
@@ -47,10 +48,10 @@ pub(super) fn check<'tcx>(
} }
} }
fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: Symbol, lhs: Span, rhs: Span, order: Ordering) {
let cmp_str = if order.is_ge() { "smaller" } else { "greater" }; let cmp_str = if order.is_ge() { "smaller" } else { "greater" };
let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) { let suggested_value = if (name == sym::min && order.is_ge()) || (name == sym::max && order.is_le()) {
snippet(cx, rhs, "..") snippet(cx, rhs, "..")
} else { } else {
snippet(cx, lhs, "..") snippet(cx, lhs, "..")

View File

@@ -619,7 +619,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
/// Returns true if the named method can be used to convert the receiver to its "owned" /// Returns true if the named method can be used to convert the receiver to its "owned"
/// representation. /// representation.
fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
is_clone_like(cx, method_name.as_str(), method_def_id) is_clone_like(cx, method_name, method_def_id)
|| is_cow_into_owned(cx, method_name, method_def_id) || is_cow_into_owned(cx, method_name, method_def_id)
|| is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
} }
@@ -686,11 +686,11 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = arg.kind if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = arg.kind
&& let ExprKind::MethodCall(method_path, caller, &[], _) = expr.kind && let ExprKind::MethodCall(method_path, caller, &[], _) = expr.kind
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let method_name = method_path.ident.name.as_str() && let method_name = method_path.ident.name
&& match method_name { && match method_name {
"to_owned" => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id), sym::to_owned => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id),
"to_string" => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id), sym::to_string => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id),
"to_vec" => cx sym::to_vec => cx
.tcx .tcx
.impl_of_method(method_def_id) .impl_of_method(method_def_id)
.filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice()) .filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice())

View File

@@ -7,7 +7,7 @@ use rustc_hir::{self as hir, LangItem};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol, sym};
use core::ops::ControlFlow; use core::ops::ControlFlow;
@@ -39,7 +39,7 @@ fn get_enum_ty(enum_ty: Ty<'_>) -> Option<Ty<'_>> {
} }
/// Checks for the `USELESS_ASREF` lint. /// Checks for the `USELESS_ASREF` lint.
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbol, recvr: &hir::Expr<'_>) {
// when we get here, we've already checked that the call name is "as_ref" or "as_mut" // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
// check if the call is to the actual `AsRef` or `AsMut` trait // check if the call is to the actual `AsRef` or `AsMut` trait
let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
@@ -161,7 +161,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
} }
} }
fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: &str) { fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: Symbol) {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,

View File

@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_copy; use clippy_utils::ty::is_copy;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_span::Span; use rustc_span::{Span, Symbol};
use std::fmt; use std::fmt;
use super::WRONG_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION;
@@ -83,17 +83,18 @@ impl fmt::Display for Convention {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
item_name: &str, item_name: Symbol,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
first_arg_ty: Ty<'tcx>, first_arg_ty: Ty<'tcx>,
first_arg_span: Span, first_arg_span: Span,
implements_trait: bool, implements_trait: bool,
is_trait_item: bool, is_trait_item: bool,
) { ) {
let item_name_str = item_name.as_str();
if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
convs convs
.iter() .iter()
.all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item)) .all(|conv| conv.check(cx, self_ty, item_name_str, implements_trait, is_trait_item))
}) { }) {
// don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032) // don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032)
if implements_trait if implements_trait

View File

@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{ use clippy_utils::{
SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt,
is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, sym,
}; };
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@@ -320,7 +320,7 @@ fn check_comparison<'a, 'tcx>(
cx.typeck_results().expr_ty(left_side), cx.typeck_results().expr_ty(left_side),
cx.typeck_results().expr_ty(right_side), cx.typeck_results().expr_ty(right_side),
); );
if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() { if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() {
return; return;
} }
if l_ty.is_bool() && r_ty.is_bool() { if l_ty.is_bool() && r_ty.is_bool() {

View File

@@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
} }
if is_type_diagnostic_item(cx, ty, sym::Vec) if is_type_diagnostic_item(cx, ty, sym::Vec)
&& let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]) && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[(sym::clone, ".to_owned()")])
&& let TyKind::Path(QPath::Resolved(_, path)) = input.kind && let TyKind::Path(QPath::Resolved(_, path)) = input.kind
&& let Some(elem_ty) = path && let Some(elem_ty) = path
.segments .segments
@@ -253,8 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
} }
if is_type_lang_item(cx, ty, LangItem::String) if is_type_lang_item(cx, ty, LangItem::String)
&& let Some(clone_spans) = && let Some(clone_spans) = get_spans(
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) cx,
Some(body.id()),
idx,
&[(sym::clone, ".to_string()"), (sym::as_str, "")],
)
{ {
diag.span_suggestion( diag.span_suggestion(
input.span, input.span,

View File

@@ -1,11 +1,11 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sym;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym;
use super::DURATION_SUBSEC; use super::DURATION_SUBSEC;
@@ -21,9 +21,9 @@ pub(crate) fn check<'tcx>(
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
&& let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right) && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right)
{ {
let suggested_fn = match (method_path.ident.as_str(), divisor) { let suggested_fn = match (method_path.ident.name, divisor) {
("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", (sym::subsec_micros, 1_000) | (sym::subsec_nanos, 1_000_000) => "subsec_millis",
("subsec_nanos", 1_000) => "subsec_micros", (sym::subsec_nanos, 1_000) => "subsec_micros",
_ => return, _ => return,
}; };
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;

View File

@@ -37,7 +37,7 @@ impl EarlyLintPass for OptionEnvUnwrap {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind
&& matches!(seg.ident.name, sym::expect | sym::unwrap) && matches!(seg.ident.name, sym::expect | sym::unwrap)
&& is_direct_expn_of(receiver.span, "option_env").is_some() && is_direct_expn_of(receiver.span, sym::option_env).is_some()
{ {
span_lint_and_help( span_lint_and_help(
cx, cx,

View File

@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{indent_of, snippet}; use clippy_utils::source::{indent_of, snippet};
use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary, sym};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_middle::ty::{GenericArgKind, Ty};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{DUMMY_SP, Span, sym}; use rustc_span::{DUMMY_SP, Span};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@@ -169,7 +169,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
let mut iter = get_attr( let mut iter = get_attr(
self.cx.sess(), self.cx.sess(),
self.cx.tcx.get_attrs_unchecked(adt.did()), self.cx.tcx.get_attrs_unchecked(adt.did()),
"has_significant_drop", sym::has_significant_drop,
); );
if iter.next().is_some() { if iter.next().is_some() {
return true; return true;

View File

@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::sym;
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::sym; use rustc_span::Symbol;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -62,17 +63,17 @@ fn get_pointee_ty_and_count_expr<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>,
) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
const METHODS: [&str; 10] = [ const METHODS: [Symbol; 10] = [
"copy_to", sym::copy_to,
"copy_from", sym::copy_from,
"copy_to_nonoverlapping", sym::copy_to_nonoverlapping,
"copy_from_nonoverlapping", sym::copy_from_nonoverlapping,
"add", sym::add,
"wrapping_add", sym::wrapping_add,
"sub", sym::sub,
"wrapping_sub", sym::wrapping_sub,
"offset", sym::offset,
"wrapping_offset", sym::wrapping_offset,
]; ];
if let ExprKind::Call(func, [.., count]) = expr.kind if let ExprKind::Call(func, [.., count]) = expr.kind
@@ -97,7 +98,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
} }
if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
// Find calls to copy_{from,to}{,_nonoverlapping} // Find calls to copy_{from,to}{,_nonoverlapping}
&& let method_ident = method_path.ident.as_str() && let method_ident = method_path.ident.name
&& METHODS.contains(&method_ident) && METHODS.contains(&method_ident)
// Get the pointee type // Get the pointee type

View File

@@ -266,7 +266,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
// If we have a size expression, check that it is equal to what's passed to `resize` // If we have a size expression, check that it is equal to what's passed to `resize`
SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
|| matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity") || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity)
} else { } else {
self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
true true
@@ -288,7 +288,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
// Check that len expression is equals to `with_capacity` expression // Check that len expression is equals to `with_capacity` expression
return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
|| matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity"); || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity);
} }
self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);

View File

@@ -5,9 +5,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::macros::matching_root_macro_call; use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::path_to_local_id;
use clippy_utils::source::{snippet, str_literal_to_char_literal}; use clippy_utils::source::{snippet, str_literal_to_char_literal};
use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::visitors::{Descend, for_each_expr};
use clippy_utils::{path_to_local_id, sym};
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::{BinOpKind, LitKind}; use rustc_ast::{BinOpKind, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -83,29 +83,29 @@ impl StringPatterns {
impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]);
const PATTERN_METHODS: [(&str, usize); 22] = [ const PATTERN_METHODS: [(Symbol, usize); 22] = [
("contains", 0), (sym::contains, 0),
("starts_with", 0), (sym::starts_with, 0),
("ends_with", 0), (sym::ends_with, 0),
("find", 0), (sym::find, 0),
("rfind", 0), (sym::rfind, 0),
("split", 0), (sym::split, 0),
("split_inclusive", 0), (sym::split_inclusive, 0),
("rsplit", 0), (sym::rsplit, 0),
("split_terminator", 0), (sym::split_terminator, 0),
("rsplit_terminator", 0), (sym::rsplit_terminator, 0),
("splitn", 1), (sym::splitn, 1),
("rsplitn", 1), (sym::rsplitn, 1),
("split_once", 0), (sym::split_once, 0),
("rsplit_once", 0), (sym::rsplit_once, 0),
("matches", 0), (sym::matches, 0),
("rmatches", 0), (sym::rmatches, 0),
("match_indices", 0), (sym::match_indices, 0),
("rmatch_indices", 0), (sym::rmatch_indices, 0),
("trim_start_matches", 0), (sym::trim_start_matches, 0),
("trim_end_matches", 0), (sym::trim_end_matches, 0),
("replace", 0), (sym::replace, 0),
("replacen", 0), (sym::replacen, 0),
]; ];
fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) { fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) {
@@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns {
&& let ExprKind::MethodCall(method, receiver, args, _) = expr.kind && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind
&& let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind()
&& ty.is_str() && ty.is_str()
&& let method_name = method.ident.name.as_str() && let method_name = method.ident.name
&& let Some(&(_, pos)) = PATTERN_METHODS && let Some(&(_, pos)) = PATTERN_METHODS
.iter() .iter()
.find(|(array_method_name, _)| *array_method_name == method_name) .find(|(array_method_name, _)| *array_method_name == method_name)

View File

@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::match_libc_symbol;
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::visitors::is_expr_unsafe; use clippy_utils::visitors::is_expr_unsafe;
use clippy_utils::{match_libc_symbol, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -44,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
&& let ExprKind::Call(func, [recv]) = expr.kind && let ExprKind::Call(func, [recv]) = expr.kind
&& let ExprKind::Path(path) = &func.kind && let ExprKind::Path(path) = &func.kind
&& let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id() && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& match_libc_symbol(cx, did, "strlen") && match_libc_symbol(cx, did, sym::strlen)
&& let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind
&& !recv.span.from_expansion() && !recv.span.from_expansion()
&& path.ident.name == sym::as_ptr && path.ident.name == sym::as_ptr

View File

@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym};
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::sym;
use std::ops::ControlFlow; use std::ops::ControlFlow;
declare_clippy_lint! { declare_clippy_lint! {
@@ -150,10 +149,10 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
remaining_args, remaining_args,
_, _,
) => { ) => {
let method_name = method_name_ident.name.as_str(); let method_name = method_name_ident.name;
// `Peekable` methods // `Peekable` methods
if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq") if matches!(method_name, sym::peek | sym::peek_mut | sym::next_if | sym::next_if_eq)
&& arg_is_mut_peekable(self.cx, self_arg) && arg_is_mut_peekable(self.cx, self_arg)
{ {
return ControlFlow::Break(()); return ControlFlow::Break(());
@@ -167,7 +166,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
} }
// foo.by_ref(), keep checking for `peek` // foo.by_ref(), keep checking for `peek`
if method_name == "by_ref" { if method_name == sym::by_ref {
continue; continue;
} }

View File

@@ -1,9 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::sym;
use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_ast::ast::{Expr, ExprKind, MethodCall};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::Symbol;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -30,19 +32,20 @@ declare_clippy_lint! {
} }
declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> { fn is_useless_rounding(cx: &EarlyContext<'_>, expr: &Expr) -> Option<(Symbol, String)> {
if let ExprKind::MethodCall(box MethodCall { if let ExprKind::MethodCall(box MethodCall {
seg: name_ident, seg: name_ident,
receiver, receiver,
.. ..
}) = &expr.kind }) = &expr.kind
&& let method_name = name_ident.ident.name.as_str() && let method_name = name_ident.ident.name
&& (method_name == "ceil" || method_name == "round" || method_name == "floor") && matches!(method_name, sym::ceil | sym::floor | sym::round)
&& let ExprKind::Lit(token_lit) = &receiver.kind && let ExprKind::Lit(token_lit) = &receiver.kind
&& token_lit.is_semantic_float() && token_lit.is_semantic_float()
&& let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>()
&& f.fract() == 0.0
{ {
(f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string())) Some((method_name, snippet(cx, receiver.span, "..").into()))
} else { } else {
None None
} }

View File

@@ -79,7 +79,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
let mut result = Vec::new(); let mut result = Vec::new();
let _: Option<!> = for_each_expr(cx, body.value, |e| { let _: Option<!> = for_each_expr(cx, body.value, |e| {
// check for `expect` // check for `expect`
if let Some(arglists) = method_chain_args(e, &["expect"]) { if let Some(arglists) = method_chain_args(e, &[sym::expect]) {
let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
if is_type_diagnostic_item(cx, receiver_ty, sym::Option) if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(cx, receiver_ty, sym::Result) || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
@@ -89,7 +89,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
} }
// check for `unwrap` // check for `unwrap`
if let Some(arglists) = method_chain_args(e, &["unwrap"]) { if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) {
let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
if is_type_diagnostic_item(cx, receiver_ty, sym::Option) if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(cx, receiver_ty, sym::Result) || is_type_diagnostic_item(cx, receiver_ty, sym::Result)

View File

@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_context};
use clippy_utils::sugg::{DiagExt as _, Sugg}; use clippy_utils::sugg::{DiagExt as _, Sugg};
use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{ use clippy_utils::{
get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym,
}; };
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@@ -15,7 +15,7 @@ use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym}; use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
declare_clippy_lint! { declare_clippy_lint! {
@@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}, },
ExprKind::MethodCall(name, recv, [], _) => { ExprKind::MethodCall(name, recv, [], _) => {
if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
let a = cx.typeck_results().expr_ty(e); let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(recv); let b = cx.typeck_results().expr_ty(recv);
if same_type_and_consts(a, b) { if same_type_and_consts(a, b) {

View File

@@ -1,4 +1,4 @@
use clippy_utils::{MaybePath, get_attr, higher, path_def_id}; use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym};
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::LitIntType; use rustc_ast::LitIntType;
use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::ast::{LitFloatType, LitKind};
@@ -826,5 +826,5 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
let attrs = cx.tcx.hir_attrs(hir_id); let attrs = cx.tcx.hir_attrs(hir_id);
get_attr(cx.sess(), attrs, "author").count() > 0 get_attr(cx.sess(), attrs, sym::author).count() > 0
} }

View File

@@ -1,4 +1,4 @@
use clippy_utils::get_attr; use clippy_utils::{get_attr, sym};
use hir::TraitItem; use hir::TraitItem;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -60,5 +60,5 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir {
fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
let attrs = cx.tcx.hir_attrs(hir_id); let attrs = cx.tcx.hir_attrs(hir_id);
get_attr(cx.sess(), attrs, "dump").count() > 0 get_attr(cx.sess(), attrs, sym::dump).count() > 0
} }

View File

@@ -8,14 +8,14 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_copy; use clippy_utils::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment}; use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{DesugaringKind, Span, sym}; use rustc_span::{DesugaringKind, Span};
pub struct UselessVec { pub struct UselessVec {
too_large_for_stack: u64, too_large_for_stack: u64,
@@ -249,10 +249,8 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
/// that also exists on slices. If this returns true, it means that /// that also exists on slices. If this returns true, it means that
/// this expression does not actually require a `Vec` and could just work with an array. /// this expression does not actually require a `Vec` and could just work with an array.
pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"];
if let ExprKind::MethodCall(path, _, [], _) = e.kind { if let ExprKind::MethodCall(path, _, [], _) = e.kind {
ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str()) matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len)
} else { } else {
is_trait_method(cx, e, sym::IntoIterator) is_trait_method(cx, e, sym::IntoIterator)
} }

View File

@@ -1,11 +1,10 @@
use crate::internal_paths; use crate::internal_paths;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{is_lint_allowed, method_calls}; use clippy_utils::{is_lint_allowed, method_calls, sym};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;
declare_tool_lint! { declare_tool_lint! {
/// ### What it does /// ### What it does
@@ -39,8 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
} }
let (method_names, arg_lists, spans) = method_calls(expr, 2); let (method_names, arg_lists, spans) = method_calls(expr, 2);
let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); if let [sym::expn_data, sym::outer_expn] = method_names.as_slice()
if let ["expn_data", "outer_expn"] = method_names.as_slice()
&& let (self_arg, args) = arg_lists[1] && let (self_arg, args) = arg_lists[1]
&& args.is_empty() && args.is_empty()
&& let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs()

View File

@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::sym;
use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_ast::ast::{Crate, ItemKind, ModKind};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -25,11 +26,11 @@ impl EarlyLintPass for UnsortedClippyUtilsPaths {
if let Some(utils) = krate if let Some(utils) = krate
.items .items
.iter() .iter()
.find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils")) .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::utils))
&& let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind
&& let Some(paths) = items && let Some(paths) = items
.iter() .iter()
.find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths")) .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::paths))
&& let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind
{ {
let mut last_name: Option<String> = None; let mut last_name: Option<String> = None;

View File

@@ -5,11 +5,11 @@ use rustc_lexer::TokenKind;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_middle::ty::{AdtDef, TyCtxt};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::{Span, sym}; use rustc_span::{Span, Symbol};
use std::str::FromStr; use std::str::FromStr;
use crate::source::SpanRangeExt; use crate::source::SpanRangeExt;
use crate::tokenize_with_text; use crate::{sym, tokenize_with_text};
/// Deprecation status of attributes known by Clippy. /// Deprecation status of attributes known by Clippy.
pub enum DeprecationStatus { pub enum DeprecationStatus {
@@ -21,17 +21,17 @@ pub enum DeprecationStatus {
} }
#[rustfmt::skip] #[rustfmt::skip]
pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ pub const BUILTIN_ATTRIBUTES: &[(Symbol, DeprecationStatus)] = &[
("author", DeprecationStatus::None), (sym::author, DeprecationStatus::None),
("version", DeprecationStatus::None), (sym::version, DeprecationStatus::None),
("cognitive_complexity", DeprecationStatus::None), (sym::cognitive_complexity, DeprecationStatus::None),
("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")), (sym::cyclomatic_complexity, DeprecationStatus::Replaced("cognitive_complexity")),
("dump", DeprecationStatus::None), (sym::dump, DeprecationStatus::None),
("msrv", DeprecationStatus::None), (sym::msrv, DeprecationStatus::None),
// The following attributes are for the 3rd party crate authors. // The following attributes are for the 3rd party crate authors.
// See book/src/attribs.md // See book/src/attribs.md
("has_significant_drop", DeprecationStatus::None), (sym::has_significant_drop, DeprecationStatus::None),
("format_args", DeprecationStatus::None), (sym::format_args, DeprecationStatus::None),
]; ];
pub struct LimitStack { pub struct LimitStack {
@@ -52,11 +52,11 @@ impl LimitStack {
pub fn limit(&self) -> u64 { pub fn limit(&self) -> u64 {
*self.stack.last().expect("there should always be a value in the stack") *self.stack.last().expect("there should always be a value in the stack")
} }
pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) { pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) {
let stack = &mut self.stack; let stack = &mut self.stack;
parse_attrs(sess, attrs, name, |val| stack.push(val)); parse_attrs(sess, attrs, name, |val| stack.push(val));
} }
pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) { pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) {
let stack = &mut self.stack; let stack = &mut self.stack;
parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
} }
@@ -65,7 +65,7 @@ impl LimitStack {
pub fn get_attr<'a, A: AttributeExt + 'a>( pub fn get_attr<'a, A: AttributeExt + 'a>(
sess: &'a Session, sess: &'a Session,
attrs: &'a [A], attrs: &'a [A],
name: &'static str, name: Symbol,
) -> impl Iterator<Item = &'a A> { ) -> impl Iterator<Item = &'a A> {
attrs.iter().filter(move |attr| { attrs.iter().filter(move |attr| {
let Some(attr_segments) = attr.ident_path() else { let Some(attr_segments) = attr.ident_path() else {
@@ -75,8 +75,8 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy { if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy {
BUILTIN_ATTRIBUTES BUILTIN_ATTRIBUTES
.iter() .iter()
.find_map(|&(builtin_name, ref deprecation_status)| { .find_map(|(builtin_name, deprecation_status)| {
if attr_segments[1].name.as_str() == builtin_name { if attr_segments[1].name == *builtin_name {
Some(deprecation_status) Some(deprecation_status)
} else { } else {
None None
@@ -108,7 +108,7 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
}, },
DeprecationStatus::None => { DeprecationStatus::None => {
diag.cancel(); diag.cancel();
attr_segments[1].as_str() == name attr_segments[1].name == name
}, },
} }
}, },
@@ -119,9 +119,9 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
}) })
} }
fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: &'static str, mut f: F) { fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: Symbol, mut f: F) {
for attr in get_attr(sess, attrs, name) { for attr in get_attr(sess, attrs, name) {
if let Some(ref value) = attr.value_str() { if let Some(value) = attr.value_str() {
if let Ok(value) = FromStr::from_str(value.as_str()) { if let Ok(value) = FromStr::from_str(value.as_str()) {
f(value); f(value);
} else { } else {
@@ -133,7 +133,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name:
} }
} }
pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: &'static str) -> Option<&'a A> { pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: Symbol) -> Option<&'a A> {
let mut unique_attr: Option<&A> = None; let mut unique_attr: Option<&A> = None;
for attr in get_attr(sess, attrs, name) { for attr in get_attr(sess, attrs, name) {
if let Some(duplicate) = unique_attr { if let Some(duplicate) = unique_attr {

View File

@@ -487,7 +487,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id), ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
ExprKind::Block(block, _) => self.block(block), ExprKind::Block(block, _) => self.block(block),
ExprKind::Lit(lit) => { ExprKind::Lit(lit) => {
if is_direct_expn_of(e.span, "cfg").is_some() { if is_direct_expn_of(e.span, sym::cfg).is_some() {
None None
} else { } else {
Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e))) Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)))
@@ -565,7 +565,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
}) })
}, },
ExprKind::Lit(lit) => { ExprKind::Lit(lit) => {
if is_direct_expn_of(e.span, "cfg").is_some() { if is_direct_expn_of(e.span, sym::cfg).is_some() {
None None
} else { } else {
match &lit.node { match &lit.node {
@@ -654,7 +654,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
span, span,
.. ..
}) = self.tcx.hir_node(body_id.hir_id) }) = self.tcx.hir_node(body_id.hir_id)
&& is_direct_expn_of(*span, "cfg").is_some() && is_direct_expn_of(*span, sym::cfg).is_some()
{ {
return None; return None;
} }

View File

@@ -10,6 +10,7 @@
//! - option-if-let-else //! - option-if-let-else
use crate::consts::{ConstEvalCtxt, FullInt}; use crate::consts::{ConstEvalCtxt, FullInt};
use crate::sym;
use crate::ty::{all_predicates_of, is_copy}; use crate::ty::{all_predicates_of, is_copy};
use crate::visitors::is_const_evaluatable; use crate::visitors::is_const_evaluatable;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@@ -19,7 +20,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::adjustment::Adjust;
use rustc_span::{Symbol, sym}; use rustc_span::Symbol;
use std::{cmp, ops}; use std::{cmp, ops};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -49,14 +50,13 @@ impl ops::BitOrAssign for EagernessSuggestion {
/// Determine the eagerness of the given function call. /// Determine the eagerness of the given function call.
fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
use EagernessSuggestion::{Eager, Lazy, NoChange}; use EagernessSuggestion::{Eager, Lazy, NoChange};
let name = name.as_str();
let ty = match cx.tcx.impl_of_method(fn_id) { let ty = match cx.tcx.impl_of_method(fn_id) {
Some(id) => cx.tcx.type_of(id).instantiate_identity(), Some(id) => cx.tcx.type_of(id).instantiate_identity(),
None => return Lazy, None => return Lazy,
}; };
if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg { if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg {
if matches!( if matches!(
cx.tcx.crate_name(fn_id.krate), cx.tcx.crate_name(fn_id.krate),
sym::std | sym::core | sym::alloc | sym::proc_macro sym::std | sym::core | sym::alloc | sym::proc_macro

View File

@@ -299,7 +299,7 @@ impl<'a> VecArgs<'a> {
pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<VecArgs<'a>> { pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<VecArgs<'a>> {
if let ExprKind::Call(fun, args) = expr.kind if let ExprKind::Call(fun, args) = expr.kind
&& let ExprKind::Path(ref qpath) = fun.kind && let ExprKind::Path(ref qpath) = fun.kind
&& is_expn_of(fun.span, "vec").is_some() && is_expn_of(fun.span, sym::vec).is_some()
&& let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
{ {
return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 { return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 {

View File

@@ -1097,13 +1097,13 @@ pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symb
/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec` /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
/// containing the `Expr`s for /// containing the `Expr`s for
/// `.bar()` and `.baz()` /// `.bar()` and `.baz()`
pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> { pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
let mut current = expr; let mut current = expr;
let mut matched = Vec::with_capacity(methods.len()); let mut matched = Vec::with_capacity(methods.len());
for method_name in methods.iter().rev() { for method_name in methods.iter().rev() {
// method chains are stored last -> first // method chains are stored last -> first
if let ExprKind::MethodCall(path, receiver, args, _) = current.kind { if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
if path.ident.name.as_str() == *method_name { if path.ident.name == *method_name {
if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
return None; return None;
} }
@@ -1489,14 +1489,14 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
/// macro `name`. /// macro `name`.
/// See also [`is_direct_expn_of`]. /// See also [`is_direct_expn_of`].
#[must_use] #[must_use]
pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { pub fn is_expn_of(mut span: Span, name: Symbol) -> Option<Span> {
loop { loop {
if span.from_expansion() { if span.from_expansion() {
let data = span.ctxt().outer_expn_data(); let data = span.ctxt().outer_expn_data();
let new_span = data.call_site; let new_span = data.call_site;
if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
&& mac_name.as_str() == name && mac_name == name
{ {
return Some(new_span); return Some(new_span);
} }
@@ -1519,13 +1519,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
/// from `bar!` by `is_direct_expn_of`. /// from `bar!` by `is_direct_expn_of`.
#[must_use] #[must_use]
pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option<Span> {
if span.from_expansion() { if span.from_expansion() {
let data = span.ctxt().outer_expn_data(); let data = span.ctxt().outer_expn_data();
let new_span = data.call_site; let new_span = data.call_site;
if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
&& mac_name.as_str() == name && mac_name == name
{ {
return Some(new_span); return Some(new_span);
} }
@@ -1789,11 +1789,11 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
} }
/// Checks if the given `DefId` matches the `libc` item. /// Checks if the given `DefId` matches the `libc` item.
pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool {
let path = cx.get_def_path(did); 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 // 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. // modules based on the target platform. Ignore everything but crate name and the item name.
path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name) path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name)
} }
/// Returns the list of condition expressions and the list of blocks in a /// Returns the list of condition expressions and the list of blocks in a

View File

@@ -2,8 +2,8 @@
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock};
use crate::get_unique_attr;
use crate::visitors::{Descend, for_each_expr_without_closures}; use crate::visitors::{Descend, for_each_expr_without_closures};
use crate::{get_unique_attr, sym};
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
@@ -12,7 +12,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol};
use std::ops::ControlFlow; use std::ops::ControlFlow;
const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -42,7 +42,7 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
} else { } else {
// Allow users to tag any macro as being format!-like // Allow users to tag any macro as being format!-like
// TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method // TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method
get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some() get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), sym::format_args).is_some()
} }
} }
@@ -248,10 +248,10 @@ impl<'a> PanicExpn<'a> {
let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else {
return None; return None;
}; };
let name = path.segments.last().unwrap().ident.as_str(); let name = path.segments.last().unwrap().ident.name;
// This has no argument // This has no argument
if name == "panic_cold_explicit" { if name == sym::panic_cold_explicit {
return Some(Self::Empty); return Some(Self::Empty);
} }
@@ -259,18 +259,18 @@ impl<'a> PanicExpn<'a> {
return None; return None;
}; };
let result = match name { let result = match name {
"panic" if arg.span.eq_ctxt(expr.span) => Self::Empty, sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty,
"panic" | "panic_str" => Self::Str(arg), sym::panic | sym::panic_str => Self::Str(arg),
"panic_display" | "panic_cold_display" => { sym::panic_display | sym::panic_cold_display => {
let ExprKind::AddrOf(_, _, e) = &arg.kind else { let ExprKind::AddrOf(_, _, e) = &arg.kind else {
return None; return None;
}; };
Self::Display(e) Self::Display(e)
}, },
"panic_fmt" => Self::Format(arg), sym::panic_fmt => Self::Format(arg),
// Since Rust 1.52, `assert_{eq,ne}` macros expand to use: // Since Rust 1.52, `assert_{eq,ne}` macros expand to use:
// `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));` // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));`
"assert_failed" => { sym::assert_failed => {
// It should have 4 arguments in total (we already matched with the first argument, // It should have 4 arguments in total (we already matched with the first argument,
// so we're just checking for 3) // so we're just checking for 3)
if rest.len() != 3 { if rest.len() != 3 {

View File

@@ -1,17 +1,17 @@
use crate::source::snippet; use crate::source::snippet;
use crate::visitors::{Descend, for_each_expr_without_closures}; use crate::visitors::{Descend, for_each_expr_without_closures};
use crate::{path_to_local_id, strip_pat_refs}; use crate::{path_to_local_id, strip_pat_refs, sym};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Span; use rustc_span::{Span, Symbol};
use std::borrow::Cow; use std::borrow::Cow;
pub fn get_spans( pub fn get_spans(
cx: &LateContext<'_>, cx: &LateContext<'_>,
opt_body_id: Option<BodyId>, opt_body_id: Option<BodyId>,
idx: usize, idx: usize,
replacements: &[(&'static str, &'static str)], replacements: &[(Symbol, &'static str)],
) -> Option<Vec<(Span, Cow<'static, str>)>> { ) -> Option<Vec<(Span, Cow<'static, str>)>> {
if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) {
if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind { if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
@@ -27,7 +27,7 @@ pub fn get_spans(
fn extract_clone_suggestions<'tcx>( fn extract_clone_suggestions<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
id: HirId, id: HirId,
replace: &[(&'static str, &'static str)], replace: &[(Symbol, &'static str)],
body: &'tcx Body<'_>, body: &'tcx Body<'_>,
) -> Option<Vec<(Span, Cow<'static, str>)>> { ) -> Option<Vec<(Span, Cow<'static, str>)>> {
let mut spans = Vec::new(); let mut spans = Vec::new();
@@ -35,11 +35,11 @@ fn extract_clone_suggestions<'tcx>(
if let ExprKind::MethodCall(seg, recv, [], _) = e.kind if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
&& path_to_local_id(recv, id) && path_to_local_id(recv, id)
{ {
if seg.ident.as_str() == "capacity" { if seg.ident.name == sym::capacity {
return ControlFlow::Break(()); return ControlFlow::Break(());
} }
for &(fn_name, suffix) in replace { for &(fn_name, suffix) in replace {
if seg.ident.as_str() == fn_name { if seg.ident.name == fn_name {
spans.push((e.span, snippet(cx, recv.span, "_") + suffix)); spans.push((e.span, snippet(cx, recv.span, "_") + suffix));
return ControlFlow::Continue(Descend::No); return ControlFlow::Continue(Descend::No);
} }

View File

@@ -29,172 +29,330 @@ macro_rules! generate {
}; };
} }
// List of extra symbols to be included in Clippy (for example, as `sym::ambiguous_glob_reexports`).
// An alternative content can be specified using a colon after the symbol name.
//
// `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted.
generate! { generate! {
abs,
align_of,
ambiguous_glob_reexports,
as_bytes,
as_deref_mut,
as_deref,
as_mut,
AsyncReadExt, AsyncReadExt,
AsyncWriteExt, AsyncWriteExt,
BACKSLASH_SINGLE_QUOTE: r"\'", BACKSLASH_SINGLE_QUOTE: r"\'",
Binary, Binary,
build_hasher,
bytes,
cargo_clippy: "cargo-clippy",
Cargo_toml: "Cargo.toml",
cast,
chars,
CLIPPY_ARGS, CLIPPY_ARGS,
CLIPPY_CONF_DIR, CLIPPY_CONF_DIR,
CRLF: "\r\n",
Cargo_toml: "Cargo.toml",
Current,
DOUBLE_QUOTE: "\"",
Deserialize,
EarlyLintPass,
ErrorKind,
IntoIter,
Itertools,
LF: "\n",
Lazy,
Lint,
LowerExp,
LowerHex,
MAX,
MIN,
MsrvStack,
Octal,
OpenOptions,
Other,
PathLookup,
Regex,
RegexBuilder,
RegexSet,
Start,
Step,
Symbol,
SyntaxContext,
TBD,
UpperExp,
UpperHex,
V4,
V6,
Visitor,
Weak,
abs,
align_of,
ambiguous_glob_reexports,
append,
arg,
as_bytes,
as_deref,
as_deref_mut,
as_mut,
assert_failed,
author,
borrow,
borrow_mut,
build_hasher,
by_ref,
bytes,
capacity,
cargo_clippy: "cargo-clippy",
cast,
cast_const,
cast_mut,
ceil,
ceil_char_boundary,
chain,
chars,
checked_abs,
checked_add,
checked_isqrt,
checked_mul,
checked_pow,
checked_rem_euclid,
checked_sub,
clamp,
clippy_utils, clippy_utils,
clone_into, clone_into,
cloned, cloned,
cognitive_complexity,
collect, collect,
const_ptr, const_ptr,
contains, contains,
copied, copied,
CRLF: "\r\n", copy_from,
Current, copy_from_nonoverlapping,
copy_to,
copy_to_nonoverlapping,
count_ones,
cycle,
cyclomatic_complexity,
de, de,
Deserialize,
diagnostics, diagnostics,
disallowed_types, disallowed_types,
DOUBLE_QUOTE: "\"", drain,
EarlyLintPass, dump,
ends_with, ends_with,
enum_glob_use, enum_glob_use,
enumerate,
err,
error, error,
ErrorKind,
exp, exp,
expect_err,
expn_data,
extend, extend,
finish_non_exhaustive, filter,
filter_map,
find,
find_map,
finish, finish,
finish_non_exhaustive,
first,
flat_map, flat_map,
flatten,
floor,
floor_char_boundary,
fold,
for_each, for_each,
from_bytes_with_nul_unchecked,
from_bytes_with_nul, from_bytes_with_nul,
from_bytes_with_nul_unchecked,
from_ptr, from_ptr,
from_raw, from_raw,
from_ref, from_ref,
from_str,
from_str_radix, from_str_radix,
fs, fs,
fuse,
futures_util, futures_util,
get, get,
get_mut,
get_or_insert_with,
get_unchecked,
get_unchecked_mut,
has_significant_drop,
hidden_glob_reexports, hidden_glob_reexports,
hygiene, hygiene,
if_chain,
insert, insert,
inspect,
int_roundings, int_roundings,
into,
into_bytes, into_bytes,
into_ok,
into_owned, into_owned,
IntoIter,
io, io,
is_ascii, is_ascii,
is_char_boundary,
is_digit,
is_empty, is_empty,
is_err, is_err,
is_file,
is_none, is_none,
is_ok, is_ok,
is_some, is_some,
isqrt,
itertools, itertools,
Itertools, join,
kw, kw,
last, last,
lazy_static, lazy_static,
Lazy,
LF: "\n",
Lint,
ln, ln,
lock,
lock_api, lock_api,
log, log,
LowerExp, log10,
LowerHex, log2,
macro_use_imports, macro_use_imports,
map_or_else, map_break,
map_continue,
map_or, map_or,
map_or_else,
match_indices,
matches,
max, max,
MAX, max_by,
max_by_key,
max_value,
maximum,
mem, mem,
min, min,
MIN, min_by,
min_by_key,
min_value,
minimum,
mode, mode,
module_name_repetitions, module_name_repetitions,
msrv, msrv,
msrvs, msrvs,
MsrvStack,
mut_ptr, mut_ptr,
mutex, mutex,
needless_return, needless_return,
next_back,
next_if,
next_if_eq,
next_tuple, next_tuple,
Octal, nth,
ok,
ok_or,
once_cell, once_cell,
OpenOptions, open,
or_default, or_default,
Other, or_else,
or_insert,
or_insert_with,
outer_expn,
panic_cold_display,
panic_cold_explicit,
panic_display,
panic_str,
parse, parse,
PathLookup, partition,
paths, paths,
peek,
peek_mut,
peekable,
pow,
powf, powf,
powi, powi,
product,
push, push,
read_line,
read_to_end,
read_to_string,
redundant_pub_crate, redundant_pub_crate,
regex, regex,
Regex, rem_euclid,
RegexBuilder, repeat,
RegexSet, replace,
replacen,
reserve, reserve,
resize, resize,
restriction, restriction,
rustc_lint_defs, rev,
rfind,
rmatch_indices,
rmatches,
round,
rposition,
rsplit,
rsplit_once,
rsplit_terminator,
rsplitn,
rsplitn_mut,
rustc_lint, rustc_lint,
rustc_lint_defs,
rustc_span, rustc_span,
rustfmt_skip, rustfmt_skip,
rwlock, rwlock,
saturating_abs,
saturating_pow,
scan,
seek,
serde, serde,
set_len, set_len,
set_mode, set_mode,
set_readonly, set_readonly,
signum, signum,
single_component_path_imports, single_component_path_imports,
skip_while,
slice_mut_unchecked,
slice_unchecked,
sort,
sort_by,
sort_unstable_by,
span_lint_and_then, span_lint_and_then,
split_whitespace,
split, split,
split_at,
split_at_checked,
split_at_mut,
split_at_mut_checked,
split_inclusive,
split_once,
split_terminator,
split_whitespace,
splitn,
splitn_mut,
sqrt, sqrt,
Start, starts_with,
Step, step_by,
strlen,
style, style,
subsec_micros,
subsec_nanos,
sum,
symbol, symbol,
Symbol,
SyntaxContext,
take, take,
TBD, take_while,
then,
then_some, then_some,
to_ascii_lowercase, to_ascii_lowercase,
to_ascii_uppercase, to_ascii_uppercase,
to_digit, to_digit,
to_lowercase, to_lowercase,
to_os_string,
to_owned, to_owned,
to_path_buf,
to_uppercase, to_uppercase,
tokio, tokio,
trim,
trim_end_matches,
trim_start_matches,
unreachable_pub, unreachable_pub,
unsafe_removed_from_name, unsafe_removed_from_name,
unused,
unused_braces, unused_braces,
unused_extern_crates, unused_extern_crates,
unused_import_braces, unused_import_braces,
unused_trait_names, unused_trait_names,
unused,
unwrap_err, unwrap_err,
unwrap_err_unchecked,
unwrap_or_default, unwrap_or_default,
unwrap_or_else, unwrap_or_else,
UpperExp, unwrap_unchecked,
UpperHex, unzip,
V4, utils,
V6, wake,
Visitor,
warnings, warnings,
Weak,
wildcard_imports, wildcard_imports,
with_capacity, with_capacity,
wrapping_offset, wrapping_offset,
write,
writeln,
zip,
} }