diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d357755236..fe518c8642 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -664,7 +664,7 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: let attr = node .doc_comments_and_attrs() .nth((*invoc_attr_index) as usize) - .and_then(Either::right) + .and_then(Either::left) .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index)); ( ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 2bffb12dee..eefc12570d 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -364,9 +364,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_derive_ident(derive, ident) } - // FIXME: use this instead? - // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option; - pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { self.imp.record_literal_missing_fields(literal) } @@ -931,7 +928,6 @@ impl<'db> SemanticsImpl<'db> { file.with_value(derive.clone()), )?; let attrs = adt_def.attrs(self.db); - // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/11298 let mut derive_paths = attrs.get(attr_id)?.parse_path_comma_token_tree()?; let derive_idx = tt diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 4aeb714189..0a8fb2e47a 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -73,8 +73,8 @@ impl ops::Deref for RawAttrs { } } impl Attrs { - pub fn get(&self, AttrId { ast_index, .. }: AttrId) -> Option<&Attr> { - (**self).get(ast_index as usize) + pub fn get(&self, id: AttrId) -> Option<&Attr> { + (**self).iter().find(|attr| attr.id == id) } } @@ -89,14 +89,6 @@ impl ops::Deref for Attrs { } } -impl ops::Index for Attrs { - type Output = Attr; - - fn index(&self, AttrId { ast_index, .. }: AttrId) -> &Self::Output { - &(**self)[ast_index as usize] - } -} - impl ops::Deref for AttrsWithOwner { type Target = Attrs; @@ -110,7 +102,7 @@ impl RawAttrs { pub(crate) fn new(db: &dyn DefDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self { let entries = collect_attrs(owner) - .flat_map(|(id, attr)| match attr { + .filter_map(|(id, attr)| match attr { Either::Left(attr) => { attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id)) } @@ -525,38 +517,36 @@ impl AttrsWithOwner { fn inner_attributes( syntax: &SyntaxNode, -) -> Option<(impl Iterator, impl Iterator)> { - let (attrs, docs) = match_ast! { +) -> Option>> { + let node = match_ast! { match syntax { - ast::SourceFile(it) => (it.attrs(), ast::DocCommentIter::from_syntax_node(it.syntax())), - ast::ExternBlock(it) => { - let extern_item_list = it.extern_item_list()?; - (extern_item_list.attrs(), ast::DocCommentIter::from_syntax_node(extern_item_list.syntax())) + ast::SourceFile(_) => syntax.clone(), + ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(), + ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(), + ast::Impl(it) => it.assoc_item_list()?.syntax().clone(), + ast::Module(it) => it.item_list()?.syntax().clone(), + ast::BlockExpr(it) => { + use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT}; + // Block expressions accept outer and inner attributes, but only when they are the outer + // expression of an expression statement or the final expression of another block expression. + let may_carry_attributes = matches!( + it.syntax().parent().map(|it| it.kind()), + Some(BLOCK_EXPR | EXPR_STMT) + ); + if !may_carry_attributes { + return None + } + syntax.clone() }, - ast::Fn(it) => { - let body = it.body()?; - let stmt_list = body.stmt_list()?; - (stmt_list.attrs(), ast::DocCommentIter::from_syntax_node(body.syntax())) - }, - ast::Impl(it) => { - let assoc_item_list = it.assoc_item_list()?; - (assoc_item_list.attrs(), ast::DocCommentIter::from_syntax_node(assoc_item_list.syntax())) - }, - ast::Module(it) => { - let item_list = it.item_list()?; - (item_list.attrs(), ast::DocCommentIter::from_syntax_node(item_list.syntax())) - }, - // FIXME: BlockExpr's only accept inner attributes in specific cases - // Excerpt from the reference: - // Block expressions accept outer and inner attributes, but only when they are the outer - // expression of an expression statement or the final expression of another block expression. - ast::BlockExpr(_it) => return None, _ => return None, } }; - let attrs = attrs.filter(|attr| attr.kind().is_inner()); - let docs = docs.filter(|doc| doc.is_inner()); - Some((attrs, docs)) + + let attrs = ast::AttrDocCommentIter::from_syntax_node(&node).filter(|el| match el { + Either::Left(attr) => attr.kind().is_inner(), + Either::Right(comment) => comment.is_inner(), + }); + Some(attrs) } #[derive(Debug)] @@ -833,24 +823,16 @@ fn attrs_from_item_tree(id: ItemTreeId, db: &dyn DefDatabase fn collect_attrs( owner: &dyn ast::HasAttrs, ) -> impl Iterator)> { - let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) - .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); - - let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer()); - let attrs = outer_attrs - .chain(inner_attrs.into_iter().flatten()) - .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); - - let outer_docs = - ast::DocCommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer); - let docs = outer_docs - .chain(inner_docs.into_iter().flatten()) - .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text))); - // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved - docs.chain(attrs) - .sorted_by_key(|&(offset, _)| offset) + let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten(); + let outer_attrs = + ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el { + Either::Left(attr) => attr.kind().is_outer(), + Either::Right(comment) => comment.is_outer(), + }); + outer_attrs + .chain(inner_attrs) .enumerate() - .map(|(id, (_, attr))| (AttrId { ast_index: id as u32 }, attr)) + .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr)) } pub(crate) fn variants_attrs_source_map( diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs index 6b4abd8c44..5c32a31e44 100644 --- a/crates/hir_def/src/child_by_source.rs +++ b/crates/hir_def/src/child_by_source.rs @@ -117,7 +117,7 @@ impl ChildBySource for ItemScope { |(ast_id, calls)| { let adt = ast_id.to_node(db.upcast()); calls.for_each(|(attr_id, calls)| { - if let Some(Either::Right(attr)) = + if let Some(Either::Left(attr)) = adt.doc_comments_and_attrs().nth(attr_id.ast_index as usize) { res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, calls.into())); diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 69749decd5..b46f3fc955 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -157,7 +157,7 @@ pub fn expand_speculative( let attr = item .doc_comments_and_attrs() .nth(invoc_attr_index as usize) - .and_then(Either::right)?; + .and_then(Either::left)?; match attr.token_tree() { Some(token_tree) => { 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 diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 29fc1fd2e0..e599efc5e2 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -1364,10 +1364,21 @@ impl Twait for Stwuct { fn goto_def_derive_input() { check( r#" + //- minicore:derive + #[rustc_builtin_macro] + pub macro Copy {} + // ^^^^ + #[derive(Copy$0)] + struct Foo; + "#, + ); + check( + r#" //- minicore:derive #[rustc_builtin_macro] pub macro Copy {} // ^^^^ +#[cfg_attr(feature = "false", derive)] #[derive(Copy$0)] struct Foo; "#, diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 5c1aed3cd4..91b46cf8e9 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs @@ -27,8 +27,8 @@ pub use self::{ operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix}, traits::{ - DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams, HasLoopBody, - HasModuleItem, HasName, HasTypeBounds, HasVisibility, + AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams, + HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility, }, }; diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 705aa5edac..7211c77e88 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -160,14 +160,9 @@ impl ast::Attr { } pub fn kind(&self) -> AttrKind { - let first_token = self.syntax().first_token(); - let first_token_kind = first_token.as_ref().map(SyntaxToken::kind); - let second_token_kind = - first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); - - match (first_token_kind, second_token_kind) { - (Some(T![#]), Some(T![!])) => AttrKind::Inner, - _ => AttrKind::Outer, + match self.excl_token() { + Some(_) => AttrKind::Inner, + None => AttrKind::Outer, } } diff --git a/crates/syntax/src/ast/traits.rs b/crates/syntax/src/ast/traits.rs index 98b1087e64..aa2b7ed5c8 100644 --- a/crates/syntax/src/ast/traits.rs +++ b/crates/syntax/src/ast/traits.rs @@ -76,8 +76,8 @@ pub trait HasDocComments: HasAttrs { fn doc_comments(&self) -> DocCommentIter { DocCommentIter { iter: self.syntax().children_with_tokens() } } - fn doc_comments_and_attrs(&self) -> AttrCommentIter { - AttrCommentIter { iter: self.syntax().children_with_tokens() } + fn doc_comments_and_attrs(&self) -> AttrDocCommentIter { + AttrDocCommentIter { iter: self.syntax().children_with_tokens() } } } @@ -113,17 +113,23 @@ impl Iterator for DocCommentIter { } } -pub struct AttrCommentIter { +pub struct AttrDocCommentIter { iter: SyntaxElementChildren, } -impl Iterator for AttrCommentIter { - type Item = Either; +impl AttrDocCommentIter { + pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> AttrDocCommentIter { + AttrDocCommentIter { iter: syntax_node.children_with_tokens() } + } +} + +impl Iterator for AttrDocCommentIter { + type Item = Either; fn next(&mut self) -> Option { self.iter.by_ref().find_map(|el| match el { - SyntaxElement::Node(node) => ast::Attr::cast(node).map(Either::Right), + SyntaxElement::Node(node) => ast::Attr::cast(node).map(Either::Left), SyntaxElement::Token(tok) => { - ast::Comment::cast(tok).filter(ast::Comment::is_doc).map(Either::Left) + ast::Comment::cast(tok).filter(ast::Comment::is_doc).map(Either::Right) } }) }