-use crate::utils::{match_def_path, match_trait_method, paths, span_lint};
+use crate::utils::{match_def_path, match_trait_method, paths, qpath_res, span_lint};
use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind, Item, ItemKind};
+use rustc_hir::def::Res;
+use rustc_hir::{Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
#[derive(Default)]
pub struct ToStringInDisplay {
in_display_impl: bool,
+ self_hir_id: Option<HirId>,
}
impl ToStringInDisplay {
pub fn new() -> Self {
- Self { in_display_impl: false }
+ Self {
+ in_display_impl: false,
+ self_hir_id: None,
+ }
}
}
fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if is_display_impl(cx, item) {
self.in_display_impl = false;
+ self.self_hir_id = None;
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
+ if_chain! {
+ if self.in_display_impl;
+ if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
+ let body = cx.tcx.hir().body(*body_id);
+ if !body.params.is_empty();
+ then {
+ let self_param = &body.params[0];
+ self.self_hir_id = Some(self_param.pat.hir_id);
+ }
}
}
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::MethodCall(ref path, _, _, _) = expr.kind;
+ if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind;
if path.ident.name == sym!(to_string);
if match_trait_method(cx, expr, &paths::TO_STRING);
if self.in_display_impl;
-
+ if let ExprKind::Path(ref qpath) = args[0].kind;
+ if let Res::Local(hir_id) = qpath_res(cx, qpath, args[0].hir_id);
+ if let Some(self_hir_id) = self.self_hir_id;
+ if hir_id == self_hir_id;
then {
span_lint(
cx,