Skip to content

Add is_inner information to rustdoc-json-types #140409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ impl AttributeExt for Attribute {
}
}

fn style(&self) -> AttrStyle {
self.style
fn opt_style(&self) -> Option<AttrStyle> {
Some(self.style)
}
}

Expand Down Expand Up @@ -806,7 +806,14 @@ pub trait AttributeExt: Debug {
/// * `#[doc(...)]` returns `None`.
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>;

fn style(&self) -> AttrStyle;
fn style(&self) -> AttrStyle {
match self.opt_style() {
Some(style) => style,
None => panic!("AttributeExt::style: `{self:?}` has no style"),
}
}

fn opt_style(&self) -> Option<AttrStyle>;
}

// FIXME(fn_delegation): use function delegation instead of manually forwarding
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,11 +1245,11 @@ impl AttributeExt for Attribute {
}

#[inline]
fn style(&self) -> AttrStyle {
fn opt_style(&self) -> Option<AttrStyle> {
match &self {
Attribute::Unparsed(u) => u.style,
Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style,
_ => panic!(),
Attribute::Unparsed(u) => Some(u.style),
Attribute::Parsed(AttributeKind::DocComment { style, .. }) => Some(*style),
_ => None,
}
}
}
Expand Down Expand Up @@ -1345,6 +1345,11 @@ impl Attribute {
pub fn style(&self) -> AttrStyle {
AttributeExt::style(self)
}

#[inline]
pub fn opt_style(&self) -> Option<AttrStyle> {
AttributeExt::opt_style(self)
}
}

/// Attributes owned by a HIR owner.
Expand Down
24 changes: 18 additions & 6 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{fmt, iter};

use arrayvec::ArrayVec;
use rustc_abi::{ExternAbi, VariantIdx};
use rustc_ast::AttrStyle;
use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::def::{CtorKind, DefKind, Res};
Expand Down Expand Up @@ -759,13 +760,20 @@ impl Item {
Some(tcx.visibility(def_id))
}

pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
/// Returns a Vec of stringified attributes with a boolean set to `true` if it's an inner
/// attribute.
pub(crate) fn attributes(
&self,
tcx: TyCtxt<'_>,
cache: &Cache,
is_json: bool,
) -> Vec<(bool, String)> {
const ALLOWED_ATTRIBUTES: &[Symbol] =
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];

use rustc_abi::IntegerType;

let mut attrs: Vec<String> = self
let mut attrs: Vec<(bool, String)> = self
.attrs
.other_attrs
.iter()
Expand All @@ -786,15 +794,19 @@ impl Item {
// because it isn't public API.
None
}
_ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
_ => Some((
attr.opt_style() == Some(AttrStyle::Inner),
rustc_hir_pretty::attribute_to_string(&tcx, attr),
)),
}
} else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
Some(
Some((
attr.opt_style() == Some(AttrStyle::Inner),
rustc_hir_pretty::attribute_to_string(&tcx, attr)
.replace("\\\n", "")
.replace('\n', "")
.replace(" ", " "),
)
))
} else {
None
}
Expand Down Expand Up @@ -860,7 +872,7 @@ impl Item {
out.push(&int_s);
}
if !out.is_empty() {
attrs.push(format!("#[repr({})]", out.join(", ")));
attrs.push((false, format!("#[repr({})]", out.join(", "))));
}
}
attrs
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ fn render_assoc_item(
// a whitespace prefix and newline.
fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
fmt::from_fn(move |f| {
for a in it.attributes(cx.tcx(), cx.cache(), false) {
for (_, a) in it.attributes(cx.tcx(), cx.cache(), false) {
writeln!(f, "{prefix}{a}")?;
}
Ok(())
Expand All @@ -1204,7 +1204,7 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) ->
// When an attribute is rendered inside a <code> tag, it is formatted using
// a div to produce a newline after it.
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
for attr in it.attributes(cx.tcx(), cx.cache(), false) {
for (_, attr) in it.attributes(cx.tcx(), cx.cache(), false) {
write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ impl JsonRenderer<'_> {
})
.collect();
let docs = item.opt_doc_value();
let attrs = item.attributes(self.tcx, self.cache(), true);
let attrs = item
.attributes(self.tcx, self.cache(), true)
.into_iter()
.map(|(is_inner, content)| Attribute { is_inner, content })
.collect::<Vec<_>>();
let span = item.span(self.tcx);
let visibility = item.visibility(self.tcx);
let clean::ItemInner { name, item_id, .. } = *item.inner;
Expand Down Expand Up @@ -767,7 +771,11 @@ impl FromClean<clean::ProcMacro> for ProcMacro {
fn from_clean(mac: clean::ProcMacro, _renderer: &JsonRenderer<'_>) -> Self {
ProcMacro {
kind: from_macro_kind(mac.kind),
helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
helpers: mac
.helpers
.iter()
.map(|x| Attribute { is_inner: false, content: x.to_string() })
.collect(),
}
}
}
Expand Down
15 changes: 12 additions & 3 deletions src/rustdoc-json-types/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
/// This integer is incremented with every breaking change to the API,
/// and is returned along with the JSON blob as [`Crate::format_version`].
/// Consuming code should assert that this value matches the format version(s) that it supports.
pub const FORMAT_VERSION: u32 = 45;
pub const FORMAT_VERSION: u32 = 46;

/// The root of the emitted JSON blob.
///
Expand Down Expand Up @@ -152,6 +152,15 @@ pub struct ItemSummary {
pub kind: ItemKind,
}

/// An attribute (like `#[inline]`).
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct Attribute {
/// Whether it is an inner (`#![]`) or an outer attribute (`#[]`).
pub is_inner: bool,
/// The content of the attribute.
pub content: String,
}

/// Anything that can hold documentation - modules, structs, enums, functions, traits, etc.
///
/// The `Item` data type holds fields that can apply to any of these,
Expand Down Expand Up @@ -193,7 +202,7 @@ pub struct Item {
///
/// As an internal implementation detail subject to change, this debug-printing format
/// is currently equivalent to the HIR pretty-printing of parsed attributes.
pub attrs: Vec<String>,
pub attrs: Vec<Attribute>,
/// Information about the item’s deprecation, if present.
pub deprecation: Option<Deprecation>,
/// The type-specific fields describing this item.
Expand Down Expand Up @@ -1301,7 +1310,7 @@ pub struct ProcMacro {
/// Some(T),
/// }
/// ```
pub helpers: Vec<String>,
pub helpers: Vec<Attribute>,
}

/// The way a [`ProcMacro`] is declared to be used.
Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc-json/attrs/automatically_derived.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ impl Default for Manual {
}
}

//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]'
//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '[{"content": "#[automatically_derived]", "is_inner": false}]'
//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]'
2 changes: 1 addition & 1 deletion tests/rustdoc-json/attrs/export_name_2021.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ edition: 2021
#![no_std]

//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
//@ is "$.index[?(@.name=='example')].attrs" '[{"content": "#[export_name = \"altered\"]", "is_inner": false}]'
#[export_name = "altered"]
pub extern "C" fn example() {}
2 changes: 1 addition & 1 deletion tests/rustdoc-json/attrs/export_name_2024.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
// The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024
// is still `#[export_name = ..]` without the `unsafe` attribute wrapper.

//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]'
//@ is "$.index[?(@.name=='example')].attrs" '[{"content": "#[export_name = \"altered\"]", "is_inner": false}]'
#[unsafe(export_name = "altered")]
pub extern "C" fn example() {}
7 changes: 7 additions & 0 deletions tests/rustdoc-json/attrs/inner_vs_outer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![no_std]

//@ is "$.index[?(@.name=='foo')].attrs" '[{"content": "#[allow(unused)]", "is_inner": false}, {"content": "#[allow(dead_code)]", "is_inner": true}]'
#[allow(unused)]
pub mod foo {
#![allow(dead_code)]
}
4 changes: 2 additions & 2 deletions tests/rustdoc-json/attrs/must_use.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![no_std]

//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]"]'
//@ is "$.index[?(@.name=='example')].attrs" '[{"content": "#[must_use]", "is_inner": false}]'
#[must_use]
pub fn example() -> impl Iterator<Item = i64> {}

//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]'
//@ is "$.index[?(@.name=='explicit_message')].attrs" '[{"content": "#[must_use = \"does nothing if you do not use it\"]", "is_inner": false}]'
#[must_use = "does nothing if you do not use it"]
pub fn explicit_message() -> impl Iterator<Item = i64> {}
2 changes: 1 addition & 1 deletion tests/rustdoc-json/attrs/no_mangle_2021.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ edition: 2021
#![no_std]

//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]'
//@ is "$.index[?(@.name=='example')].attrs" '[{"content": "#[no_mangle]", "is_inner": false}]'
#[no_mangle]
pub extern "C" fn example() {}
2 changes: 1 addition & 1 deletion tests/rustdoc-json/attrs/no_mangle_2024.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
// The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024
// is still `#[no_mangle]` without the `unsafe` attribute wrapper.

//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]'
//@ is "$.index[?(@.name=='example')].attrs" '[{"content": "#[no_mangle]", "is_inner": false}]'
#[unsafe(no_mangle)]
pub extern "C" fn example() {}
6 changes: 3 additions & 3 deletions tests/rustdoc-json/attrs/non_exhaustive.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
#![no_std]

//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]'
//@ is "$.index[?(@.name=='MyEnum')].attrs" '[{"content": "#[non_exhaustive]", "is_inner": false}]'
#[non_exhaustive]
pub enum MyEnum {
First,
}

pub enum NonExhaustiveVariant {
//@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]'
//@ is "$.index[?(@.name=='Variant')].attrs" '[{"content": "#[non_exhaustive]", "is_inner": false}]'
#[non_exhaustive]
Variant(i64),
}

//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]'
//@ is "$.index[?(@.name=='MyStruct')].attrs" '[{"content": "#[non_exhaustive]", "is_inner": false}]'
#[non_exhaustive]
pub struct MyStruct {
pub x: i64,
Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc-json/attrs/repr_align.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![no_std]

//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]'
//@ is "$.index[?(@.name=='Aligned')].attrs" '[{"content": "#[repr(align(4))]", "is_inner": false}]'
#[repr(align(4))]
pub struct Aligned {
a: i8,
Expand Down
6 changes: 3 additions & 3 deletions tests/rustdoc-json/attrs/repr_c.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#![no_std]

//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]'
//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '[{"content": "#[repr(C)]", "is_inner": false}]'
#[repr(C)]
pub struct ReprCStruct(pub i64);

//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]'
//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '[{"content": "#[repr(C)]", "is_inner": false}]'
#[repr(C)]
pub enum ReprCEnum {
First,
}

//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]'
//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '[{"content": "#[repr(C)]", "is_inner": false}]'
#[repr(C)]
pub union ReprCUnion {
pub left: i64,
Expand Down
Loading
Loading