Skip to content

Commit 122b141

Browse files
End of rework of Attributes struct
1 parent c4739bc commit 122b141

File tree

11 files changed

+145
-136
lines changed

11 files changed

+145
-136
lines changed

src/librustdoc/clean/types.rs

+97-19
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl Item {
122122

123123
/// Finds the `doc` attribute as a NameValue and returns the corresponding
124124
/// value found.
125-
crate fn doc_value(&self) -> Option<&str> {
125+
crate fn doc_value(&self) -> Option<String> {
126126
self.attrs.doc_value()
127127
}
128128

@@ -469,11 +469,13 @@ crate struct DocFragment {
469469
/// This allows distinguishing between the original documentation and a pub re-export.
470470
/// If it is `None`, the item was not re-exported.
471471
crate parent_module: Option<DefId>,
472-
crate doc: String,
472+
crate doc: Symbol,
473473
crate kind: DocFragmentKind,
474+
crate need_backline: bool,
475+
crate indent: usize,
474476
}
475477

476-
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
478+
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
477479
crate enum DocFragmentKind {
478480
/// A doc fragment created from a `///` or `//!` doc comment.
479481
SugaredDoc,
@@ -484,16 +486,42 @@ crate enum DocFragmentKind {
484486
Include { filename: Symbol },
485487
}
486488

489+
fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
490+
let s = frag.doc.as_str();
491+
let mut iter = s.lines().peekable();
492+
while let Some(line) = iter.next() {
493+
if line.chars().any(|c| !c.is_whitespace()) {
494+
assert!(line.len() >= frag.indent);
495+
out.push_str(&line[frag.indent..]);
496+
} else {
497+
out.push_str(line);
498+
}
499+
if iter.peek().is_some() {
500+
out.push('\n');
501+
}
502+
}
503+
if frag.need_backline {
504+
out.push('\n');
505+
}
506+
}
507+
487508
impl<'a> FromIterator<&'a DocFragment> for String {
488509
fn from_iter<T>(iter: T) -> Self
489510
where
490511
T: IntoIterator<Item = &'a DocFragment>,
491512
{
513+
let mut prev_kind: Option<DocFragmentKind> = None;
492514
iter.into_iter().fold(String::new(), |mut acc, frag| {
493-
if !acc.is_empty() {
515+
if !acc.is_empty()
516+
&& prev_kind
517+
.take()
518+
.map(|p| matches!(p, DocFragmentKind::Include { .. }) && p != frag.kind)
519+
.unwrap_or(false)
520+
{
494521
acc.push('\n');
495522
}
496-
acc.push_str(&frag.doc);
523+
add_doc_fragment(&mut acc, &frag);
524+
prev_kind = Some(frag.kind);
497525
acc
498526
})
499527
}
@@ -565,7 +593,7 @@ impl Attributes {
565593
/// Reads a `MetaItem` from within an attribute, looks for whether it is a
566594
/// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
567595
/// its expansion.
568-
crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, String)> {
596+
crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, Symbol)> {
569597
mi.meta_item_list().and_then(|list| {
570598
for meta in list {
571599
if meta.has_name(sym::include) {
@@ -574,7 +602,7 @@ impl Attributes {
574602
// look for that instead
575603
return meta.meta_item_list().and_then(|list| {
576604
let mut filename: Option<Symbol> = None;
577-
let mut contents: Option<String> = None;
605+
let mut contents: Option<Symbol> = None;
578606

579607
for it in list {
580608
if it.has_name(sym::file) {
@@ -583,7 +611,7 @@ impl Attributes {
583611
}
584612
} else if it.has_name(sym::contents) {
585613
if let Some(docs) = it.value_str() {
586-
contents = Some(docs.to_string());
614+
contents = Some(docs);
587615
}
588616
}
589617
}
@@ -622,30 +650,51 @@ impl Attributes {
622650
attrs: &[ast::Attribute],
623651
additional_attrs: Option<(&[ast::Attribute], DefId)>,
624652
) -> Attributes {
625-
let mut doc_strings = vec![];
653+
let mut doc_strings: Vec<DocFragment> = vec![];
626654
let mut sp = None;
627655
let mut cfg = Cfg::True;
628656
let mut doc_line = 0;
629657

658+
fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment) {
659+
if let Some(prev) = doc_strings.last_mut() {
660+
if matches!(prev.kind, DocFragmentKind::Include { .. })
661+
|| prev.kind != frag.kind
662+
|| prev.parent_module != frag.parent_module
663+
{
664+
// add a newline for extra padding between segments
665+
prev.need_backline = prev.kind == DocFragmentKind::SugaredDoc
666+
|| prev.kind == DocFragmentKind::RawDoc
667+
} else {
668+
prev.need_backline = true;
669+
}
670+
}
671+
}
672+
630673
let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
631674
if let Some(value) = attr.doc_str() {
632675
trace!("got doc_str={:?}", value);
633-
let value = beautify_doc_string(value).to_string();
676+
let value = beautify_doc_string(value);
634677
let kind = if attr.is_doc_comment() {
635678
DocFragmentKind::SugaredDoc
636679
} else {
637680
DocFragmentKind::RawDoc
638681
};
639682

640683
let line = doc_line;
641-
doc_line += value.lines().count();
642-
doc_strings.push(DocFragment {
684+
doc_line += value.as_str().lines().count();
685+
let frag = DocFragment {
643686
line,
644687
span: attr.span,
645688
doc: value,
646689
kind,
647690
parent_module,
648-
});
691+
need_backline: false,
692+
indent: 0,
693+
};
694+
695+
update_need_backline(&mut doc_strings, &frag);
696+
697+
doc_strings.push(frag);
649698

650699
if sp.is_none() {
651700
sp = Some(attr.span);
@@ -663,14 +712,18 @@ impl Attributes {
663712
} else if let Some((filename, contents)) = Attributes::extract_include(&mi)
664713
{
665714
let line = doc_line;
666-
doc_line += contents.lines().count();
667-
doc_strings.push(DocFragment {
715+
doc_line += contents.as_str().lines().count();
716+
let frag = DocFragment {
668717
line,
669718
span: attr.span,
670719
doc: contents,
671720
kind: DocFragmentKind::Include { filename },
672721
parent_module,
673-
});
722+
need_backline: false,
723+
indent: 0,
724+
};
725+
update_need_backline(&mut doc_strings, &frag);
726+
doc_strings.push(frag);
674727
}
675728
}
676729
}
@@ -721,14 +774,39 @@ impl Attributes {
721774

722775
/// Finds the `doc` attribute as a NameValue and returns the corresponding
723776
/// value found.
724-
crate fn doc_value(&self) -> Option<&str> {
725-
self.doc_strings.first().map(|s| s.doc.as_str())
777+
crate fn doc_value(&self) -> Option<String> {
778+
let mut iter = self.doc_strings.iter();
779+
780+
let ori = iter.next()?;
781+
let mut out = String::new();
782+
add_doc_fragment(&mut out, &ori);
783+
while let Some(new_frag) = iter.next() {
784+
if matches!(ori.kind, DocFragmentKind::Include { .. })
785+
|| new_frag.kind != ori.kind
786+
|| new_frag.parent_module != ori.parent_module
787+
{
788+
break;
789+
}
790+
add_doc_fragment(&mut out, &new_frag);
791+
}
792+
if out.is_empty() { None } else { Some(out) }
793+
}
794+
795+
crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
796+
let mut ret = FxHashMap::default();
797+
798+
for new_frag in self.doc_strings.iter() {
799+
let out = ret.entry(new_frag.parent_module).or_insert_with(|| String::new());
800+
add_doc_fragment(out, &new_frag);
801+
}
802+
ret
726803
}
727804

728805
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
729806
/// with newlines.
730807
crate fn collapsed_doc_value(&self) -> Option<String> {
731-
if !self.doc_strings.is_empty() { Some(self.doc_strings.iter().collect()) } else { None }
808+
let s: String = self.doc_strings.iter().collect();
809+
if s.is_empty() { None } else { Some(s) }
732810
}
733811

734812
/// Gets links as a vector

src/librustdoc/core.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ crate fn run_global_ctxt(
525525
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
526526

527527
if let Some(ref m) = krate.module {
528-
if let None | Some("") = m.doc_value() {
528+
if m.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
529529
let help = "The following guide may be of use:\n\
530530
https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
531531
tcx.struct_lint_node(

src/librustdoc/doctest.rs

-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,6 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
987987
self.collector.names.push(name);
988988
}
989989

990-
attrs.collapse_doc_comments();
991990
attrs.unindent_doc_comments();
992991
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
993992
// anything else, this will combine them for us.

src/librustdoc/formats/cache.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,10 @@ impl DocFolder for Cache {
314314
ty: item.type_(),
315315
name: s.to_string(),
316316
path: path.join("::"),
317-
desc: item
318-
.doc_value()
319-
.map_or_else(|| String::new(), short_markdown_summary),
317+
desc: item.doc_value().map_or_else(
318+
|| String::new(),
319+
|x| short_markdown_summary(&x.as_str()),
320+
),
320321
parent,
321322
parent_idx: None,
322323
search_type: get_index_search_type(&item),

src/librustdoc/html/render/cache.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
7878
ty: item.type_(),
7979
name: item.name.unwrap().to_string(),
8080
path: fqp[..fqp.len() - 1].join("::"),
81-
desc: item.doc_value().map_or_else(|| String::new(), short_markdown_summary),
81+
desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
8282
parent: Some(did),
8383
parent_idx: None,
8484
search_type: get_index_search_type(&item),
@@ -127,7 +127,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
127127
let crate_doc = krate
128128
.module
129129
.as_ref()
130-
.map(|module| module.doc_value().map_or_else(|| String::new(), short_markdown_summary))
130+
.map(|module| module.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)))
131131
.unwrap_or_default();
132132

133133
#[derive(Serialize)]

src/librustdoc/html/render/mod.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ crate mod cache;
3030
#[cfg(test)]
3131
mod tests;
3232

33-
use std::borrow::Cow;
3433
use std::cell::{Cell, RefCell};
3534
use std::cmp::Ordering;
3635
use std::collections::{BTreeMap, VecDeque};
@@ -198,11 +197,11 @@ impl SharedContext<'_> {
198197

199198
/// Based on whether the `collapse-docs` pass was run, return either the `doc_value` or the
200199
/// `collapsed_doc_value` of the given item.
201-
crate fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<Cow<'a, str>> {
200+
crate fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<String> {
202201
if self.collapsed {
203-
item.collapsed_doc_value().map(|s| s.into())
202+
item.collapsed_doc_value().map(|s| s.to_string())
204203
} else {
205-
item.doc_value().map(|s| s.into())
204+
item.doc_value().map(|s| s.to_string())
206205
}
207206
}
208207
}
@@ -1622,7 +1621,7 @@ impl Context<'_> {
16221621
let short = short.to_string();
16231622
map.entry(short).or_default().push((
16241623
myname,
1625-
Some(item.doc_value().map_or_else(|| String::new(), plain_text_summary)),
1624+
Some(item.doc_value().map_or_else(String::new, |s| plain_text_summary(&s))),
16261625
));
16271626
}
16281627

@@ -1880,7 +1879,7 @@ fn document_short(
18801879
return;
18811880
}
18821881
if let Some(s) = item.doc_value() {
1883-
let mut summary_html = MarkdownSummaryLine(s, &item.links()).into_string();
1882+
let mut summary_html = MarkdownSummaryLine(&s, &item.links()).into_string();
18841883

18851884
if s.contains('\n') {
18861885
let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link));
@@ -2197,7 +2196,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
21972196
let stab = myitem.stability_class(cx.tcx());
21982197
let add = if stab.is_some() { " " } else { "" };
21992198

2200-
let doc_value = myitem.doc_value().unwrap_or("");
2199+
let doc_value = myitem.doc_value().unwrap_or_else(String::new);
22012200
write!(
22022201
w,
22032202
"<tr class=\"{stab}{add}module-item\">\
@@ -2207,7 +2206,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
22072206
</tr>",
22082207
name = *myitem.name.as_ref().unwrap(),
22092208
stab_tags = extra_info_tags(myitem, item, cx.tcx()),
2210-
docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
2209+
docs = MarkdownSummaryLine(&doc_value, &myitem.links()).into_string(),
22112210
class = myitem.type_(),
22122211
add = add,
22132212
stab = stab.unwrap_or_else(String::new),

src/librustdoc/passes/calculate_doc_coverage.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
238238
&i.attrs
239239
.doc_strings
240240
.iter()
241-
.map(|d| d.doc.as_str())
241+
.map(|d| d.doc.to_string())
242242
.collect::<Vec<_>>()
243243
.join("\n"),
244244
&mut tests,

0 commit comments

Comments
 (0)