@@ -78,7 +78,7 @@ impl CheckAttrVisitor<'tcx> {
78
78
} else if self . tcx . sess . check_name ( attr, sym:: track_caller) {
79
79
self . check_track_caller ( & attr. span , attrs, span, target)
80
80
} else if self . tcx . sess . check_name ( attr, sym:: doc) {
81
- self . check_doc_alias ( attr, hir_id, target)
81
+ self . check_doc_attrs ( attr, hir_id, target)
82
82
} else if self . tcx . sess . check_name ( attr, sym:: no_link) {
83
83
self . check_no_link ( & attr, span, target)
84
84
} else if self . tcx . sess . check_name ( attr, sym:: export_name) {
@@ -297,89 +297,103 @@ impl CheckAttrVisitor<'tcx> {
297
297
. emit ( ) ;
298
298
}
299
299
300
- fn check_doc_alias ( & self , attr : & Attribute , hir_id : HirId , target : Target ) -> bool {
300
+ fn check_doc_alias ( & self , meta : & NestedMetaItem , hir_id : HirId , target : Target ) -> bool {
301
+ if !meta. is_value_str ( ) {
302
+ self . doc_alias_str_error ( meta) ;
303
+ return false ;
304
+ }
305
+ let doc_alias = meta. value_str ( ) . map ( |s| s. to_string ( ) ) . unwrap_or_else ( String :: new) ;
306
+ if doc_alias. is_empty ( ) {
307
+ self . doc_alias_str_error ( meta) ;
308
+ return false ;
309
+ }
310
+ if let Some ( c) =
311
+ doc_alias. chars ( ) . find ( |& c| c == '"' || c == '\'' || ( c. is_whitespace ( ) && c != ' ' ) )
312
+ {
313
+ self . tcx
314
+ . sess
315
+ . struct_span_err (
316
+ meta. name_value_literal_span ( ) . unwrap_or_else ( || meta. span ( ) ) ,
317
+ & format ! ( "{:?} character isn't allowed in `#[doc(alias = \" ...\" )]`" , c, ) ,
318
+ )
319
+ . emit ( ) ;
320
+ return false ;
321
+ }
322
+ if doc_alias. starts_with ( ' ' ) || doc_alias. ends_with ( ' ' ) {
323
+ self . tcx
324
+ . sess
325
+ . struct_span_err (
326
+ meta. name_value_literal_span ( ) . unwrap_or_else ( || meta. span ( ) ) ,
327
+ "`#[doc(alias = \" ...\" )]` cannot start or end with ' '" ,
328
+ )
329
+ . emit ( ) ;
330
+ return false ;
331
+ }
332
+ if let Some ( err) = match target {
333
+ Target :: Impl => Some ( "implementation block" ) ,
334
+ Target :: ForeignMod => Some ( "extern block" ) ,
335
+ Target :: AssocTy => {
336
+ let parent_hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
337
+ let containing_item = self . tcx . hir ( ) . expect_item ( parent_hir_id) ;
338
+ if Target :: from_item ( containing_item) == Target :: Impl {
339
+ Some ( "type alias in implementation block" )
340
+ } else {
341
+ None
342
+ }
343
+ }
344
+ Target :: AssocConst => {
345
+ let parent_hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
346
+ let containing_item = self . tcx . hir ( ) . expect_item ( parent_hir_id) ;
347
+ // We can't link to trait impl's consts.
348
+ let err = "associated constant in trait implementation block" ;
349
+ match containing_item. kind {
350
+ ItemKind :: Impl { of_trait : Some ( _) , .. } => Some ( err) ,
351
+ _ => None ,
352
+ }
353
+ }
354
+ _ => None ,
355
+ } {
356
+ self . tcx
357
+ . sess
358
+ . struct_span_err (
359
+ meta. span ( ) ,
360
+ & format ! ( "`#[doc(alias = \" ...\" )]` isn't allowed on {}" , err) ,
361
+ )
362
+ . emit ( ) ;
363
+ return false ;
364
+ }
365
+ true
366
+ }
367
+
368
+ fn check_attr_crate_level (
369
+ & self ,
370
+ meta : & NestedMetaItem ,
371
+ hir_id : HirId ,
372
+ attr_name : & str ,
373
+ ) -> bool {
374
+ if CRATE_HIR_ID == hir_id {
375
+ self . tcx
376
+ . sess
377
+ . struct_span_err (
378
+ meta. span ( ) ,
379
+ & format ! (
380
+ "`#![doc({} = \" ...\" )]` isn't allowed as a crate level attribute" ,
381
+ attr_name,
382
+ ) ,
383
+ )
384
+ . emit ( ) ;
385
+ return false ;
386
+ }
387
+ }
388
+
389
+ fn check_doc_attrs ( & self , attr : & Attribute , hir_id : HirId , target : Target ) -> bool {
301
390
if let Some ( mi) = attr. meta ( ) {
302
391
if let Some ( list) = mi. meta_item_list ( ) {
303
392
for meta in list {
304
393
if meta. has_name ( sym:: alias) {
305
- if !meta. is_value_str ( ) {
306
- self . doc_alias_str_error ( meta) ;
307
- return false ;
308
- }
309
- let doc_alias =
310
- meta. value_str ( ) . map ( |s| s. to_string ( ) ) . unwrap_or_else ( String :: new) ;
311
- if doc_alias. is_empty ( ) {
312
- self . doc_alias_str_error ( meta) ;
313
- return false ;
314
- }
315
- if let Some ( c) = doc_alias
316
- . chars ( )
317
- . find ( |& c| c == '"' || c == '\'' || ( c. is_whitespace ( ) && c != ' ' ) )
394
+ if !self . check_attr_crate_level ( meta, hir_id, "alias" )
395
+ || !self . check_doc_alias ( meta, hir_id, target)
318
396
{
319
- self . tcx
320
- . sess
321
- . struct_span_err (
322
- meta. name_value_literal_span ( ) . unwrap_or_else ( || meta. span ( ) ) ,
323
- & format ! (
324
- "{:?} character isn't allowed in `#[doc(alias = \" ...\" )]`" ,
325
- c,
326
- ) ,
327
- )
328
- . emit ( ) ;
329
- return false ;
330
- }
331
- if doc_alias. starts_with ( ' ' ) || doc_alias. ends_with ( ' ' ) {
332
- self . tcx
333
- . sess
334
- . struct_span_err (
335
- meta. name_value_literal_span ( ) . unwrap_or_else ( || meta. span ( ) ) ,
336
- "`#[doc(alias = \" ...\" )]` cannot start or end with ' '" ,
337
- )
338
- . emit ( ) ;
339
- return false ;
340
- }
341
- if let Some ( err) = match target {
342
- Target :: Impl => Some ( "implementation block" ) ,
343
- Target :: ForeignMod => Some ( "extern block" ) ,
344
- Target :: AssocTy => {
345
- let parent_hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
346
- let containing_item = self . tcx . hir ( ) . expect_item ( parent_hir_id) ;
347
- if Target :: from_item ( containing_item) == Target :: Impl {
348
- Some ( "type alias in implementation block" )
349
- } else {
350
- None
351
- }
352
- }
353
- Target :: AssocConst => {
354
- let parent_hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
355
- let containing_item = self . tcx . hir ( ) . expect_item ( parent_hir_id) ;
356
- // We can't link to trait impl's consts.
357
- let err = "associated constant in trait implementation block" ;
358
- match containing_item. kind {
359
- ItemKind :: Impl { of_trait : Some ( _) , .. } => Some ( err) ,
360
- _ => None ,
361
- }
362
- }
363
- _ => None ,
364
- } {
365
- self . tcx
366
- . sess
367
- . struct_span_err (
368
- meta. span ( ) ,
369
- & format ! ( "`#[doc(alias = \" ...\" )]` isn't allowed on {}" , err) ,
370
- )
371
- . emit ( ) ;
372
- return false ;
373
- }
374
- if CRATE_HIR_ID == hir_id {
375
- self . tcx
376
- . sess
377
- . struct_span_err (
378
- meta. span ( ) ,
379
- "`#![doc(alias = \" ...\" )]` isn't allowed as a crate \
380
- level attribute",
381
- )
382
- . emit ( ) ;
383
397
return false ;
384
398
}
385
399
}
0 commit comments