aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/attr.rs')
-rw-r--r--crates/hir_def/src/attr.rs83
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
409impl Attr { 416impl 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()