1- use crate :: utils:: { match_def_path, match_type, paths, span_help_and_lint, span_lint, walk_ptrs_ty} ;
1+ use crate :: utils:: {
2+ match_def_path, match_type, method_calls, paths, span_help_and_lint, span_lint, span_lint_and_sugg, walk_ptrs_ty,
3+ } ;
24use if_chain:: if_chain;
35use rustc:: hir;
46use rustc:: hir:: def:: { DefKind , Res } ;
@@ -7,6 +9,7 @@ use rustc::hir::*;
79use rustc:: lint:: { EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintArray , LintPass } ;
810use rustc:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
911use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
12+ use rustc_errors:: Applicability ;
1013use syntax:: ast:: { Crate as AstCrate , ItemKind , Name } ;
1114use syntax:: source_map:: Span ;
1215use syntax_pos:: symbol:: LocalInternedString ;
@@ -72,6 +75,29 @@ declare_clippy_lint! {
7275 "usage of the lint functions of the compiler instead of the utils::* variant"
7376}
7477
78+ declare_clippy_lint ! {
79+ /// **What it does:** Checks for calls to `cx.outer().expn_info()` and suggests to use
80+ /// the `cx.outer_expn_info()`
81+ ///
82+ /// **Why is this bad?** `cx.outer_expn_info()` is faster and more concise.
83+ ///
84+ /// **Known problems:** None.
85+ ///
86+ /// **Example:**
87+ /// Bad:
88+ /// ```rust
89+ /// expr.span.ctxt().outer().expn_info()
90+ /// ```
91+ ///
92+ /// Good:
93+ /// ```rust
94+ /// expr.span.ctxt().outer_expn_info()
95+ /// ```
96+ pub OUTER_EXPN_INFO ,
97+ internal,
98+ "using `cx.outer().expn_info()` instead of `cx.outer_expn_info()`"
99+ }
100+
75101declare_lint_pass ! ( ClippyLintsInternal => [ CLIPPY_LINTS_INTERNAL ] ) ;
76102
77103impl EarlyLintPass for ClippyLintsInternal {
@@ -251,3 +277,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
251277 }
252278 }
253279}
280+
281+ pub struct OuterExpnInfoPass ;
282+
283+ impl_lint_pass ! ( OuterExpnInfoPass => [ OUTER_EXPN_INFO ] ) ;
284+
285+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for OuterExpnInfoPass {
286+ fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx hir:: Expr ) {
287+ let ( method_names, arg_lists) = method_calls ( expr, 2 ) ;
288+ let method_names: Vec < LocalInternedString > = method_names. iter ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
289+ let method_names: Vec < & str > = method_names. iter ( ) . map ( std:: convert:: AsRef :: as_ref) . collect ( ) ;
290+ if_chain ! {
291+ if let [ "expn_info" , "outer" ] = method_names. as_slice( ) ;
292+ let args = arg_lists[ 1 ] ;
293+ if args. len( ) == 1 ;
294+ let self_arg = & args[ 0 ] ;
295+ let self_ty = walk_ptrs_ty( cx. tables. expr_ty( self_arg) ) ;
296+ if match_type( cx, self_ty, & paths:: SYNTAX_CONTEXT ) ;
297+ then {
298+ span_lint_and_sugg(
299+ cx,
300+ OUTER_EXPN_INFO ,
301+ expr. span. trim_start( self_arg. span) . unwrap_or( expr. span) ,
302+ "usage of `outer().expn_info()`" ,
303+ "try" ,
304+ ".outer_expn_info()" . to_string( ) ,
305+ Applicability :: MachineApplicable ,
306+ ) ;
307+ }
308+ }
309+ }
310+ }
0 commit comments