@@ -8,7 +8,7 @@ use rustc_middle::hir::map::Map;
8
8
use rustc_middle:: ty:: query:: Providers ;
9
9
use rustc_middle:: ty:: TyCtxt ;
10
10
11
- use rustc_ast:: { Attribute , Lit , LitKind , NestedMetaItem } ;
11
+ use rustc_ast:: { AttrStyle , Attribute , Lit , LitKind , NestedMetaItem } ;
12
12
use rustc_errors:: { pluralize, struct_span_err, Applicability } ;
13
13
use rustc_hir as hir;
14
14
use rustc_hir:: def_id:: LocalDefId ;
@@ -564,7 +564,7 @@ impl CheckAttrVisitor<'tcx> {
564
564
true
565
565
}
566
566
567
- fn check_attr_crate_level (
567
+ fn check_attr_not_crate_level (
568
568
& self ,
569
569
meta : & NestedMetaItem ,
570
570
hir_id : HirId ,
@@ -586,6 +586,48 @@ impl CheckAttrVisitor<'tcx> {
586
586
true
587
587
}
588
588
589
+ fn check_attr_crate_level (
590
+ & self ,
591
+ attr : & Attribute ,
592
+ meta : & NestedMetaItem ,
593
+ hir_id : HirId ,
594
+ ) -> bool {
595
+ if hir_id != CRATE_HIR_ID {
596
+ self . tcx . struct_span_lint_hir (
597
+ INVALID_DOC_ATTRIBUTES ,
598
+ hir_id,
599
+ meta. span ( ) ,
600
+ |lint| {
601
+ let mut err = lint. build (
602
+ "this attribute can only be applied at the crate level" ,
603
+ ) ;
604
+ if attr. style == AttrStyle :: Outer && self . tcx . hir ( ) . get_parent_item ( hir_id) == CRATE_HIR_ID {
605
+ if let Ok ( mut src) =
606
+ self . tcx . sess . source_map ( ) . span_to_snippet ( attr. span )
607
+ {
608
+ src. insert ( 1 , '!' ) ;
609
+ err. span_suggestion_verbose (
610
+ attr. span ,
611
+ "to apply to the crate, use an inner attribute" ,
612
+ src,
613
+ Applicability :: MaybeIncorrect ,
614
+ ) ;
615
+ } else {
616
+ err. span_help (
617
+ attr. span ,
618
+ "to apply to the crate, use an inner attribute" ,
619
+ ) ;
620
+ }
621
+ }
622
+ err. note ( "read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information" )
623
+ . emit ( ) ;
624
+ } ,
625
+ ) ;
626
+ return false ;
627
+ }
628
+ true
629
+ }
630
+
589
631
fn check_doc_attrs ( & self , attr : & Attribute , hir_id : HirId , target : Target ) -> bool {
590
632
let mut is_valid = true ;
591
633
@@ -594,35 +636,58 @@ impl CheckAttrVisitor<'tcx> {
594
636
if let Some ( i_meta) = meta. meta_item ( ) {
595
637
match i_meta. name_or_empty ( ) {
596
638
sym:: alias
597
- if !self . check_attr_crate_level ( & meta, hir_id, "alias" )
639
+ if !self . check_attr_not_crate_level ( & meta, hir_id, "alias" )
598
640
|| !self . check_doc_alias ( & meta, hir_id, target) =>
599
641
{
600
642
is_valid = false
601
643
}
602
644
603
645
sym:: keyword
604
- if !self . check_attr_crate_level ( & meta, hir_id, "keyword" )
646
+ if !self . check_attr_not_crate_level ( & meta, hir_id, "keyword" )
605
647
|| !self . check_doc_keyword ( & meta, hir_id) =>
606
648
{
607
649
is_valid = false
608
650
}
609
651
610
- sym:: test if CRATE_HIR_ID != hir_id => {
652
+ sym:: html_favicon_url
653
+ | sym:: html_logo_url
654
+ | sym:: html_playground_url
655
+ | sym:: issue_tracker_base_url
656
+ | sym:: html_root_url
657
+ | sym:: html_no_source
658
+ | sym:: test
659
+ if !self . check_attr_crate_level ( & attr, & meta, hir_id) =>
660
+ {
661
+ is_valid = false ;
662
+ }
663
+
664
+ sym:: inline | sym:: no_inline if target != Target :: Use => {
611
665
self . tcx . struct_span_lint_hir (
612
666
INVALID_DOC_ATTRIBUTES ,
613
667
hir_id,
614
668
meta. span ( ) ,
615
669
|lint| {
616
- lint. build (
617
- "`#![doc(test(...)]` is only allowed \
618
- as a crate-level attribute",
619
- )
620
- . emit ( ) ;
670
+ let mut err = lint. build (
671
+ "this attribute can only be applied to a `use` item" ,
672
+ ) ;
673
+ err. span_label ( meta. span ( ) , "only applicable on `use` items" ) ;
674
+ if attr. style == AttrStyle :: Outer {
675
+ err. span_label (
676
+ self . tcx . hir ( ) . span ( hir_id) ,
677
+ "not a `use` item" ,
678
+ ) ;
679
+ }
680
+ err. note ( "read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information" )
681
+ . emit ( ) ;
621
682
} ,
622
683
) ;
623
684
is_valid = false ;
624
685
}
625
686
687
+ sym:: inline | sym:: no_inline => {
688
+ // FIXME(#80275): conflicting inline attributes
689
+ }
690
+
626
691
// no_default_passes: deprecated
627
692
// passes: deprecated
628
693
// plugins: removed, but rustdoc warns about it itself
@@ -635,12 +700,10 @@ impl CheckAttrVisitor<'tcx> {
635
700
| sym:: html_playground_url
636
701
| sym:: html_root_url
637
702
| sym:: include
638
- | sym:: inline
639
703
| sym:: issue_tracker_base_url
640
704
| sym:: keyword
641
705
| sym:: masked
642
706
| sym:: no_default_passes
643
- | sym:: no_inline
644
707
| sym:: notable_trait
645
708
| sym:: passes
646
709
| sym:: plugins
0 commit comments