@@ -3,15 +3,15 @@ use syntax::ptr::P;
3
3
use rustc_front:: hir:: * ;
4
4
use reexport:: * ;
5
5
use rustc_front:: util:: { is_comparison_binop, binop_to_string} ;
6
- use syntax:: codemap:: { Span , Spanned } ;
6
+ use syntax:: codemap:: { Span , Spanned , ExpnFormat } ;
7
7
use rustc_front:: intravisit:: FnKind ;
8
8
use rustc:: middle:: ty;
9
9
use rustc:: middle:: const_eval:: ConstVal :: Float ;
10
10
use rustc:: middle:: const_eval:: eval_const_expr_partial;
11
11
use rustc:: middle:: const_eval:: EvalHint :: ExprTypeChecked ;
12
12
13
13
use utils:: { get_item_name, match_path, snippet, get_parent_expr, span_lint} ;
14
- use utils:: { span_help_and_lint, in_external_macro , walk_ptrs_ty, is_integer_literal} ;
14
+ use utils:: { span_help_and_lint, walk_ptrs_ty, is_integer_literal} ;
15
15
16
16
/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default.
17
17
///
@@ -345,14 +345,17 @@ impl LintPass for UsedUnderscoreBinding {
345
345
346
346
impl LateLintPass for UsedUnderscoreBinding {
347
347
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
348
+ if in_attributes_expansion ( cx, expr) { // Don't lint things expanded by #[derive(...)], etc
349
+ return ;
350
+ }
348
351
let needs_lint = match expr. node {
349
352
ExprPath ( _, ref path) => {
350
353
let ident = path. segments . last ( )
351
354
. expect ( "path should always have at least one segment" )
352
355
. identifier ;
353
356
ident. name . as_str ( ) . chars ( ) . next ( ) == Some ( '_' ) //starts with '_'
354
357
&& ident. name . as_str ( ) . chars ( ) . skip ( 1 ) . next ( ) != Some ( '_' ) //doesn't start with "__"
355
- && ident. name != ident. unhygienic_name //not in macro
358
+ && ident. name != ident. unhygienic_name //not in bang macro
356
359
&& is_used ( cx, expr)
357
360
} ,
358
361
ExprField ( _, spanned) => {
@@ -362,9 +365,6 @@ impl LateLintPass for UsedUnderscoreBinding {
362
365
} ,
363
366
_ => false
364
367
} ;
365
- if in_external_macro ( cx, expr. span ) {
366
- return
367
- }
368
368
if needs_lint {
369
369
cx. span_lint ( USED_UNDERSCORE_BINDING , expr. span ,
370
370
"used binding which is prefixed with an underscore. A leading underscore \
@@ -373,6 +373,8 @@ impl LateLintPass for UsedUnderscoreBinding {
373
373
}
374
374
}
375
375
376
+ /// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea
377
+ /// of what it means for an expression to be "used".
376
378
fn is_used ( cx : & LateContext , expr : & Expr ) -> bool {
377
379
if let Some ( ref parent) = get_parent_expr ( cx, expr) {
378
380
match parent. node {
@@ -385,3 +387,16 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool {
385
387
true
386
388
}
387
389
}
390
+
391
+ /// Test whether an expression is in a macro expansion (e.g. something generated by #[derive(...)]
392
+ /// or the like)
393
+ fn in_attributes_expansion ( cx : & LateContext , expr : & Expr ) -> bool {
394
+ cx. sess ( ) . codemap ( ) . with_expn_info ( expr. span . expn_id , |info_opt| {
395
+ info_opt. map_or ( false , |info| {
396
+ match info. callee . format {
397
+ ExpnFormat :: MacroAttribute ( _) => true ,
398
+ _ => false ,
399
+ }
400
+ } )
401
+ } )
402
+ }
0 commit comments