@@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath,
1010use rustc_middle:: ty;
1111use rustc_session:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
1212use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
13- use rustc_span:: symbol:: { sym, Ident , Symbol } ;
13+ use rustc_span:: symbol:: { kw , sym, Ident , Symbol } ;
1414
1515declare_tool_lint ! {
1616 pub rustc:: DEFAULT_HASH_TYPES ,
@@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl {
267267 }
268268 }
269269}
270+
271+ declare_tool_lint ! {
272+ pub rustc:: EXISTING_DOC_KEYWORD ,
273+ Deny ,
274+ "Check that documented keywords in std and core actually exist" ,
275+ report_in_external_macro: true
276+ }
277+
278+ declare_lint_pass ! ( ExistingDocKeyword => [ EXISTING_DOC_KEYWORD ] ) ;
279+
280+ fn is_doc_keyword ( s : Symbol ) -> bool {
281+ s <= kw:: Union
282+ }
283+
284+ impl < ' tcx > LateLintPass < ' tcx > for ExistingDocKeyword {
285+ fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & rustc_hir:: Item < ' _ > ) {
286+ for attr in item. attrs {
287+ if !attr. has_name ( sym:: doc) {
288+ continue ;
289+ }
290+ if let Some ( list) = attr. meta_item_list ( ) {
291+ for nested in list {
292+ if nested. has_name ( sym:: keyword) {
293+ let v = nested
294+ . value_str ( )
295+ . expect ( "#[doc(keyword = \" ...\" )] expected a value!" ) ;
296+ if is_doc_keyword ( v) {
297+ return ;
298+ }
299+ cx. struct_span_lint ( EXISTING_DOC_KEYWORD , attr. span , |lint| {
300+ lint. build ( & format ! (
301+ "Found non-existing keyword `{}` used in \
302+ `#[doc(keyword = \" ...\" )]`",
303+ v,
304+ ) )
305+ . help ( "only existing keywords are allowed in core/std" )
306+ . emit ( ) ;
307+ } ) ;
308+ }
309+ }
310+ }
311+ }
312+ }
313+ }
0 commit comments