@@ -7,14 +7,14 @@ use rustc_ast::ast;
77use rustc_data_structures:: fx:: FxHashSet ;
88use rustc_data_structures:: thin_vec:: ThinVec ;
99use rustc_hir as hir;
10- use rustc_hir:: attrs:: { self , DeprecatedSince } ;
10+ use rustc_hir:: attrs:: { self , DeprecatedSince , DocAttribute , DocInline , HideOrShow } ;
1111use rustc_hir:: def:: CtorKind ;
1212use rustc_hir:: def_id:: DefId ;
1313use rustc_hir:: { HeaderSafety , Safety } ;
1414use rustc_metadata:: rendered_const;
1515use rustc_middle:: ty:: TyCtxt ;
1616use rustc_middle:: { bug, ty} ;
17- use rustc_span:: { Pos , kw, sym} ;
17+ use rustc_span:: { Pos , Symbol , kw, sym} ;
1818use rustdoc_json_types:: * ;
1919
2020use crate :: clean:: { self , ItemId } ;
@@ -46,7 +46,7 @@ impl JsonRenderer<'_> {
4646 . attrs
4747 . other_attrs
4848 . iter ( )
49- . filter_map ( |a| maybe_from_hir_attr ( a, item. item_id , self . tcx ) )
49+ . flat_map ( |a| maybe_from_hir_attr ( a, item. item_id , self . tcx ) )
5050 . collect ( ) ;
5151 let span = item. span ( self . tcx ) ;
5252 let visibility = item. visibility ( self . tcx ) ;
@@ -902,24 +902,20 @@ impl FromClean<ItemType> for ItemKind {
902902/// Maybe convert a attribute from hir to json.
903903///
904904/// Returns `None` if the attribute shouldn't be in the output.
905- fn maybe_from_hir_attr (
906- attr : & hir:: Attribute ,
907- item_id : ItemId ,
908- tcx : TyCtxt < ' _ > ,
909- ) -> Option < Attribute > {
905+ fn maybe_from_hir_attr ( attr : & hir:: Attribute , item_id : ItemId , tcx : TyCtxt < ' _ > ) -> Vec < Attribute > {
910906 use attrs:: AttributeKind as AK ;
911907
912908 let kind = match attr {
913909 hir:: Attribute :: Parsed ( kind) => kind,
914910
915911 hir:: Attribute :: Unparsed ( _) => {
916912 // FIXME: We should handle `#[doc(hidden)]`.
917- return Some ( other_attr ( tcx, attr) ) ;
913+ return vec ! [ other_attr( tcx, attr) ] ;
918914 }
919915 } ;
920916
921- Some ( match kind {
922- AK :: Deprecation { .. } => return None , // Handled separately into Item::deprecation.
917+ vec ! [ match kind {
918+ AK :: Deprecation { .. } => return Vec :: new ( ) , // Handled separately into Item::deprecation.
923919 AK :: DocComment { .. } => unreachable!( "doc comments stripped out earlier" ) ,
924920
925921 AK :: MacroExport { .. } => Attribute :: MacroExport ,
@@ -939,9 +935,118 @@ fn maybe_from_hir_attr(
939935 AK :: NoMangle ( _) => Attribute :: NoMangle ,
940936 AK :: NonExhaustive ( _) => Attribute :: NonExhaustive ,
941937 AK :: AutomaticallyDerived ( _) => Attribute :: AutomaticallyDerived ,
938+ AK :: Doc ( d) => {
939+ fn toggle_attr( ret: & mut Vec <Attribute >, name: & str , v: & Option <rustc_span:: Span >) {
940+ if v. is_some( ) {
941+ ret. push( Attribute :: Other ( format!( "#[doc({name})]" ) ) ) ;
942+ }
943+ }
944+
945+ fn name_value_attr(
946+ ret: & mut Vec <Attribute >,
947+ name: & str ,
948+ v: & Option <( Symbol , rustc_span:: Span ) >,
949+ ) {
950+ if let Some ( ( v, _) ) = v {
951+ // We use `as_str` and debug display to have characters escaped and `"`
952+ // characters surrounding the string.
953+ ret. push( Attribute :: Other ( format!( "#[doc({name} = {:?})]" , v. as_str( ) ) ) ) ;
954+ }
955+ }
956+
957+ let DocAttribute {
958+ aliases,
959+ hidden,
960+ inline,
961+ cfg,
962+ auto_cfg,
963+ auto_cfg_change,
964+ fake_variadic,
965+ keyword,
966+ attribute,
967+ masked,
968+ notable_trait,
969+ search_unbox,
970+ html_favicon_url,
971+ html_logo_url,
972+ html_playground_url,
973+ html_root_url,
974+ html_no_source,
975+ issue_tracker_base_url,
976+ rust_logo,
977+ test_attrs,
978+ no_crate_inject,
979+ } = & * * d;
980+
981+ let mut ret = Vec :: new( ) ;
982+
983+ for ( alias, _) in aliases {
984+ // We use `as_str` and debug display to have characters escaped and `"` characters
985+ // surrounding the string.
986+ ret. push( Attribute :: Other ( format!( "#[doc(alias = {:?})]" , alias. as_str( ) ) ) ) ;
987+ }
988+ toggle_attr( & mut ret, "hidden" , hidden) ;
989+ if let Some ( inline) = inline. first( ) {
990+ ret. push( Attribute :: Other ( format!(
991+ "#[doc({})]" ,
992+ match inline. 0 {
993+ DocInline :: Inline => "inline" ,
994+ DocInline :: NoInline => "no_inline" ,
995+ }
996+ ) ) ) ;
997+ }
998+ for sub_cfg in cfg {
999+ ret. push( Attribute :: Other ( format!( "#[doc(cfg({sub_cfg}))]" ) ) ) ;
1000+ }
1001+ for ( auto_cfg, _) in auto_cfg {
1002+ let kind = match auto_cfg. kind {
1003+ HideOrShow :: Hide => "hide" ,
1004+ HideOrShow :: Show => "show" ,
1005+ } ;
1006+ let mut out = format!( "#[doc(auto_cfg({kind}(" ) ;
1007+ for ( pos, value) in auto_cfg. values. iter( ) . enumerate( ) {
1008+ if pos > 0 {
1009+ out. push_str( ", " ) ;
1010+ }
1011+ out. push_str( value. name. as_str( ) ) ;
1012+ if let Some ( ( value, _) ) = value. value {
1013+ // We use `as_str` and debug display to have characters escaped and `"`
1014+ // characters surrounding the string.
1015+ out. push_str( & format!( " = {:?}" , value. as_str( ) ) ) ;
1016+ }
1017+ }
1018+ out. push_str( ")))]" ) ;
1019+ ret. push( Attribute :: Other ( out) ) ;
1020+ }
1021+ for ( change, _) in auto_cfg_change {
1022+ ret. push( Attribute :: Other ( format!( "#[doc(auto_cfg = {change})]" ) ) ) ;
1023+ }
1024+ toggle_attr( & mut ret, "fake_variadic" , fake_variadic) ;
1025+ name_value_attr( & mut ret, "keyword" , keyword) ;
1026+ name_value_attr( & mut ret, "attribute" , attribute) ;
1027+ toggle_attr( & mut ret, "masked" , masked) ;
1028+ toggle_attr( & mut ret, "notable_trait" , notable_trait) ;
1029+ toggle_attr( & mut ret, "search_unbox" , search_unbox) ;
1030+ name_value_attr( & mut ret, "html_favicon_url" , html_favicon_url) ;
1031+ name_value_attr( & mut ret, "html_logo_url" , html_logo_url) ;
1032+ name_value_attr( & mut ret, "html_playground_url" , html_playground_url) ;
1033+ name_value_attr( & mut ret, "html_root_url" , html_root_url) ;
1034+ toggle_attr( & mut ret, "html_no_source" , html_no_source) ;
1035+ name_value_attr( & mut ret, "issue_tracker_base_url" , issue_tracker_base_url) ;
1036+ toggle_attr( & mut ret, "rust_logo" , rust_logo) ;
1037+ let source_map = tcx. sess. source_map( ) ;
1038+ for attr_span in test_attrs {
1039+ // FIXME: This is ugly, remove when `test_attrs` has been ported to new attribute API.
1040+ if let Ok ( snippet) = source_map. span_to_snippet( * attr_span) {
1041+ ret. push( Attribute :: Other ( format!( "#[doc(test(attr({snippet})))" ) ) ) ;
1042+ }
1043+ }
1044+ toggle_attr( & mut ret, "no_crate_inject" , no_crate_inject) ;
1045+ return ret;
1046+ }
9421047
9431048 _ => other_attr( tcx, attr) ,
944- } )
1049+ } ]
9451050}
9461051
9471052fn other_attr ( tcx : TyCtxt < ' _ > , attr : & hir:: Attribute ) -> Attribute {
0 commit comments