Skip to content

Commit cc04cfc

Browse files
committed
Reduce allocations in attribute collection
1 parent c08df0f commit cc04cfc

File tree

9 files changed

+61
-70
lines changed

9 files changed

+61
-70
lines changed

crates/hir/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
664664
let attr = node
665665
.doc_comments_and_attrs()
666666
.nth((*invoc_attr_index) as usize)
667-
.and_then(Either::right)
667+
.and_then(Either::left)
668668
.unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
669669
(
670670
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),

crates/hir_def/src/attr.rs

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -525,38 +525,36 @@ impl AttrsWithOwner {
525525

526526
fn inner_attributes(
527527
syntax: &SyntaxNode,
528-
) -> Option<(impl Iterator<Item = ast::Attr>, impl Iterator<Item = ast::Comment>)> {
529-
let (attrs, docs) = match_ast! {
528+
) -> Option<impl Iterator<Item = Either<ast::Attr, ast::Comment>>> {
529+
let node = match_ast! {
530530
match syntax {
531-
ast::SourceFile(it) => (it.attrs(), ast::DocCommentIter::from_syntax_node(it.syntax())),
532-
ast::ExternBlock(it) => {
533-
let extern_item_list = it.extern_item_list()?;
534-
(extern_item_list.attrs(), ast::DocCommentIter::from_syntax_node(extern_item_list.syntax()))
535-
},
536-
ast::Fn(it) => {
537-
let body = it.body()?;
538-
let stmt_list = body.stmt_list()?;
539-
(stmt_list.attrs(), ast::DocCommentIter::from_syntax_node(body.syntax()))
540-
},
541-
ast::Impl(it) => {
542-
let assoc_item_list = it.assoc_item_list()?;
543-
(assoc_item_list.attrs(), ast::DocCommentIter::from_syntax_node(assoc_item_list.syntax()))
544-
},
545-
ast::Module(it) => {
546-
let item_list = it.item_list()?;
547-
(item_list.attrs(), ast::DocCommentIter::from_syntax_node(item_list.syntax()))
531+
ast::SourceFile(_) => syntax.clone(),
532+
ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(),
533+
ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(),
534+
ast::Impl(it) => it.assoc_item_list()?.syntax().clone(),
535+
ast::Module(it) => it.item_list()?.syntax().clone(),
536+
ast::BlockExpr(it) => {
537+
use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT};
538+
// Block expressions accept outer and inner attributes, but only when they are the outer
539+
// expression of an expression statement or the final expression of another block expression.
540+
let may_carry_attributes = matches!(
541+
it.syntax().parent().map(|it| it.kind()),
542+
Some(BLOCK_EXPR | EXPR_STMT)
543+
);
544+
if !may_carry_attributes {
545+
return None
546+
}
547+
syntax.clone()
548548
},
549-
// FIXME: BlockExpr's only accept inner attributes in specific cases
550-
// Excerpt from the reference:
551-
// Block expressions accept outer and inner attributes, but only when they are the outer
552-
// expression of an expression statement or the final expression of another block expression.
553-
ast::BlockExpr(_it) => return None,
554549
_ => return None,
555550
}
556551
};
557-
let attrs = attrs.filter(|attr| attr.kind().is_inner());
558-
let docs = docs.filter(|doc| doc.is_inner());
559-
Some((attrs, docs))
552+
553+
let attrs = ast::AttrDocCommentIter::from_syntax_node(&node).filter(|el| match el {
554+
Either::Left(attr) => attr.kind().is_inner(),
555+
Either::Right(comment) => comment.is_inner(),
556+
});
557+
Some(attrs)
560558
}
561559

562560
#[derive(Debug)]
@@ -833,24 +831,16 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
833831
fn collect_attrs(
834832
owner: &dyn ast::HasAttrs,
835833
) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
836-
let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
837-
.map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
838-
839-
let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer());
840-
let attrs = outer_attrs
841-
.chain(inner_attrs.into_iter().flatten())
842-
.map(|attr| (attr.syntax().text_range().start(), Either::Left(attr)));
843-
844-
let outer_docs =
845-
ast::DocCommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer);
846-
let docs = outer_docs
847-
.chain(inner_docs.into_iter().flatten())
848-
.map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text)));
849-
// sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
850-
docs.chain(attrs)
851-
.sorted_by_key(|&(offset, _)| offset)
834+
let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
835+
let outer_attrs =
836+
ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
837+
Either::Left(attr) => attr.kind().is_outer(),
838+
Either::Right(comment) => comment.is_outer(),
839+
});
840+
outer_attrs
841+
.chain(inner_attrs)
852842
.enumerate()
853-
.map(|(id, (_, attr))| (AttrId { ast_index: id as u32 }, attr))
843+
.map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr))
854844
}
855845

856846
pub(crate) fn variants_attrs_source_map(

crates/hir_def/src/child_by_source.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ impl ChildBySource for ItemScope {
117117
|(ast_id, calls)| {
118118
let adt = ast_id.to_node(db.upcast());
119119
calls.for_each(|(attr_id, calls)| {
120-
if let Some(Either::Right(attr)) =
120+
if let Some(Either::Left(attr)) =
121121
adt.doc_comments_and_attrs().nth(attr_id.ast_index as usize)
122122
{
123123
res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, calls.into()));

crates/hir_expand/src/db.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ pub fn expand_speculative(
157157
let attr = item
158158
.doc_comments_and_attrs()
159159
.nth(invoc_attr_index as usize)
160-
.and_then(Either::right)?;
160+
.and_then(Either::left)?;
161161
match attr.token_tree() {
162162
Some(token_tree) => {
163163
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
@@ -323,7 +323,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
323323
ast::Item::cast(node.clone())?
324324
.doc_comments_and_attrs()
325325
.nth(invoc_attr_index as usize)
326-
.and_then(Either::right)
326+
.and_then(Either::left)
327327
.map(|attr| attr.syntax().clone())
328328
.into_iter()
329329
.collect()

crates/hir_expand/src/hygiene.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ fn make_hygiene_info(
191191
.to_node(db)
192192
.doc_comments_and_attrs()
193193
.nth(invoc_attr_index as usize)
194-
.and_then(Either::right)?
194+
.and_then(Either::left)?
195195
.token_tree()?;
196196
Some(InFile::new(ast_id.file_id, tt))
197197
}

crates/hir_expand/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ impl HirFileId {
205205
.to_node(db)
206206
.doc_comments_and_attrs()
207207
.nth(invoc_attr_index as usize)
208-
.and_then(Either::right)?
208+
.and_then(Either::left)?
209209
.token_tree()?;
210210
Some(InFile::new(ast_id.file_id, tt))
211211
}
@@ -382,7 +382,7 @@ impl MacroCallKind {
382382
.doc_comments_and_attrs()
383383
.nth(derive_attr_index as usize)
384384
.expect("missing derive")
385-
.expect_right("derive is a doc comment?")
385+
.expect_left("derive is a doc comment?")
386386
.syntax()
387387
.text_range()
388388
}
@@ -391,7 +391,7 @@ impl MacroCallKind {
391391
.doc_comments_and_attrs()
392392
.nth(invoc_attr_index as usize)
393393
.expect("missing attribute")
394-
.expect_right("attribute macro is a doc comment?")
394+
.expect_left("attribute macro is a doc comment?")
395395
.syntax()
396396
.text_range(),
397397
};
@@ -483,7 +483,7 @@ impl ExpansionInfo {
483483
let attr = item
484484
.doc_comments_and_attrs()
485485
.nth(*invoc_attr_index as usize)
486-
.and_then(Either::right)?;
486+
.and_then(Either::left)?;
487487
match attr.token_tree() {
488488
Some(token_tree)
489489
if token_tree.syntax().text_range().contains_range(token_range) =>

crates/syntax/src/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ pub use self::{
2727
operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp},
2828
token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix},
2929
traits::{
30-
DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams, HasLoopBody,
31-
HasModuleItem, HasName, HasTypeBounds, HasVisibility,
30+
AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams,
31+
HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility,
3232
},
3333
};
3434

crates/syntax/src/ast/node_ext.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,9 @@ impl ast::Attr {
160160
}
161161

162162
pub fn kind(&self) -> AttrKind {
163-
let first_token = self.syntax().first_token();
164-
let first_token_kind = first_token.as_ref().map(SyntaxToken::kind);
165-
let second_token_kind =
166-
first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind);
167-
168-
match (first_token_kind, second_token_kind) {
169-
(Some(T![#]), Some(T![!])) => AttrKind::Inner,
170-
_ => AttrKind::Outer,
163+
match self.excl_token() {
164+
Some(_) => AttrKind::Inner,
165+
None => AttrKind::Outer,
171166
}
172167
}
173168

crates/syntax/src/ast/traits.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ pub trait HasDocComments: HasAttrs {
7676
fn doc_comments(&self) -> DocCommentIter {
7777
DocCommentIter { iter: self.syntax().children_with_tokens() }
7878
}
79-
fn doc_comments_and_attrs(&self) -> AttrCommentIter {
80-
AttrCommentIter { iter: self.syntax().children_with_tokens() }
79+
fn doc_comments_and_attrs(&self) -> AttrDocCommentIter {
80+
AttrDocCommentIter { iter: self.syntax().children_with_tokens() }
8181
}
8282
}
8383

@@ -113,17 +113,23 @@ impl Iterator for DocCommentIter {
113113
}
114114
}
115115

116-
pub struct AttrCommentIter {
116+
pub struct AttrDocCommentIter {
117117
iter: SyntaxElementChildren,
118118
}
119119

120-
impl Iterator for AttrCommentIter {
121-
type Item = Either<ast::Comment, ast::Attr>;
120+
impl AttrDocCommentIter {
121+
pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> AttrDocCommentIter {
122+
AttrDocCommentIter { iter: syntax_node.children_with_tokens() }
123+
}
124+
}
125+
126+
impl Iterator for AttrDocCommentIter {
127+
type Item = Either<ast::Attr, ast::Comment>;
122128
fn next(&mut self) -> Option<Self::Item> {
123129
self.iter.by_ref().find_map(|el| match el {
124-
SyntaxElement::Node(node) => ast::Attr::cast(node).map(Either::Right),
130+
SyntaxElement::Node(node) => ast::Attr::cast(node).map(Either::Left),
125131
SyntaxElement::Token(tok) => {
126-
ast::Comment::cast(tok).filter(ast::Comment::is_doc).map(Either::Left)
132+
ast::Comment::cast(tok).filter(ast::Comment::is_doc).map(Either::Right)
127133
}
128134
})
129135
}

0 commit comments

Comments
 (0)