about summary refs log tree commit diff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-01-30 22:08:25 +0000
committerGitHub <noreply@github.com>2022-01-30 22:08:25 +0000
commitfd3942eb620e37a4e4bfdd587d8a2893ccf6fea0 (patch)
treef9f387ca6d71551eecda7ca359be7322456f249b /crates
parentc08df0f1f5e188e2e1e8f1715ff3a6d583cfb9f3 (diff)
parentddf7b70a0f8f7fc1e49d2bf0365752be3b4aab8b (diff)
downloadrust-fd3942eb620e37a4e4bfdd587d8a2893ccf6fea0.tar.gz
rust-fd3942eb620e37a4e4bfdd587d8a2893ccf6fea0.zip
Merge #11382
11382: fix: Fix `cfg_attr` invalidating derive identifier IDE functionalities r=Veykril a=Veykril

Proper fix for https://github.com/rust-analyzer/rust-analyzer/issues/11298
bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/semantics.rs4
-rw-r--r--crates/hir_def/src/attr.rs92
-rw-r--r--crates/hir_def/src/child_by_source.rs2
-rw-r--r--crates/hir_expand/src/db.rs4
-rw-r--r--crates/hir_expand/src/hygiene.rs2
-rw-r--r--crates/hir_expand/src/lib.rs8
-rw-r--r--crates/ide/src/goto_definition.rs11
-rw-r--r--crates/syntax/src/ast.rs4
-rw-r--r--crates/syntax/src/ast/node_ext.rs11
-rw-r--r--crates/syntax/src/ast/traits.rs20
11 files changed, 75 insertions, 85 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d3577552361..fe518c86429 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<AnyDiagnostic>, 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 2bffb12deee..eefc12570d7 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 4aeb714189a..0a8fb2e47a8 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<AttrId> 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<Item = ast::Attr>, impl Iterator<Item = ast::Comment>)> {
-    let (attrs, docs) = match_ast! {
+) -> Option<impl Iterator<Item = Either<ast::Attr, ast::Comment>>> {
+    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::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()))
+            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()
             },
-            // 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<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
 fn collect_attrs(
     owner: &dyn ast::HasAttrs,
 ) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
-    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 6b4abd8c44e..5c32a31e443 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 69749decd5c..b46f3fc9554 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<Sy
                 ast::Item::cast(node.clone())?
                     .doc_comments_and_attrs()
                     .nth(invoc_attr_index as usize)
-                    .and_then(Either::right)
+                    .and_then(Either::left)
                     .map(|attr| attr.syntax().clone())
                     .into_iter()
                     .collect()
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index d7dc0443b21..d2b719bf570 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -191,7 +191,7 @@ fn make_hygiene_info(
                 .to_node(db)
                 .doc_comments_and_attrs()
                 .nth(invoc_attr_index as usize)
-                .and_then(Either::right)?
+                .and_then(Either::left)?
                 .token_tree()?;
             Some(InFile::new(ast_id.file_id, tt))
         }
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index a1b1e943f12..51899ca2f65 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -205,7 +205,7 @@ impl HirFileId {
                             .to_node(db)
                             .doc_comments_and_attrs()
                             .nth(invoc_attr_index as usize)
-                            .and_then(Either::right)?
+                            .and_then(Either::left)?
                             .token_tree()?;
                         Some(InFile::new(ast_id.file_id, tt))
                     }
@@ -382,7 +382,7 @@ impl MacroCallKind {
                     .doc_comments_and_attrs()
                     .nth(derive_attr_index as usize)
                     .expect("missing derive")
-                    .expect_right("derive is a doc comment?")
+                    .expect_left("derive is a doc comment?")
                     .syntax()
                     .text_range()
             }
@@ -391,7 +391,7 @@ impl MacroCallKind {
                 .doc_comments_and_attrs()
                 .nth(invoc_attr_index as usize)
                 .expect("missing attribute")
-                .expect_right("attribute macro is a doc comment?")
+                .expect_left("attribute macro is a doc comment?")
                 .syntax()
                 .text_range(),
         };
@@ -483,7 +483,7 @@ impl ExpansionInfo {
                     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)
                             if token_tree.syntax().text_range().contains_range(token_range) =>
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 29fc1fd2e03..e599efc5e2d 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 5c1aed3cd48..91b46cf8e9d 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 705aa5edac4..7211c77e880 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 98b1087e641..aa2b7ed5c8b 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<ast::Comment, ast::Attr>;
+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<ast::Attr, ast::Comment>;
     fn next(&mut self) -> Option<Self::Item> {
         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)
             }
         })
     }