Skip to content

Commit ebf4658

Browse files
committed
Auto merge of rust-lang#12024 - XFFXFF:derive_completion, r=Veykril
derive completions take existing derives into count fixes rust-lang#12019 The immediate reason is that when we are doing derive completion, [`ctx.existing_derives`](https://github.com/rust-lang/rust-analyzer/blob/d1f6b4e2a0ab1a1343ab4a381c89b186a76fd001/crates/ide_completion/src/completions/attribute/derive.rs#L82) is empty, this is because we expand the macro when looking for the ancestors of the token to be completed. Take the following code as an example, we find the first `SyntaxNode` with kind `Attr` based on the ancestors of the token, but the parent of `Attr` is not a `Struct` as we [expect](https://github.com/rust-lang/rust-analyzer/blob/d1f6b4e2a0ab1a1343ab4a381c89b186a76fd001/crates/hir/src/semantics.rs#L518). ```rust #[derive(PartialEq, Eq, Or$0)] struct S; ``` The ancestors of the token to be completed above. ``` [email protected] [email protected] "Or" , [email protected] [email protected] [email protected] "Or" , [email protected] [email protected] [email protected] [email protected] "Or" , [email protected] [email protected] [email protected] [email protected] [email protected] "Or" , [email protected] [email protected] "#" [email protected] " " [email protected] "[" [email protected] [email protected] [email protected] [email protected] [email protected] "Or" [email protected] "]" [email protected] " " , [email protected] [email protected] [email protected] "#" [email protected] " " [email protected] "[" [email protected] [email protected] [email protected] [email protected] [email protected] "PartialEq" [email protected] "]" [email protected] " " [email protected] [email protected] "#" [email protected] " " [email protected] "[" [email protected] [email protected] [email protected] [email protected] [email protected] "Eq" [email protected] "]" [email protected] " " [email protected] [email protected] "#" [email protected] " " [email protected] "[" [email protected] [email protected] [email protected] [email protected] [email protected] "Or" [email protected] "]" [email protected] " " [email protected] "(" [email protected] " " [email protected] ")" [email protected] " " ... ``` I make a small change to not do macro expansion when looking up the ancestors of the token. What I don't understand is that `self.sema.token_ancestors_with_macros(self.token.clone())` doesn't seem to expand the macro if the derive completion triggered without any prefix, like `#[derive(PartialEq, Eq, $0)]`. The ancestors of the token with `#[derive(PartialEq, Eq, $0)]`. ``` [email protected] [email protected] "(" [email protected] "PartialEq" [email protected] "," [email protected] " " [email protected] "Eq" [email protected] "," [email protected] " " [email protected] ")" , [email protected] [email protected] [email protected] [email protected] [email protected] "derive" [email protected] [email protected] "(" [email protected] "PartialEq" [email protected] "," [email protected] " " [email protected] "Eq" [email protected] "," [email protected] " " [email protected] ")" , [email protected] [email protected] "#" [email protected] "[" [email protected] [email protected] [email protected] [email protected] [email protected] "derive" [email protected] [email protected] "(" [email protected] "PartialEq" [email protected] "," [email protected] " " [email protected] "Eq" [email protected] "," [email protected] " " [email protected] ")" [email protected] "]" , [email protected] [email protected] [email protected] "#" [email protected] "[" [email protected] [email protected] [email protected] [email protected] [email protected] "derive" [email protected] [email protected] "(" [email protected] "PartialEq" [email protected] "," [email protected] " " [email protected] "Eq" [email protected] "," [email protected] " " [email protected] ")" [email protected] "]" [email protected] " " [email protected] "struct" [email protected] " " [email protected] [email protected] "Test" [email protected] ";" ... ```
2 parents d1f6b4e + fedd024 commit ebf4658

File tree

2 files changed

+31
-11
lines changed

2 files changed

+31
-11
lines changed

crates/ide_completion/src/context.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,8 @@ impl<'a> CompletionContext<'a> {
523523
// successful expansions
524524
(Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
525525
let new_offset = fake_mapped_token.text_range().start();
526-
derive_ctx = Some((actual_expansion, fake_expansion, new_offset));
526+
derive_ctx =
527+
Some((actual_expansion, fake_expansion, new_offset, orig_attr));
527528
break 'expansion;
528529
}
529530
// exactly one expansion failed, inconsistent state so stop expanding completely
@@ -718,7 +719,7 @@ impl<'a> CompletionContext<'a> {
718719
original_file: &SyntaxNode,
719720
file_with_fake_ident: SyntaxNode,
720721
offset: TextSize,
721-
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize)>,
722+
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
722723
) {
723724
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
724725
let syntax_element = NodeOrToken::Token(fake_ident_token);
@@ -742,16 +743,14 @@ impl<'a> CompletionContext<'a> {
742743
(self.expected_type, self.expected_name) = self.expected_type_and_name();
743744

744745
// Overwrite the path kind for derives
745-
if let Some((original_file, file_with_fake_ident, offset)) = derive_ctx {
746-
let attr = self
746+
if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
747+
self.existing_derives = self
747748
.sema
748-
.token_ancestors_with_macros(self.token.clone())
749-
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
750-
.find_map(ast::Attr::cast);
751-
if let Some(attr) = &attr {
752-
self.existing_derives =
753-
self.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
754-
}
749+
.resolve_derive_macro(&origin_attr)
750+
.into_iter()
751+
.flatten()
752+
.flatten()
753+
.collect();
755754

756755
if let Some(ast::NameLike::NameRef(name_ref)) =
757756
find_node_at_offset(&file_with_fake_ident, offset)

crates/ide_completion/src/tests/attribute.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,27 @@ mod derive {
747747
);
748748
}
749749

750+
#[test]
751+
fn derive_with_existing_derives() {
752+
check_derive(
753+
r#"
754+
//- minicore: derive, copy, clone, ord, eq, default, fmt
755+
#[derive(PartialEq, Eq, Or$0)] struct Test;
756+
"#,
757+
expect![[r#"
758+
md core
759+
de Default macro Default
760+
de Clone, Copy
761+
de PartialOrd, Ord
762+
de Clone macro Clone
763+
de PartialOrd
764+
kw self::
765+
kw super::
766+
kw crate::
767+
"#]],
768+
);
769+
}
770+
750771
#[test]
751772
fn derive_flyimport() {
752773
check_derive(

0 commit comments

Comments
 (0)