From ec824a92d05caa1908cb25cbd5b969c8e995aaa7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 17 Mar 2021 14:38:11 +0100 Subject: Better handling of block doc comments --- crates/hir_def/src/attr.rs | 83 +++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 38 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 7ba53ee5c..aeeb2c5cf 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -77,33 +77,19 @@ impl RawAttrs { pub(crate) const EMPTY: Self = Self { entries: None }; pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self { - let attrs: Vec<_> = collect_attrs(owner).collect(); - let entries = if attrs.is_empty() { - // Avoid heap allocation - None - } else { - Some( - attrs - .into_iter() - .enumerate() - .flat_map(|(i, attr)| match attr { - Either::Left(attr) => Attr::from_src(attr, hygiene).map(|attr| (i, attr)), - Either::Right(comment) => comment.doc_comment().map(|doc| { - ( - i, - Attr { - index: 0, - input: Some(AttrInput::Literal(SmolStr::new(doc))), - path: ModPath::from(hir_expand::name!(doc)), - }, - ) - }), - }) - .map(|(i, attr)| Attr { index: i as u32, ..attr }) - .collect(), - ) - }; - Self { entries } + let entries = collect_attrs(owner) + .enumerate() + .flat_map(|(i, attr)| match attr { + Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32), + Either::Right(comment) => comment.doc_comment().map(|doc| Attr { + index: i as u32, + input: Some(AttrInput::Literal(SmolStr::new(doc))), + path: ModPath::from(hir_expand::name!(doc)), + }), + }) + .collect::>(); + + Self { entries: if entries.is_empty() { None } else { Some(entries) } } } fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Self { @@ -162,7 +148,7 @@ impl RawAttrs { let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; // FIXME hygiene let hygiene = Hygiene::new_unhygienic(); - Attr::from_src(attr, &hygiene).map(|attr| Attr { index, ..attr }) + Attr::from_src(attr, &hygiene, index) }); let cfg_options = &crate_graph[krate].cfg_options; @@ -325,15 +311,36 @@ impl Attrs { AttrInput::Literal(s) => Some(s), AttrInput::TokenTree(_) => None, }); - // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the - // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524). - let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n")) - .map(|it| it.as_str()) - .collect::(); - if docs.is_empty() { + let indent = docs + .clone() + .flat_map(|s| s.lines()) + .filter(|line| !line.chars().all(|c| c.is_whitespace())) + .map(|line| line.chars().take_while(|c| c.is_whitespace()).count()) + .min() + .unwrap_or(0); + let mut buf = String::new(); + for doc in docs { + // str::lines doesn't yield anything for the empty string + if doc.is_empty() { + buf.push('\n'); + } else { + buf.extend(Itertools::intersperse( + doc.lines().map(|line| { + line.char_indices() + .nth(indent) + .map_or(line, |(offset, _)| &line[offset..]) + .trim_end() + }), + "\n", + )); + } + buf.push('\n'); + } + buf.pop(); + if buf.is_empty() { None } else { - Some(Documentation(docs)) + Some(Documentation(buf)) } } } @@ -407,7 +414,7 @@ pub enum AttrInput { } impl Attr { - fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option { + fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option { let path = ModPath::from_src(ast.path()?, hygiene)?; let input = if let Some(lit) = ast.literal() { let value = match lit.kind() { @@ -420,7 +427,7 @@ impl Attr { } else { None }; - Some(Attr { index: 0, path, input }) + Some(Attr { index, path, input }) } /// Maps this lowered `Attr` back to its original syntax node. @@ -508,7 +515,7 @@ impl<'a> AttrQuery<'a> { self.attrs().next().is_some() } - pub fn attrs(self) -> impl Iterator { + pub fn attrs(self) -> impl Iterator + Clone { let key = self.key; self.attrs .iter() -- cgit v1.2.3