11use crate :: context:: { CheckLintNameResult , LintStore } ;
22use crate :: late:: unerased_lint_store;
33use rustc_ast as ast;
4- use rustc_ast:: attr;
54use rustc_ast:: unwrap_or;
65use rustc_ast_pretty:: pprust;
76use rustc_data_structures:: fx:: FxHashMap ;
87use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
98use 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 } ;
1110use rustc_hir:: { intravisit, HirId } ;
1211use rustc_middle:: hir:: map:: Map ;
1312use rustc_middle:: lint:: LevelAndSource ;
@@ -32,7 +31,8 @@ use std::cmp;
3231fn lint_levels ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> LintLevelMap {
3332 assert_eq ! ( cnum, LOCAL_CRATE ) ;
3433 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) ;
3636 let mut builder = LintLevelMapBuilder { levels, tcx, store } ;
3737 let krate = tcx. hir ( ) . krate ( ) ;
3838
@@ -56,6 +56,7 @@ pub struct LintLevelsBuilder<'s> {
5656 cur : u32 ,
5757 warn_about_weird_lints : bool ,
5858 store : & ' s LintStore ,
59+ crate_attrs : & ' s [ ast:: Attribute ] ,
5960}
6061
6162pub struct BuilderPush {
@@ -64,14 +65,20 @@ pub struct BuilderPush {
6465}
6566
6667impl < ' 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 {
6874 let mut builder = LintLevelsBuilder {
6975 sess,
7076 sets : LintLevelSets :: new ( ) ,
7177 cur : 0 ,
7278 id_to_set : Default :: default ( ) ,
7379 warn_about_weird_lints,
7480 store,
81+ crate_attrs,
7582 } ;
7683 builder. process_command_line ( sess, store) ;
7784 assert_eq ! ( builder. sets. list. len( ) , 1 ) ;
@@ -304,15 +311,22 @@ impl<'s> LintLevelsBuilder<'s> {
304311 } ;
305312 let tool_name = if meta_item. path . segments . len ( ) > 1 {
306313 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 ! (
309316 sess,
310317 tool_ident. span,
311318 E0710 ,
312- "an unknown tool name found in scoped lint: `{}`" ,
319+ "unknown tool name `{}` found in scoped lint: `{}`" ,
320+ tool_ident. name,
313321 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 ( ) ;
316330 continue ;
317331 }
318332
@@ -559,6 +573,20 @@ impl<'s> LintLevelsBuilder<'s> {
559573 }
560574}
561575
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+
562590struct LintLevelMapBuilder < ' a , ' tcx > {
563591 levels : LintLevelsBuilder < ' tcx > ,
564592 tcx : TyCtxt < ' tcx > ,
0 commit comments