Skip to content

Commit b8ca0d4

Browse files
authored
Rollup merge of #148021 - GuillaumeGomez:simplify-mod-render, r=notriddle
[rustdoc] Simplify module rendering and HTML tags handling Extracted code from #145458. This PR simplifies the rendering of modules, in particular the HTML tags handling. Instead of having all items in a `vec`, we make a map with their types as key, allowing to then iterate over the types, which allows us to open and close the HTML tag at every turn without the need to check if a tag was opened or not, or to check it's still the same kind of type. For a better review experience: enable "Hide whitespace", the diff will be much smaller. r? `@notriddle`
2 parents 3f40ce5 + 90c047b commit b8ca0d4

File tree

1 file changed

+141
-143
lines changed

1 file changed

+141
-143
lines changed

src/librustdoc/html/render/print_item.rs

Lines changed: 141 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::iter;
55
use askama::Template;
66
use rustc_abi::VariantIdx;
77
use rustc_ast::join_path_syms;
8-
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
8+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
99
use rustc_hir as hir;
1010
use rustc_hir::def::CtorKind;
1111
use rustc_hir::def_id::DefId;
@@ -307,8 +307,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
307307
fmt::from_fn(|w| {
308308
write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?;
309309

310-
let mut not_stripped_items =
311-
items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
310+
let mut not_stripped_items: FxIndexMap<ItemType, Vec<(usize, &clean::Item)>> =
311+
FxIndexMap::default();
312+
313+
for (index, item) in items.iter().filter(|i| !i.is_stripped()).enumerate() {
314+
not_stripped_items.entry(item.type_()).or_default().push((index, item));
315+
}
312316

313317
// the order of item types in the listing
314318
fn reorder(ty: ItemType) -> u8 {
@@ -331,11 +335,6 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
331335
}
332336

333337
fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
334-
let rty1 = reorder(i1.type_());
335-
let rty2 = reorder(i2.type_());
336-
if rty1 != rty2 {
337-
return rty1.cmp(&rty2);
338-
}
339338
let is_stable1 =
340339
i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
341340
let is_stable2 =
@@ -357,7 +356,9 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
357356

358357
match cx.shared.module_sorting {
359358
ModuleSorting::Alphabetical => {
360-
not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
359+
for items in not_stripped_items.values_mut() {
360+
items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
361+
}
361362
}
362363
ModuleSorting::DeclarationOrder => {}
363364
}
@@ -380,155 +381,152 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
380381
// can be identical even if the elements are different (mostly in imports).
381382
// So in case this is an import, we keep everything by adding a "unique id"
382383
// (which is the position in the vector).
383-
not_stripped_items.dedup_by_key(|(idx, i)| {
384-
(
385-
i.item_id,
386-
if i.name.is_some() { Some(full_path(cx, i)) } else { None },
387-
i.type_(),
388-
if i.is_import() { *idx } else { 0 },
389-
)
390-
});
384+
for items in not_stripped_items.values_mut() {
385+
items.dedup_by_key(|(idx, i)| {
386+
(
387+
i.item_id,
388+
if i.name.is_some() { Some(full_path(cx, i)) } else { None },
389+
i.type_(),
390+
if i.is_import() { *idx } else { 0 },
391+
)
392+
});
393+
}
391394

392395
debug!("{not_stripped_items:?}");
393-
let mut last_section = None;
394396

395-
for (_, myitem) in &not_stripped_items {
396-
let my_section = item_ty_to_section(myitem.type_());
397-
if Some(my_section) != last_section {
398-
if last_section.is_some() {
399-
w.write_str(ITEM_TABLE_CLOSE)?;
400-
}
401-
last_section = Some(my_section);
402-
let section_id = my_section.id();
403-
let tag =
404-
if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN };
405-
write!(
406-
w,
407-
"{}",
408-
write_section_heading(my_section.name(), &cx.derive_id(section_id), None, tag)
409-
)?;
410-
}
411-
412-
match myitem.kind {
413-
clean::ExternCrateItem { ref src } => {
414-
use crate::html::format::print_anchor;
397+
let mut types = not_stripped_items.keys().copied().collect::<Vec<_>>();
398+
types.sort_unstable_by(|a, b| reorder(*a).cmp(&reorder(*b)));
415399

416-
match *src {
417-
Some(src) => {
418-
write!(
419-
w,
420-
"<dt><code>{}extern crate {} as {};",
421-
visibility_print_with_space(myitem, cx),
422-
print_anchor(myitem.item_id.expect_def_id(), src, cx),
423-
EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
424-
)?;
425-
}
426-
None => {
427-
write!(
428-
w,
429-
"<dt><code>{}extern crate {};",
430-
visibility_print_with_space(myitem, cx),
431-
print_anchor(
432-
myitem.item_id.expect_def_id(),
433-
myitem.name.unwrap(),
434-
cx
435-
)
436-
)?;
437-
}
438-
}
439-
w.write_str("</code></dt>")?;
440-
}
400+
for type_ in types {
401+
let my_section = item_ty_to_section(type_);
402+
let tag = if my_section == super::ItemSection::Reexports {
403+
REEXPORTS_TABLE_OPEN
404+
} else {
405+
ITEM_TABLE_OPEN
406+
};
407+
write!(
408+
w,
409+
"{}",
410+
write_section_heading(my_section.name(), &cx.derive_id(my_section.id()), None, tag)
411+
)?;
441412

442-
clean::ImportItem(ref import) => {
443-
let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| {
444-
print_extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
445-
});
413+
for (_, myitem) in &not_stripped_items[&type_] {
414+
match myitem.kind {
415+
clean::ExternCrateItem { ref src } => {
416+
use crate::html::format::print_anchor;
446417

447-
let id = match import.kind {
448-
clean::ImportKind::Simple(s) => {
449-
format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
418+
match *src {
419+
Some(src) => {
420+
write!(
421+
w,
422+
"<dt><code>{}extern crate {} as {};",
423+
visibility_print_with_space(myitem, cx),
424+
print_anchor(myitem.item_id.expect_def_id(), src, cx),
425+
EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
426+
)?;
427+
}
428+
None => {
429+
write!(
430+
w,
431+
"<dt><code>{}extern crate {};",
432+
visibility_print_with_space(myitem, cx),
433+
print_anchor(
434+
myitem.item_id.expect_def_id(),
435+
myitem.name.unwrap(),
436+
cx
437+
)
438+
)?;
439+
}
450440
}
451-
clean::ImportKind::Glob => String::new(),
452-
};
453-
write!(
454-
w,
455-
"<dt{id}>\
456-
<code>"
457-
)?;
458-
render_attributes_in_code(w, myitem, "", cx);
459-
write!(
460-
w,
461-
"{vis}{imp}</code>{stab_tags}\
462-
</dt>",
463-
vis = visibility_print_with_space(myitem, cx),
464-
imp = import.print(cx)
465-
)?;
466-
}
467-
468-
_ => {
469-
if myitem.name.is_none() {
470-
continue;
471441
}
472-
473-
let unsafety_flag = match myitem.kind {
474-
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
475-
if myitem.fn_header(tcx).unwrap().safety
476-
== hir::HeaderSafety::Normal(hir::Safety::Unsafe) =>
477-
{
478-
"<sup title=\"unsafe function\">⚠</sup>"
479-
}
480-
clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
481-
"<sup title=\"unsafe static\">⚠</sup>"
482-
}
483-
_ => "",
484-
};
485-
486-
let visibility_and_hidden = match myitem.visibility(tcx) {
487-
Some(ty::Visibility::Restricted(_)) => {
488-
if myitem.is_doc_hidden() {
489-
// Don't separate with a space when there are two of them
490-
"<span title=\"Restricted Visibility\">&nbsp;🔒</span><span title=\"Hidden item\">👻</span> "
491-
} else {
492-
"<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
442+
clean::ImportItem(ref import) => {
443+
let stab_tags =
444+
import.source.did.map_or_else(String::new, |import_def_id| {
445+
print_extra_info_tags(tcx, myitem, item, Some(import_def_id))
446+
.to_string()
447+
});
448+
let id = match import.kind {
449+
clean::ImportKind::Simple(s) => {
450+
format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
493451
}
452+
clean::ImportKind::Glob => String::new(),
453+
};
454+
write!(
455+
w,
456+
"<dt{id}>\
457+
<code>"
458+
)?;
459+
render_attributes_in_code(w, myitem, "", cx);
460+
write!(
461+
w,
462+
"{vis}{imp}</code>{stab_tags}\
463+
</dt>",
464+
vis = visibility_print_with_space(myitem, cx),
465+
imp = import.print(cx)
466+
)?;
467+
}
468+
_ => {
469+
if myitem.name.is_none() {
470+
continue;
494471
}
495-
_ if myitem.is_doc_hidden() => {
496-
"<span title=\"Hidden item\">&nbsp;👻</span> "
497-
}
498-
_ => "",
499-
};
500472

501-
let docs =
502-
MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
503-
let (docs_before, docs_after) =
504-
if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
505-
write!(
506-
w,
507-
"<dt>\
508-
<a class=\"{class}\" href=\"{href}\" title=\"{title1} {title2}\">\
509-
{name}\
510-
</a>\
511-
{visibility_and_hidden}\
512-
{unsafety_flag}\
513-
{stab_tags}\
514-
</dt>\
515-
{docs_before}{docs}{docs_after}",
516-
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
517-
visibility_and_hidden = visibility_and_hidden,
518-
stab_tags = print_extra_info_tags(tcx, myitem, item, None),
519-
class = myitem.type_(),
520-
unsafety_flag = unsafety_flag,
521-
href = print_item_path(myitem.type_(), myitem.name.unwrap().as_str()),
522-
title1 = myitem.type_(),
523-
title2 = full_path(cx, myitem),
524-
)?;
473+
let unsafety_flag = match myitem.kind {
474+
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
475+
if myitem.fn_header(tcx).unwrap().safety
476+
== hir::HeaderSafety::Normal(hir::Safety::Unsafe) =>
477+
{
478+
"<sup title=\"unsafe function\">⚠</sup>"
479+
}
480+
clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
481+
"<sup title=\"unsafe static\">⚠</sup>"
482+
}
483+
_ => "",
484+
};
485+
let visibility_and_hidden = match myitem.visibility(tcx) {
486+
Some(ty::Visibility::Restricted(_)) => {
487+
if myitem.is_doc_hidden() {
488+
// Don't separate with a space when there are two of them
489+
"<span title=\"Restricted Visibility\">&nbsp;🔒</span><span title=\"Hidden item\">👻</span> "
490+
} else {
491+
"<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
492+
}
493+
}
494+
_ if myitem.is_doc_hidden() => {
495+
"<span title=\"Hidden item\">&nbsp;👻</span> "
496+
}
497+
_ => "",
498+
};
499+
500+
let docs = MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx))
501+
.into_string();
502+
let (docs_before, docs_after) =
503+
if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
504+
write!(
505+
w,
506+
"<dt>\
507+
<a class=\"{class}\" href=\"{href}\" title=\"{title1} {title2}\">\
508+
{name}\
509+
</a>\
510+
{visibility_and_hidden}\
511+
{unsafety_flag}\
512+
{stab_tags}\
513+
</dt>\
514+
{docs_before}{docs}{docs_after}",
515+
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
516+
visibility_and_hidden = visibility_and_hidden,
517+
stab_tags = print_extra_info_tags(tcx, myitem, item, None),
518+
class = type_,
519+
unsafety_flag = unsafety_flag,
520+
href = print_item_path(type_, myitem.name.unwrap().as_str()),
521+
title1 = myitem.type_(),
522+
title2 = full_path(cx, myitem),
523+
)?;
524+
}
525525
}
526526
}
527-
}
528-
529-
if last_section.is_some() {
530527
w.write_str(ITEM_TABLE_CLOSE)?;
531528
}
529+
532530
Ok(())
533531
})
534532
}

0 commit comments

Comments
 (0)