use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::fn_def_id;
+use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
-use rustc_hir::{def::Res, def_id::DefIdMap, Expr};
+use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
/// ### What it does
/// Denies the configured methods and functions in clippy.toml
///
+ /// Note: Even though this lint is warn-by-default, it will only trigger if
+ /// methods are defined in the clippy.toml file.
+ ///
/// ### Why is this bad?
/// Some methods are undesirable in certain contexts, and it's beneficial to
/// lint for them as needed.
/// ```
#[clippy::version = "1.49.0"]
pub DISALLOWED_METHODS,
- nursery,
+ style,
"use of a disallowed method call"
}
#[derive(Clone, Debug)]
pub struct DisallowedMethods {
conf_disallowed: Vec<conf::DisallowedMethod>,
- disallowed: DefIdMap<Option<String>>,
+ disallowed: DefIdMap<usize>,
}
impl DisallowedMethods {
impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
fn check_crate(&mut self, cx: &LateContext<'_>) {
- for conf in &self.conf_disallowed {
- let (path, reason) = match conf {
- conf::DisallowedMethod::Simple(path) => (path, None),
- conf::DisallowedMethod::WithReason { path, reason } => (
- path,
- reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
- ),
- };
- let segs: Vec<_> = path.split("::").collect();
- if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) {
- self.disallowed.insert(id, reason);
+ for (index, conf) in self.conf_disallowed.iter().enumerate() {
+ let segs: Vec<_> = conf.path().split("::").collect();
+ if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
+ self.disallowed.insert(id, index);
}
}
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let def_id = match fn_def_id(cx, expr) {
+ let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::Call(receiver, _) = parent.kind
+ && receiver.hir_id == expr.hir_id
+ {
+ None
+ } else {
+ path_def_id(cx, expr)
+ };
+ let def_id = match uncalled_path.or_else(|| fn_def_id(cx, expr)) {
Some(def_id) => def_id,
None => return,
};
- let reason = match self.disallowed.get(&def_id) {
- Some(reason) => reason,
+ let conf = match self.disallowed.get(&def_id) {
+ Some(&index) => &self.conf_disallowed[index],
None => return,
};
- let func_path = cx.tcx.def_path_str(def_id);
- let msg = format!("use of a disallowed method `{}`", func_path);
+ let msg = format!("use of a disallowed method `{}`", conf.path());
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
- if let Some(reason) = reason {
- diag.note(reason);
+ if let conf::DisallowedMethod::WithReason {
+ reason: Some(reason), ..
+ } = conf
+ {
+ diag.note(&format!("{} (from clippy.toml)", reason));
}
});
}