]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
Merge commit 'f4850f7292efa33759b4f7f9b7621268979e9914' into clippyup
[rust.git] / src / tools / clippy / clippy_lints / src / utils / internal_lints / outer_expn_data_pass.rs
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;
6 use rustc_hir as hir;
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_lint_pass, declare_tool_lint};
9 use rustc_span::symbol::Symbol;
10
11 declare_clippy_lint! {
12     /// ### What it does
13     /// Checks for calls to `cx.outer().expn_data()` and suggests to use
14     /// the `cx.outer_expn_data()`
15     ///
16     /// ### Why is this bad?
17     /// `cx.outer_expn_data()` is faster and more concise.
18     ///
19     /// ### Example
20     /// ```rust,ignore
21     /// expr.span.ctxt().outer().expn_data()
22     /// ```
23     ///
24     /// Use instead:
25     /// ```rust,ignore
26     /// expr.span.ctxt().outer_expn_data()
27     /// ```
28     pub OUTER_EXPN_EXPN_DATA,
29     internal,
30     "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
31 }
32
33 declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
34
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) {
38             return;
39         }
40
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();
43         if_chain! {
44             if let ["expn_data", "outer_expn"] = method_names.as_slice();
45             let (self_arg, args) = arg_lists[1];
46             if args.is_empty();
47             let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
48             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
49             then {
50                 span_lint_and_sugg(
51                     cx,
52                     OUTER_EXPN_EXPN_DATA,
53                     spans[1].with_hi(expr.span.hi()),
54                     "usage of `outer_expn().expn_data()`",
55                     "try",
56                     "outer_expn_data()".to_string(),
57                     Applicability::MachineApplicable,
58                 );
59             }
60         }
61     }
62 }