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
+ } ;
2
4
use if_chain:: if_chain;
3
5
use rustc:: hir;
4
6
use rustc:: hir:: def:: { DefKind , Res } ;
@@ -7,6 +9,7 @@ use rustc::hir::*;
7
9
use rustc:: lint:: { EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintArray , LintPass } ;
8
10
use rustc:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
9
11
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
12
+ use rustc_errors:: Applicability ;
10
13
use syntax:: ast:: { Crate as AstCrate , ItemKind , Name } ;
11
14
use syntax:: source_map:: Span ;
12
15
use syntax_pos:: symbol:: LocalInternedString ;
@@ -72,6 +75,29 @@ declare_clippy_lint! {
72
75
"usage of the lint functions of the compiler instead of the utils::* variant"
73
76
}
74
77
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
+
75
101
declare_lint_pass ! ( ClippyLintsInternal => [ CLIPPY_LINTS_INTERNAL ] ) ;
76
102
77
103
impl EarlyLintPass for ClippyLintsInternal {
@@ -251,3 +277,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
251
277
}
252
278
}
253
279
}
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