Skip to content

Commit

Permalink
Rollup merge of rust-lang#132302 - fmease:rustdoc-better-vis-for-macr…
Browse files Browse the repository at this point in the history
…o-decl, r=notriddle

rustdoc: Treat declarative macros more like other item kinds

Apparently at some time in the past we were unable to generate an href for the module path inside the visibility of decl macros 2.0 (`pub(in ...)`). As a result of this, a whole separate function was introduced specifically for printing the visibility of decl macros that didn't attempt to generate any links. The description of PR rust-lang#84074 states:

> This fixes the overly-complex invariant mentioned in rust-lang#83237 (comment), where the macro source can't have any links in it only because the cache hasn't been populated yet.

I can no longer reproduce the original issue. Reusing the existing visibility rendering logic *seems* to work just fine (I couldn't come up with any counterexamples, though I invite you to prove me wrong).

* Fixes rust-lang#83000
* Fixes the visibility showing up "twice" in rustdoc-JSON output: Once as the `visibility` field, once baked into the source[^1]
* Fixes `#[doc(hidden)]` not getting rendered on doc(hidden) decl macros 2.0 under `--document-hiden-items` (for decl macros 1.2 the issue remains; I will address this separately when fixing rust-lang#132304).

---

<details><summary>Outdated Section</summary>

NOTE: The current version of this PR is committing a UI crime, I'd like to receive feedback on that. Maybe you have a satisfactory solution for how to remedy it. Namely, as you know we have two different ways of / modes for highlighting code with color:

1. Only highlighting links / item paths and avoiding to highlight tokens by kind like keywords (to reduce visual noise and maybe also artifact size). Used for item declarations(\*).
2. Highlighting tokens by kind. Used for code blocks written by the user.

(\*): With the notable exception being macro declarations! Well, since this PR reuses the same function for rendering the item visibility (which only makes sense), we have a clash of modes: We now use both ways of highlighting code for decl macros: №1 for the visibility, №2 for the rest. This awkward. See for yourself:

* On master: ![Screenshot 2024-10-29 at 03-37-48 by_example_vis_named in decl_macro a b c - Rust](https://github.com/user-attachments/assets/22f0ab6e-9ba9-4c4e-8fb0-0741c91d360b)
* On this branch: ![Screenshot 2024-10-29 at 03-36-41 by_example_vis_named in decl_macro a b c - Rust](https://github.com/user-attachments/assets/b11d81a3-3e2e-43cb-a5b8-6773a3048732)

</details>

Furthermore, we now no longer syntax-highlight declarative macros (be it `macro_rules!` or `macro`) since that was inconsistent with the way we render all other item kinds. See (collapsed) *Outdated Section* above. See also rust-lang#132302 (comment).

| On master | On this branch |
|---|---|
| ![Screenshot 2024-11-13 at 16-12-46 by_example_vis_named in decl_macro a b c - Rust](https://github.com/user-attachments/assets/cb3aeb42-a56d-4ced-80d9-f2694f369af1) | ![Screenshot 2024-11-13 at 16-13-22 by_example_vis_named in decl_macro a b c - Rust](https://github.com/user-attachments/assets/b73bee50-1b85-4862-afba-5ad471443ccc) |

[^1]: E.g., `"visibility":{"restricted":{"parent":1,"path":"::a"}},/*OMITTED*/,"inner":{"macro":"pub(in a) macro by_example_vis_named($foo:expr) {\n    ...\n}"}`
  • Loading branch information
matthiaskrgr authored Nov 13, 2024
2 parents f3df2a2 + 9016711 commit 3376eda
Show file tree
Hide file tree
Showing 9 changed files with 31 additions and 102 deletions.
18 changes: 5 additions & 13 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,7 @@ pub(crate) fn try_inline(
})
}
Res::Def(DefKind::Macro(kind), did) => {
let is_doc_hidden = cx.tcx.is_doc_hidden(did)
|| attrs_without_docs
.map(|(attrs, _)| attrs)
.is_some_and(|attrs| utils::attrs_have_doc_flag(attrs.iter(), sym::hidden));
let mac = build_macro(cx, did, name, import_def_id, kind, is_doc_hidden);
let mac = build_macro(cx, did, name, kind);

let type_kind = match kind {
MacroKind::Bang => ItemType::Macro,
Expand Down Expand Up @@ -740,18 +736,14 @@ fn build_macro(
cx: &mut DocContext<'_>,
def_id: DefId,
name: Symbol,
import_def_id: Option<LocalDefId>,
macro_kind: MacroKind,
is_doc_hidden: bool,
) -> clean::ItemKind {
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
LoadedMacro::MacroDef { def, .. } => match macro_kind {
MacroKind::Bang => {
let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
clean::MacroItem(clean::Macro {
source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden),
})
}
MacroKind::Bang => clean::MacroItem(clean::Macro {
source: utils::display_macro_source(cx, name, &def),
macro_rules: def.macro_rules,
}),
MacroKind::Derive | MacroKind::Attr => {
clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
}
Expand Down
11 changes: 4 additions & 7 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2787,13 +2787,10 @@ fn clean_maybe_renamed_item<'tcx>(
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
ItemKind::Macro(macro_def, MacroKind::Bang) => {
let ty_vis = cx.tcx.visibility(def_id);
MacroItem(Macro {
// FIXME this shouldn't be false
source: display_macro_source(cx, name, macro_def, def_id, ty_vis, false),
})
}
ItemKind::Macro(macro_def, MacroKind::Bang) => MacroItem(Macro {
source: display_macro_source(cx, name, macro_def),
macro_rules: macro_def.macro_rules,
}),
ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
// proc macros can have a name set by attributes
ItemKind::Fn(ref sig, generics, body_id) => {
Expand Down
2 changes: 2 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2543,6 +2543,8 @@ pub(crate) struct ImportSource {
#[derive(Clone, Debug)]
pub(crate) struct Macro {
pub(crate) source: String,
/// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
pub(crate) macro_rules: bool,
}

#[derive(Clone, Debug)]
Expand Down
15 changes: 3 additions & 12 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use crate::clean::{
clean_middle_ty, inline,
};
use crate::core::DocContext;
use crate::html::format::visibility_to_src_with_space;

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -593,7 +592,7 @@ pub(crate) static DOC_CHANNEL: Lazy<&'static str> =

/// Render a sequence of macro arms in a format suitable for displaying to the user
/// as part of an item declaration.
pub(super) fn render_macro_arms<'a>(
fn render_macro_arms<'a>(
tcx: TyCtxt<'_>,
matchers: impl Iterator<Item = &'a TokenTree>,
arm_delim: &str,
Expand All @@ -614,9 +613,6 @@ pub(super) fn display_macro_source(
cx: &mut DocContext<'_>,
name: Symbol,
def: &ast::MacroDef,
def_id: DefId,
vis: ty::Visibility<DefId>,
is_doc_hidden: bool,
) -> String {
// Extract the spans of all matchers. They represent the "interface" of the macro.
let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]);
Expand All @@ -626,18 +622,13 @@ pub(super) fn display_macro_source(
} else {
if matchers.len() <= 1 {
format!(
"{vis}macro {name}{matchers} {{\n ...\n}}",
vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
"macro {name}{matchers} {{\n ...\n}}",
matchers = matchers
.map(|matcher| render_macro_matcher(cx.tcx, matcher))
.collect::<String>(),
)
} else {
format!(
"{vis}macro {name} {{\n{arms}}}",
vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
arms = render_macro_arms(cx.tcx, matchers, ","),
)
format!("macro {name} {{\n{arms}}}", arms = render_macro_arms(cx.tcx, matchers, ","))
}
}
}
Expand Down
41 changes: 0 additions & 41 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1615,47 +1615,6 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
})
}

/// This function is the same as print_with_space, except that it renders no links.
/// It's used for macros' rendered source view, which is syntax highlighted and cannot have
/// any HTML in it.
pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
visibility: Option<ty::Visibility<DefId>>,
tcx: TyCtxt<'tcx>,
item_did: DefId,
is_doc_hidden: bool,
) -> impl Display + 'a + Captures<'tcx> {
let vis: Cow<'static, str> = match visibility {
None => "".into(),
Some(ty::Visibility::Public) => "pub ".into(),
Some(ty::Visibility::Restricted(vis_did)) => {
// FIXME(camelid): This may not work correctly if `item_did` is a module.
// However, rustdoc currently never displays a module's
// visibility, so it shouldn't matter.
let parent_module = find_nearest_parent_module(tcx, item_did);

if vis_did.is_crate_root() {
"pub(crate) ".into()
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
// is the same as no visibility modifier
"".into()
} else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
== Some(vis_did)
{
"pub(super) ".into()
} else {
format!("pub(in {}) ", tcx.def_path_str(vis_did)).into()
}
}
};
display_fn(move |f| {
if is_doc_hidden {
f.write_str("#[doc(hidden)] ")?;
}
f.write_str(&vis)
})
}

pub(crate) trait PrintWithSpace {
fn print_with_space(&self) -> &str;
}
Expand Down
7 changes: 0 additions & 7 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ pub(crate) fn render_example_with_highlighting(
write_footer(out, playground_button);
}

/// Highlights `src` as an item-decl, returning the HTML output.
pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
write!(out, "<pre class=\"rust item-decl\">");
write_code(out, src, None, None);
write!(out, "</pre>");
}

fn write_header(
out: &mut Buffer,
class: &str,
Expand Down
9 changes: 7 additions & 2 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use crate::html::format::{
Buffer, Ending, PrintWithSpace, display_fn, join_with_double_colon, print_abi_with_space,
print_constness_with_space, print_where_clause, visibility_print_with_space,
};
use crate::html::highlight;
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
use crate::html::render::{document_full, document_item_info};
use crate::html::url_parts_builder::UrlPartsBuilder;
Expand Down Expand Up @@ -1745,7 +1744,13 @@ fn item_variants(
}

fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
highlight::render_item_decl_with_highlighting(&t.source, w);
wrap_item(w, |w| {
// FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
if !t.macro_rules {
write!(w, "{}", visibility_print_with_space(it, cx));
}
write!(w, "{}", Escape(&t.source));
});
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
}

Expand Down
2 changes: 2 additions & 0 deletions tests/rustdoc/decl_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ mod a {
}
mod c {
//@ has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {'
// Regression test for <https://github.com/rust-lang/rust/issues/83000>:
//@ has - '//pre[@class="rust item-decl"]//a[@class="mod"]/@href' '../../index.html'
pub(in a) macro by_example_vis_named {
($foo:expr) => {}
}
Expand Down
28 changes: 8 additions & 20 deletions tests/rustdoc/macro_rules-matchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,17 @@

#![crate_name = "foo"]

//@ has 'foo/macro.todo.html'
//@ has - '//span[@class="macro"]' 'macro_rules!'
//@ hasraw - ' todo {'

//@ hasraw - '{ () =&gt; { ... }; ($('
//@ has - '//span[@class="macro-nonterminal"]' '$'
//@ has - '//span[@class="macro-nonterminal"]' 'arg'
//@ hasraw - ':tt)+'
//@ hasraw - ') =&gt; { ... }; }'
//@ has 'foo/macro.todo.html' '//pre' 'macro_rules! todo { \
// () => { ... }; \
// ($($arg:tt)+) => { ... }; \
// }'
pub use std::todo;

mod mod1 {
//@ has 'foo/macro.macro1.html'
//@ hasraw - 'macro_rules!'
//@ hasraw - 'macro1'
//@ hasraw - '{ () =&gt; { ... }; ($('
//@ has - '//span[@class="macro-nonterminal"]' '$'
//@ has - '//span[@class="macro-nonterminal"]' 'arg'
//@ hasraw - ':'
//@ hasraw - 'expr'
//@ hasraw - '),'
//@ hasraw - '+'
//@ hasraw - ') =&gt; { ... }; }'
//@ has 'foo/macro.macro1.html' '//pre' 'macro_rules! macro1 { \
// () => { ... }; \
// ($($arg:expr),+) => { ... }; \
// }'
#[macro_export]
macro_rules! macro1 {
() => {};
Expand Down

0 comments on commit 3376eda

Please sign in to comment.