blob: df37619227c86d42452279b9dd5ad45c9a3f7015 [file] [log] [blame]
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::match_type;
use clippy_utils::{is_lint_allowed, paths};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
/// variant of the function.
///
/// ### Why is this bad?
/// The `utils::*` variants also add a link to the Clippy documentation to the
/// warning/error messages.
///
/// ### Example
/// ```rust,ignore
/// cx.span_lint(LINT_NAME, "message");
/// ```
///
/// Use instead:
/// ```rust,ignore
/// utils::span_lint(cx, LINT_NAME, "message");
/// ```
pub COMPILER_LINT_FUNCTIONS,
internal,
"usage of the lint functions of the compiler instead of the utils::* variant"
}
impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
#[derive(Clone, Default)]
pub struct CompilerLintFunctions {
map: FxHashMap<&'static str, &'static str>,
}
impl CompilerLintFunctions {
#[must_use]
pub fn new() -> Self {
let mut map = FxHashMap::default();
map.insert("span_lint", "utils::span_lint");
map.insert("lint", "utils::span_lint");
map.insert("span_lint_note", "utils::span_lint_and_note");
map.insert("span_lint_help", "utils::span_lint_and_help");
Self { map }
}
}
impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
return;
}
if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind
&& let fn_name = path.ident
&& let Some(sugg) = self.map.get(fn_name.as_str())
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
&& (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT))
{
span_lint_and_help(
cx,
COMPILER_LINT_FUNCTIONS,
path.ident.span,
"usage of a compiler lint function",
None,
&format!("please use the Clippy variant of this function: `{sugg}`"),
);
}
}
}