1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::ty::match_type;
3 use clippy_utils::{is_lint_allowed, method_calls, paths};
4 use if_chain::if_chain;
5 use rustc_errors::Applicability;
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_lint_pass, declare_tool_lint};
9 use rustc_span::symbol::Symbol;
11 declare_clippy_lint! {
13 /// Checks for calls to `cx.outer().expn_data()` and suggests to use
14 /// the `cx.outer_expn_data()`
16 /// ### Why is this bad?
17 /// `cx.outer_expn_data()` is faster and more concise.
21 /// expr.span.ctxt().outer().expn_data()
26 /// expr.span.ctxt().outer_expn_data()
28 pub OUTER_EXPN_EXPN_DATA,
30 "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
33 declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
35 impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
36 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
37 if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
41 let (method_names, arg_lists, spans) = method_calls(expr, 2);
42 let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
44 if let ["expn_data", "outer_expn"] = method_names.as_slice();
45 let (self_arg, args) = arg_lists[1];
47 let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
48 if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
53 spans[1].with_hi(expr.span.hi()),
54 "usage of `outer_expn().expn_data()`",
56 "outer_expn_data()".to_string(),
57 Applicability::MachineApplicable,