Add lint to check for slow symbol comparisons
This commit is contained in:
parent
236751d093
commit
6b1779b0ee
@ -28,6 +28,8 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO,
|
||||
|
@ -605,6 +605,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
||||
store.register_late_pass(|_| {
|
||||
Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new())
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(utils::internal_lints::slow_symbol_comparisons::SlowSymbolComparisons));
|
||||
}
|
||||
|
||||
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
|
||||
|
@ -6,5 +6,6 @@ pub mod lint_without_lint_pass;
|
||||
pub mod msrv_attr_impl;
|
||||
pub mod outer_expn_data_pass;
|
||||
pub mod produce_ice;
|
||||
pub mod slow_symbol_comparisons;
|
||||
pub mod unnecessary_def_path;
|
||||
pub mod unsorted_clippy_utils_paths;
|
||||
|
@ -0,0 +1,69 @@
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::match_type;
|
||||
use clippy_utils::{match_function_call, paths};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Detects symbol comparision using `Symbol::intern`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Comparision via `Symbol::as_str()` is faster if the interned symbols are not reused.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// None, see suggestion.
|
||||
pub SLOW_SYMBOL_COMPARISONS,
|
||||
internal,
|
||||
"detects slow comparisions of symbol"
|
||||
}
|
||||
|
||||
declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]);
|
||||
|
||||
fn check_slow_comparison<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
op1: &'tcx Expr<'tcx>,
|
||||
op2: &'tcx Expr<'tcx>,
|
||||
) -> Option<(Span, String)> {
|
||||
if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL)
|
||||
&& let Some([symbol_name_expr]) = match_function_call(cx, op2, &paths::SYMBOL_INTERN)
|
||||
&& let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr)
|
||||
{
|
||||
Some((op1.span, symbol_name))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
if let ExprKind::Binary(op, left, right) = expr.kind
|
||||
&& (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne)
|
||||
&& let Some((symbol_span, symbol_name)) =
|
||||
check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left))
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SLOW_SYMBOL_COMPARISONS,
|
||||
expr.span,
|
||||
"comparing `Symbol` via `Symbol::intern`",
|
||||
"use `Symbol::as_str` and check the string instead",
|
||||
format!(
|
||||
"{}.as_str() {} \"{symbol_name}\"",
|
||||
snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability),
|
||||
op.node.as_str()
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user