1
1
use crate :: context:: { CheckLintNameResult , LintStore } ;
2
2
use crate :: late:: unerased_lint_store;
3
3
use rustc_ast as ast;
4
- use rustc_ast:: attr;
5
4
use rustc_ast:: unwrap_or;
6
5
use rustc_ast_pretty:: pprust;
7
6
use rustc_data_structures:: fx:: FxHashMap ;
8
7
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
9
8
use rustc_hir as hir;
10
- use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
9
+ use rustc_hir:: def_id:: { CrateNum , DefId , CRATE_DEF_INDEX , LOCAL_CRATE } ;
11
10
use rustc_hir:: { intravisit, HirId } ;
12
11
use rustc_middle:: hir:: map:: Map ;
13
12
use rustc_middle:: lint:: LevelAndSource ;
@@ -32,7 +31,8 @@ use std::cmp;
32
31
fn lint_levels ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> LintLevelMap {
33
32
assert_eq ! ( cnum, LOCAL_CRATE ) ;
34
33
let store = unerased_lint_store ( tcx) ;
35
- let levels = LintLevelsBuilder :: new ( tcx. sess , false , & store) ;
34
+ let crate_attrs = tcx. get_attrs ( DefId { krate : cnum, index : CRATE_DEF_INDEX } ) ;
35
+ let levels = LintLevelsBuilder :: new ( tcx. sess , false , & store, crate_attrs) ;
36
36
let mut builder = LintLevelMapBuilder { levels, tcx, store } ;
37
37
let krate = tcx. hir ( ) . krate ( ) ;
38
38
@@ -56,6 +56,7 @@ pub struct LintLevelsBuilder<'s> {
56
56
cur : u32 ,
57
57
warn_about_weird_lints : bool ,
58
58
store : & ' s LintStore ,
59
+ crate_attrs : & ' s [ ast:: Attribute ] ,
59
60
}
60
61
61
62
pub struct BuilderPush {
@@ -64,14 +65,20 @@ pub struct BuilderPush {
64
65
}
65
66
66
67
impl < ' s > LintLevelsBuilder < ' s > {
67
- pub fn new ( sess : & ' s Session , warn_about_weird_lints : bool , store : & ' s LintStore ) -> Self {
68
+ pub fn new (
69
+ sess : & ' s Session ,
70
+ warn_about_weird_lints : bool ,
71
+ store : & ' s LintStore ,
72
+ crate_attrs : & ' s [ ast:: Attribute ] ,
73
+ ) -> Self {
68
74
let mut builder = LintLevelsBuilder {
69
75
sess,
70
76
sets : LintLevelSets :: new ( ) ,
71
77
cur : 0 ,
72
78
id_to_set : Default :: default ( ) ,
73
79
warn_about_weird_lints,
74
80
store,
81
+ crate_attrs,
75
82
} ;
76
83
builder. process_command_line ( sess, store) ;
77
84
assert_eq ! ( builder. sets. list. len( ) , 1 ) ;
@@ -304,15 +311,22 @@ impl<'s> LintLevelsBuilder<'s> {
304
311
} ;
305
312
let tool_name = if meta_item. path . segments . len ( ) > 1 {
306
313
let tool_ident = meta_item. path . segments [ 0 ] . ident ;
307
- if !attr :: is_known_lint_tool ( tool_ident) {
308
- struct_span_err ! (
314
+ if !is_known_lint_tool ( tool_ident. name , sess , & self . crate_attrs ) {
315
+ let mut err = struct_span_err ! (
309
316
sess,
310
317
tool_ident. span,
311
318
E0710 ,
312
- "an unknown tool name found in scoped lint: `{}`" ,
319
+ "unknown tool name `{}` found in scoped lint: `{}`" ,
320
+ tool_ident. name,
313
321
pprust:: path_to_string( & meta_item. path) ,
314
- )
315
- . emit ( ) ;
322
+ ) ;
323
+ if sess. is_nightly_build ( ) {
324
+ err. help ( & format ! (
325
+ "add `#![register_tool({})]` to the crate root" ,
326
+ tool_ident. name
327
+ ) ) ;
328
+ }
329
+ err. emit ( ) ;
316
330
continue ;
317
331
}
318
332
@@ -559,6 +573,20 @@ impl<'s> LintLevelsBuilder<'s> {
559
573
}
560
574
}
561
575
576
+ fn is_known_lint_tool ( m_item : Symbol , sess : & Session , attrs : & [ ast:: Attribute ] ) -> bool {
577
+ if [ sym:: clippy, sym:: rustc, sym:: rustdoc] . contains ( & m_item) {
578
+ return true ;
579
+ }
580
+ // Look for registered tools
581
+ // NOTE: does no error handling; error handling is done by rustc_resolve.
582
+ sess. filter_by_name ( attrs, sym:: register_tool)
583
+ . filter_map ( |attr| attr. meta_item_list ( ) )
584
+ . flat_map ( std:: convert:: identity)
585
+ . filter_map ( |nested_meta| nested_meta. ident ( ) )
586
+ . map ( |ident| ident. name )
587
+ . any ( |name| name == m_item)
588
+ }
589
+
562
590
struct LintLevelMapBuilder < ' a , ' tcx > {
563
591
levels : LintLevelsBuilder < ' tcx > ,
564
592
tcx : TyCtxt < ' tcx > ,
0 commit comments