Skip to content

Commit 06238bd

Browse files
Update rustdoc JSON output to new attribute API
1 parent 2340f80 commit 06238bd

File tree

2 files changed

+155
-12
lines changed

2 files changed

+155
-12
lines changed

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::borrow::Cow;
2+
use std::fmt;
23
use std::path::PathBuf;
34

45
pub use ReprAttr::*;
@@ -231,6 +232,43 @@ impl CfgEntry {
231232
}
232233
}
233234

235+
impl fmt::Display for CfgEntry {
236+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237+
fn write_entries(
238+
name: &str,
239+
entries: &[CfgEntry],
240+
f: &mut fmt::Formatter<'_>,
241+
) -> fmt::Result {
242+
write!(f, "{name}(")?;
243+
for (nb, entry) in entries.iter().enumerate() {
244+
if nb != 0 {
245+
f.write_str(", ")?;
246+
}
247+
entry.fmt(f)?;
248+
}
249+
f.write_str(")")
250+
}
251+
match self {
252+
Self::All(entries, _) => write_entries("all", entries, f),
253+
Self::Any(entries, _) => write_entries("any", entries, f),
254+
Self::Not(entry, _) => write!(f, "not({entry})"),
255+
Self::Bool(value, _) => write!(f, "{value}"),
256+
Self::NameValue { name, value, .. } => {
257+
match value {
258+
// We use `as_str` and debug display to have characters escaped and `"`
259+
// characters surrounding the string.
260+
Some((value, _)) => write!(f, "{name} = {:?}", value.as_str()),
261+
None => write!(f, "{name}"),
262+
}
263+
}
264+
Self::Version(version, _) => match version {
265+
Some(version) => write!(f, "{version}"),
266+
None => Ok(()),
267+
},
268+
}
269+
}
270+
}
271+
234272
/// Possible values for the `#[linkage]` attribute, allowing to specify the
235273
/// linkage type for a `MonoItem`.
236274
///

src/librustdoc/json/conversions.rs

Lines changed: 117 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ use rustc_ast::ast;
77
use rustc_data_structures::fx::FxHashSet;
88
use rustc_data_structures::thin_vec::ThinVec;
99
use rustc_hir as hir;
10-
use rustc_hir::attrs::{self, DeprecatedSince};
10+
use rustc_hir::attrs::{self, DeprecatedSince, DocAttribute, DocInline, HideOrShow};
1111
use rustc_hir::def::CtorKind;
1212
use rustc_hir::def_id::DefId;
1313
use rustc_hir::{HeaderSafety, Safety};
1414
use rustc_metadata::rendered_const;
1515
use rustc_middle::ty::TyCtxt;
1616
use rustc_middle::{bug, ty};
17-
use rustc_span::{Pos, kw, sym};
17+
use rustc_span::{Pos, Symbol, kw, sym};
1818
use rustdoc_json_types::*;
1919

2020
use 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

9471052
fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute {

0 commit comments

Comments
 (0)