Change DocFragments from enum variant fields to structs with a nested enum

This makes the code a lot easier to work with. It also makes it easier
to add new fields without updating each variant and `match`
individually.

- Name the `Kind` variant after `DocFragmentKind` from `collapse_docs`
- Remove unneeded impls
This commit is contained in:
Joshua Nelson
2020-10-03 19:15:27 -04:00
parent 782013564e
commit 5f76b95e9b
5 changed files with 50 additions and 90 deletions

View File

@@ -370,32 +370,22 @@ impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
/// kept separate because of issue #42760. /// kept separate because of issue #42760.
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum DocFragment { pub struct DocFragment {
/// A doc fragment created from a `///` or `//!` doc comment. pub line: usize,
SugaredDoc(usize, rustc_span::Span, String), pub span: rustc_span::Span,
/// A doc fragment created from a "raw" `#[doc=""]` attribute. pub doc: String,
RawDoc(usize, rustc_span::Span, String), pub kind: DocFragmentKind,
/// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
/// given filename and the file contents.
Include(usize, rustc_span::Span, String, String),
} }
impl DocFragment { #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub fn as_str(&self) -> &str { pub enum DocFragmentKind {
match *self { /// A doc fragment created from a `///` or `//!` doc comment.
DocFragment::SugaredDoc(_, _, ref s) => &s[..], SugaredDoc,
DocFragment::RawDoc(_, _, ref s) => &s[..], /// A doc fragment created from a "raw" `#[doc=""]` attribute.
DocFragment::Include(_, _, _, ref s) => &s[..], RawDoc,
} /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
} /// given filename and the file contents.
Include { filename: String },
pub fn span(&self) -> rustc_span::Span {
match *self {
DocFragment::SugaredDoc(_, span, _)
| DocFragment::RawDoc(_, span, _)
| DocFragment::Include(_, span, _, _) => span,
}
}
} }
impl<'a> FromIterator<&'a DocFragment> for String { impl<'a> FromIterator<&'a DocFragment> for String {
@@ -407,12 +397,7 @@ impl<'a> FromIterator<&'a DocFragment> for String {
if !acc.is_empty() { if !acc.is_empty() {
acc.push('\n'); acc.push('\n');
} }
match *frag { acc.push_str(&frag.doc);
DocFragment::SugaredDoc(_, _, ref docs)
| DocFragment::RawDoc(_, _, ref docs)
| DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs),
}
acc acc
}) })
} }
@@ -547,15 +532,15 @@ impl Attributes {
.filter_map(|attr| { .filter_map(|attr| {
if let Some(value) = attr.doc_str() { if let Some(value) = attr.doc_str() {
let value = beautify_doc_string(value); let value = beautify_doc_string(value);
let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() { let kind = if attr.is_doc_comment() {
DocFragment::SugaredDoc DocFragmentKind::SugaredDoc
} else { } else {
DocFragment::RawDoc DocFragmentKind::RawDoc
}; };
let line = doc_line; let line = doc_line;
doc_line += value.lines().count(); doc_line += value.lines().count();
doc_strings.push(mk_fragment(line, attr.span, value)); doc_strings.push(DocFragment { line, span: attr.span, doc: value, kind });
if sp.is_none() { if sp.is_none() {
sp = Some(attr.span); sp = Some(attr.span);
@@ -575,9 +560,12 @@ impl Attributes {
{ {
let line = doc_line; let line = doc_line;
doc_line += contents.lines().count(); doc_line += contents.lines().count();
doc_strings.push(DocFragment::Include( doc_strings.push(DocFragment {
line, attr.span, filename, contents, line,
)); span: attr.span,
doc: contents,
kind: DocFragmentKind::Include { filename },
});
} }
} }
} }
@@ -621,7 +609,7 @@ impl Attributes {
/// Finds the `doc` attribute as a NameValue and returns the corresponding /// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found. /// value found.
pub fn doc_value(&self) -> Option<&str> { pub fn doc_value(&self) -> Option<&str> {
self.doc_strings.first().map(|s| s.as_str()) self.doc_strings.first().map(|s| s.doc.as_str())
} }
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined

View File

@@ -232,7 +232,12 @@ impl fold::DocFolder for CoverageCalculator {
let mut tests = Tests { found_tests: 0 }; let mut tests = Tests { found_tests: 0 };
find_testable_code( find_testable_code(
&i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::<Vec<_>>().join("\n"), &i.attrs
.doc_strings
.iter()
.map(|d| d.doc.as_str())
.collect::<Vec<_>>()
.join("\n"),
&mut tests, &mut tests,
ErrorCodes::No, ErrorCodes::No,
false, false,

View File

@@ -1,4 +1,4 @@
use crate::clean::{self, DocFragment, Item}; use crate::clean::{self, DocFragment, DocFragmentKind, Item};
use crate::core::DocContext; use crate::core::DocContext;
use crate::fold; use crate::fold;
use crate::fold::DocFolder; use crate::fold::DocFolder;
@@ -12,23 +12,6 @@ pub const COLLAPSE_DOCS: Pass = Pass {
description: "concatenates all document attributes into one document attribute", description: "concatenates all document attributes into one document attribute",
}; };
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum DocFragmentKind {
Sugared,
Raw,
Include,
}
impl DocFragment {
fn kind(&self) -> DocFragmentKind {
match *self {
DocFragment::SugaredDoc(..) => DocFragmentKind::Sugared,
DocFragment::RawDoc(..) => DocFragmentKind::Raw,
DocFragment::Include(..) => DocFragmentKind::Include,
}
}
}
pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
let mut krate = Collapser.fold_crate(krate); let mut krate = Collapser.fold_crate(krate);
krate.collapsed = true; krate.collapsed = true;
@@ -50,30 +33,22 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) {
for frag in take(doc_strings) { for frag in take(doc_strings) {
if let Some(mut curr_frag) = last_frag.take() { if let Some(mut curr_frag) = last_frag.take() {
let curr_kind = curr_frag.kind(); let curr_kind = &curr_frag.kind;
let new_kind = frag.kind(); let new_kind = &frag.kind;
if curr_kind == DocFragmentKind::Include || curr_kind != new_kind { if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind {
match curr_frag { if *curr_kind == DocFragmentKind::SugaredDoc
DocFragment::SugaredDoc(_, _, ref mut doc_string) || *curr_kind == DocFragmentKind::RawDoc
| DocFragment::RawDoc(_, _, ref mut doc_string) => { {
// add a newline for extra padding between segments // add a newline for extra padding between segments
doc_string.push('\n'); curr_frag.doc.push('\n');
}
_ => {}
} }
docs.push(curr_frag); docs.push(curr_frag);
last_frag = Some(frag); last_frag = Some(frag);
} else { } else {
match curr_frag { curr_frag.doc.push('\n');
DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string) curr_frag.doc.push_str(&frag.doc);
| DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => { curr_frag.span = curr_frag.span.to(frag.span);
doc_string.push('\n');
doc_string.push_str(frag.as_str());
*span = span.to(frag.span());
}
_ => unreachable!(),
}
last_frag = Some(curr_frag); last_frag = Some(curr_frag);
} }
} else { } else {

View File

@@ -8,7 +8,7 @@ use std::mem;
use std::ops::Range; use std::ops::Range;
use self::Condition::*; use self::Condition::*;
use crate::clean::{self, GetDefId, Item}; use crate::clean::{self, DocFragmentKind, GetDefId, Item};
use crate::core::DocContext; use crate::core::DocContext;
use crate::fold::{DocFolder, StripItem}; use crate::fold::{DocFolder, StripItem};
@@ -314,11 +314,11 @@ crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
if attrs.doc_strings.is_empty() { if attrs.doc_strings.is_empty() {
return None; return None;
} }
let start = attrs.doc_strings[0].span(); let start = attrs.doc_strings[0].span;
if start == DUMMY_SP { if start == DUMMY_SP {
return None; return None;
} }
let end = attrs.doc_strings.last().expect("no doc strings provided").span(); let end = attrs.doc_strings.last().expect("no doc strings provided").span;
Some(start.to(end)) Some(start.to(end))
} }
@@ -333,10 +333,8 @@ crate fn source_span_for_markdown_range(
md_range: &Range<usize>, md_range: &Range<usize>,
attrs: &clean::Attributes, attrs: &clean::Attributes,
) -> Option<Span> { ) -> Option<Span> {
let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag { let is_all_sugared_doc =
clean::DocFragment::SugaredDoc(..) => true, attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
_ => false,
});
if !is_all_sugared_doc { if !is_all_sugared_doc {
return None; return None;

View File

@@ -36,13 +36,7 @@ impl clean::Attributes {
fn unindent_fragments(docs: &mut Vec<DocFragment>) { fn unindent_fragments(docs: &mut Vec<DocFragment>) {
for fragment in docs { for fragment in docs {
match *fragment { fragment.doc = unindent(&fragment.doc);
DocFragment::SugaredDoc(_, _, ref mut doc_string)
| DocFragment::RawDoc(_, _, ref mut doc_string)
| DocFragment::Include(_, _, _, ref mut doc_string) => {
*doc_string = unindent(doc_string)
}
}
} }
} }