diff options
Diffstat (limited to 'crates/hir_def/src/attr.rs')
-rw-r--r-- | crates/hir_def/src/attr.rs | 83 |
1 files changed, 45 insertions, 38 deletions
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 { | |||
77 | pub(crate) const EMPTY: Self = Self { entries: None }; | 77 | pub(crate) const EMPTY: Self = Self { entries: None }; |
78 | 78 | ||
79 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self { | 79 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self { |
80 | let attrs: Vec<_> = collect_attrs(owner).collect(); | 80 | let entries = collect_attrs(owner) |
81 | let entries = if attrs.is_empty() { | 81 | .enumerate() |
82 | // Avoid heap allocation | 82 | .flat_map(|(i, attr)| match attr { |
83 | None | 83 | Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32), |
84 | } else { | 84 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
85 | Some( | 85 | index: i as u32, |
86 | attrs | 86 | input: Some(AttrInput::Literal(SmolStr::new(doc))), |
87 | .into_iter() | 87 | path: ModPath::from(hir_expand::name!(doc)), |
88 | .enumerate() | 88 | }), |
89 | .flat_map(|(i, attr)| match attr { | 89 | }) |
90 | Either::Left(attr) => Attr::from_src(attr, hygiene).map(|attr| (i, attr)), | 90 | .collect::<Arc<_>>(); |
91 | Either::Right(comment) => comment.doc_comment().map(|doc| { | 91 | |
92 | ( | 92 | Self { entries: if entries.is_empty() { None } else { Some(entries) } } |
93 | i, | ||
94 | Attr { | ||
95 | index: 0, | ||
96 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | ||
97 | path: ModPath::from(hir_expand::name!(doc)), | ||
98 | }, | ||
99 | ) | ||
100 | }), | ||
101 | }) | ||
102 | .map(|(i, attr)| Attr { index: i as u32, ..attr }) | ||
103 | .collect(), | ||
104 | ) | ||
105 | }; | ||
106 | Self { entries } | ||
107 | } | 93 | } |
108 | 94 | ||
109 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Self { | 95 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Self { |
@@ -162,7 +148,7 @@ impl RawAttrs { | |||
162 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | 148 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; |
163 | // FIXME hygiene | 149 | // FIXME hygiene |
164 | let hygiene = Hygiene::new_unhygienic(); | 150 | let hygiene = Hygiene::new_unhygienic(); |
165 | Attr::from_src(attr, &hygiene).map(|attr| Attr { index, ..attr }) | 151 | Attr::from_src(attr, &hygiene, index) |
166 | }); | 152 | }); |
167 | 153 | ||
168 | let cfg_options = &crate_graph[krate].cfg_options; | 154 | let cfg_options = &crate_graph[krate].cfg_options; |
@@ -325,15 +311,36 @@ impl Attrs { | |||
325 | AttrInput::Literal(s) => Some(s), | 311 | AttrInput::Literal(s) => Some(s), |
326 | AttrInput::TokenTree(_) => None, | 312 | AttrInput::TokenTree(_) => None, |
327 | }); | 313 | }); |
328 | // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the | 314 | let indent = docs |
329 | // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524). | 315 | .clone() |
330 | let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n")) | 316 | .flat_map(|s| s.lines()) |
331 | .map(|it| it.as_str()) | 317 | .filter(|line| !line.chars().all(|c| c.is_whitespace())) |
332 | .collect::<String>(); | 318 | .map(|line| line.chars().take_while(|c| c.is_whitespace()).count()) |
333 | if docs.is_empty() { | 319 | .min() |
320 | .unwrap_or(0); | ||
321 | let mut buf = String::new(); | ||
322 | for doc in docs { | ||
323 | // str::lines doesn't yield anything for the empty string | ||
324 | if doc.is_empty() { | ||
325 | buf.push('\n'); | ||
326 | } else { | ||
327 | buf.extend(Itertools::intersperse( | ||
328 | doc.lines().map(|line| { | ||
329 | line.char_indices() | ||
330 | .nth(indent) | ||
331 | .map_or(line, |(offset, _)| &line[offset..]) | ||
332 | .trim_end() | ||
333 | }), | ||
334 | "\n", | ||
335 | )); | ||
336 | } | ||
337 | buf.push('\n'); | ||
338 | } | ||
339 | buf.pop(); | ||
340 | if buf.is_empty() { | ||
334 | None | 341 | None |
335 | } else { | 342 | } else { |
336 | Some(Documentation(docs)) | 343 | Some(Documentation(buf)) |
337 | } | 344 | } |
338 | } | 345 | } |
339 | } | 346 | } |
@@ -407,7 +414,7 @@ pub enum AttrInput { | |||
407 | } | 414 | } |
408 | 415 | ||
409 | impl Attr { | 416 | impl Attr { |
410 | fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { | 417 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { |
411 | let path = ModPath::from_src(ast.path()?, hygiene)?; | 418 | let path = ModPath::from_src(ast.path()?, hygiene)?; |
412 | let input = if let Some(lit) = ast.literal() { | 419 | let input = if let Some(lit) = ast.literal() { |
413 | let value = match lit.kind() { | 420 | let value = match lit.kind() { |
@@ -420,7 +427,7 @@ impl Attr { | |||
420 | } else { | 427 | } else { |
421 | None | 428 | None |
422 | }; | 429 | }; |
423 | Some(Attr { index: 0, path, input }) | 430 | Some(Attr { index, path, input }) |
424 | } | 431 | } |
425 | 432 | ||
426 | /// Maps this lowered `Attr` back to its original syntax node. | 433 | /// Maps this lowered `Attr` back to its original syntax node. |
@@ -508,7 +515,7 @@ impl<'a> AttrQuery<'a> { | |||
508 | self.attrs().next().is_some() | 515 | self.attrs().next().is_some() |
509 | } | 516 | } |
510 | 517 | ||
511 | pub fn attrs(self) -> impl Iterator<Item = &'a Attr> { | 518 | pub fn attrs(self) -> impl Iterator<Item = &'a Attr> + Clone { |
512 | let key = self.key; | 519 | let key = self.key; |
513 | self.attrs | 520 | self.attrs |
514 | .iter() | 521 | .iter() |