aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-17 16:00:43 +0000
committerGitHub <[email protected]>2021-03-17 16:00:43 +0000
commitedf11480ceae1ef77d7084604011c0ef6f692c72 (patch)
tree6d1da24b8e275d8e36a12a48e1cdc9de0f8e1ec4 /crates/hir_def/src
parentbaa19991688c6bdd99b63b8dc6f539be44da0350 (diff)
parent5734b347ddfff0d285d3eecf5735cac30271696c (diff)
Merge #8065
8065: Better handling of block doc comments r=Veykril a=Veykril Moves doc string processing to `Attrs::docs`, as we need the indent info from all comments before being able to know how much to strip Closes #7774 Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/attr.rs105
1 files changed, 56 insertions, 49 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 7ba53ee5c..b7353d868 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -76,37 +76,23 @@ impl ops::Deref for Attrs {
76impl RawAttrs { 76impl 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 ast::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 ast::AttrsOwner>) -> Self {
110 let hygiene = Hygiene::new(db.upcast(), owner.file_id); 96 let hygiene = Hygiene::new(db.upcast(), owner.file_id);
111 Self::new(owner.value, &hygiene) 97 Self::new(owner.value, &hygiene)
112 } 98 }
@@ -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;
@@ -192,7 +178,7 @@ impl Attrs {
192 Some(it) => { 178 Some(it) => {
193 let raw_attrs = RawAttrs::from_attrs_owner( 179 let raw_attrs = RawAttrs::from_attrs_owner(
194 db, 180 db,
195 it.as_ref().map(|it| it as &dyn AttrsOwner), 181 it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
196 ); 182 );
197 match mod_data.definition_source(db) { 183 match mod_data.definition_source(db) {
198 InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs 184 InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
@@ -203,9 +189,9 @@ impl Attrs {
203 None => RawAttrs::from_attrs_owner( 189 None => RawAttrs::from_attrs_owner(
204 db, 190 db,
205 mod_data.definition_source(db).as_ref().map(|src| match src { 191 mod_data.definition_source(db).as_ref().map(|src| match src {
206 ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, 192 ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
207 ModuleSource::Module(module) => module as &dyn AttrsOwner, 193 ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
208 ModuleSource::BlockExpr(block) => block as &dyn AttrsOwner, 194 ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
209 }), 195 }),
210 ), 196 ),
211 } 197 }
@@ -263,7 +249,7 @@ impl Attrs {
263 let mut res = ArenaMap::default(); 249 let mut res = ArenaMap::default();
264 250
265 for (id, var) in src.value.iter() { 251 for (id, var) in src.value.iter() {
266 let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn AttrsOwner)) 252 let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn ast::AttrsOwner))
267 .filter(db, krate); 253 .filter(db, krate);
268 254
269 res.insert(id, attrs) 255 res.insert(id, attrs)
@@ -297,7 +283,7 @@ impl Attrs {
297 /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes. 283 /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
298 /// 284 ///
299 /// `owner` must be the original owner of the attributes. 285 /// `owner` must be the original owner of the attributes.
300 pub fn source_map(&self, owner: &dyn AttrsOwner) -> AttrSourceMap { 286 pub fn source_map(&self, owner: &dyn ast::AttrsOwner) -> AttrSourceMap {
301 AttrSourceMap { attrs: collect_attrs(owner).collect() } 287 AttrSourceMap { attrs: collect_attrs(owner).collect() }
302 } 288 }
303 289
@@ -325,15 +311,34 @@ 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.extend(Itertools::intersperse(
326 doc.lines().map(|line| {
327 line.char_indices()
328 .nth(indent)
329 .map_or(line, |(offset, _)| &line[offset..])
330 .trim_end()
331 }),
332 "\n",
333 ));
334 }
335 buf.push('\n');
336 }
337 buf.pop();
338 if buf.is_empty() {
334 None 339 None
335 } else { 340 } else {
336 Some(Documentation(docs)) 341 Some(Documentation(buf))
337 } 342 }
338 } 343 }
339} 344}
@@ -407,7 +412,7 @@ pub enum AttrInput {
407} 412}
408 413
409impl Attr { 414impl Attr {
410 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 415 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
411 let path = ModPath::from_src(ast.path()?, hygiene)?; 416 let path = ModPath::from_src(ast.path()?, hygiene)?;
412 let input = if let Some(lit) = ast.literal() { 417 let input = if let Some(lit) = ast.literal() {
413 let value = match lit.kind() { 418 let value = match lit.kind() {
@@ -420,7 +425,7 @@ impl Attr {
420 } else { 425 } else {
421 None 426 None
422 }; 427 };
423 Some(Attr { index: 0, path, input }) 428 Some(Attr { index, path, input })
424 } 429 }
425 430
426 /// Maps this lowered `Attr` back to its original syntax node. 431 /// Maps this lowered `Attr` back to its original syntax node.
@@ -429,7 +434,7 @@ impl Attr {
429 /// 434 ///
430 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of 435 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
431 /// the attribute represented by `Attr`. 436 /// the attribute represented by `Attr`.
432 pub fn to_src(&self, owner: &dyn AttrsOwner) -> Either<ast::Attr, ast::Comment> { 437 pub fn to_src(&self, owner: &dyn ast::AttrsOwner) -> Either<ast::Attr, ast::Comment> {
433 collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| { 438 collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| {
434 panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax()) 439 panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax())
435 }) 440 })
@@ -508,7 +513,7 @@ impl<'a> AttrQuery<'a> {
508 self.attrs().next().is_some() 513 self.attrs().next().is_some()
509 } 514 }
510 515
511 pub fn attrs(self) -> impl Iterator<Item = &'a Attr> { 516 pub fn attrs(self) -> impl Iterator<Item = &'a Attr> + Clone {
512 let key = self.key; 517 let key = self.key;
513 self.attrs 518 self.attrs
514 .iter() 519 .iter()
@@ -521,7 +526,7 @@ where
521 N: ast::AttrsOwner, 526 N: ast::AttrsOwner,
522{ 527{
523 let src = InFile::new(src.file_id, src.to_node(db.upcast())); 528 let src = InFile::new(src.file_id, src.to_node(db.upcast()));
524 RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 529 RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn ast::AttrsOwner))
525} 530}
526 531
527fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs { 532fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {
@@ -530,7 +535,9 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
530 tree.raw_attrs(mod_item.into()).clone() 535 tree.raw_attrs(mod_item.into()).clone()
531} 536}
532 537
533fn collect_attrs(owner: &dyn AttrsOwner) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { 538fn collect_attrs(
539 owner: &dyn ast::AttrsOwner,
540) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> {
534 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) 541 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
535 .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); 542 .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs))));
536 543