Skip to content

Commit 4d3ad04

Browse files
bors[bot]matklad
andauthored
Merge #11131
11131: internal: avoid speculation when completing macros r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents d6c3070 + 177a183 commit 4d3ad04

File tree

5 files changed

+50
-33
lines changed

5 files changed

+50
-33
lines changed

crates/hir/src/semantics.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use hir_def::{
1010
resolver::{self, HasResolver, Resolver, TypeNs},
1111
AsMacroCall, FunctionId, TraitId, VariantId,
1212
};
13-
use hir_expand::{name::AsName, ExpansionInfo};
13+
use hir_expand::{name::AsName, ExpansionInfo, MacroCallId, MacroCallLoc};
1414
use hir_ty::{associated_type_shorthand_candidates, Interner};
1515
use itertools::Itertools;
1616
use rustc_hash::{FxHashMap, FxHashSet};
@@ -160,6 +160,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
160160
self.imp.expand_attr_macro(item)
161161
}
162162

163+
pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<MacroDef>> {
164+
self.imp.resolve_derive_macro(derive)
165+
}
166+
163167
pub fn expand_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<SyntaxNode>> {
164168
self.imp.expand_derive_macro(derive)
165169
}
@@ -443,28 +447,40 @@ impl<'db> SemanticsImpl<'db> {
443447
Some(node)
444448
}
445449

450+
fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<MacroDef>> {
451+
let res = self
452+
.derive_macro_calls(attr)?
453+
.iter()
454+
.map(|&call| {
455+
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call);
456+
MacroDef { id: loc.def }
457+
})
458+
.collect();
459+
Some(res)
460+
}
461+
446462
fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
463+
let res: Vec<_> = self
464+
.derive_macro_calls(attr)?
465+
.iter()
466+
.map(|call| call.as_file())
467+
.flat_map(|file_id| {
468+
let node = self.db.parse_or_expand(file_id)?;
469+
self.cache(node.clone(), file_id);
470+
Some(node)
471+
})
472+
.collect();
473+
Some(res)
474+
}
475+
476+
fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<MacroCallId>> {
447477
let item = attr.syntax().parent().and_then(ast::Item::cast)?;
448478
let file_id = self.find_file(item.syntax()).file_id;
449479
let item = InFile::new(file_id, &item);
450480
let src = InFile::new(file_id, attr.clone());
451481
self.with_ctx(|ctx| {
452-
let macro_call_ids = ctx.attr_to_derive_macro_call(item, src)?;
453-
454-
let expansions: Vec<_> = macro_call_ids
455-
.iter()
456-
.map(|call| call.as_file())
457-
.flat_map(|file_id| {
458-
let node = self.db.parse_or_expand(file_id)?;
459-
self.cache(node.clone(), file_id);
460-
Some(node)
461-
})
462-
.collect();
463-
if expansions.is_empty() {
464-
None
465-
} else {
466-
Some(expansions)
467-
}
482+
let res = ctx.attr_to_derive_macro_call(item, src)?;
483+
Some(res.to_vec())
468484
})
469485
}
470486

crates/ide_completion/src/completions/attribute.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ mod lint;
2626
mod repr;
2727

2828
pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
29-
let attribute = ctx.attribute_under_caret.as_ref()?;
29+
let attribute = ctx.fake_attribute_under_caret.as_ref()?;
3030
let name_ref = match attribute.path() {
3131
Some(p) => Some(p.as_single_name_ref()?),
3232
None => None,
3333
};
3434
match (name_ref, attribute.token_tree()) {
3535
(Some(path), Some(tt)) if tt.l_paren_token().is_some() => match path.text().as_str() {
3636
"repr" => repr::complete_repr(acc, ctx, tt),
37-
"derive" => derive::complete_derive(acc, ctx, &parse_tt_as_comma_sep_paths(tt)?),
37+
"derive" => derive::complete_derive(acc, ctx, ctx.attr.as_ref()?),
3838
"feature" => lint::complete_lint(acc, ctx, &parse_tt_as_comma_sep_paths(tt)?, FEATURES),
3939
"allow" | "warn" | "deny" | "forbid" => {
4040
let existing_lints = parse_tt_as_comma_sep_paths(tt)?;

crates/ide_completion/src/completions/attribute/derive.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,10 @@ use crate::{
1313
item::CompletionItem, Completions, ImportEdit,
1414
};
1515

16-
pub(super) fn complete_derive(
17-
acc: &mut Completions,
18-
ctx: &CompletionContext,
19-
existing_derives: &[ast::Path],
20-
) {
16+
pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, attr: &ast::Attr) {
2117
let core = ctx.famous_defs().core();
22-
let existing_derives: FxHashSet<_> = existing_derives
23-
.into_iter()
24-
.filter_map(|path| ctx.scope.speculative_resolve_as_mac(&path))
25-
.filter(|mac| mac.kind() == MacroKind::Derive)
26-
.collect();
18+
let existing_derives: FxHashSet<_> =
19+
ctx.sema.resolve_derive_macro(attr).into_iter().flatten().collect();
2720

2821
for (name, mac) in get_derives_in_scope(ctx) {
2922
if existing_derives.contains(&mac) {

crates/ide_completion/src/completions/keyword.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
1919
cov_mark::hit!(no_keyword_completion_in_record_lit);
2020
return;
2121
}
22-
if ctx.attribute_under_caret.is_some() {
22+
if ctx.fake_attribute_under_caret.is_some() {
2323
cov_mark::hit!(no_keyword_completion_in_attr_of_expr);
2424
return;
2525
}

crates/ide_completion/src/context.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ pub(crate) struct CompletionContext<'a> {
103103

104104
/// The parent function of the cursor position if it exists.
105105
pub(super) function_def: Option<ast::Fn>,
106+
pub(super) attr: Option<ast::Attr>,
106107
/// The parent impl of the cursor position if it exists.
107108
pub(super) impl_def: Option<ast::Impl>,
108109
/// The NameLike under the cursor in the original file if it exists.
@@ -111,7 +112,7 @@ pub(crate) struct CompletionContext<'a> {
111112

112113
pub(super) completion_location: Option<ImmediateLocation>,
113114
pub(super) prev_sibling: Option<ImmediatePrevSibling>,
114-
pub(super) attribute_under_caret: Option<ast::Attr>,
115+
pub(super) fake_attribute_under_caret: Option<ast::Attr>,
115116
pub(super) previous_token: Option<SyntaxToken>,
116117

117118
pub(super) lifetime_ctx: Option<LifetimeContext>,
@@ -397,13 +398,14 @@ impl<'a> CompletionContext<'a> {
397398
expected_name: None,
398399
expected_type: None,
399400
function_def: None,
401+
attr: None,
400402
impl_def: None,
401403
name_syntax: None,
402404
lifetime_ctx: None,
403405
pattern_ctx: None,
404406
completion_location: None,
405407
prev_sibling: None,
406-
attribute_under_caret: None,
408+
fake_attribute_under_caret: None,
407409
previous_token: None,
408410
path_context: None,
409411
locals,
@@ -641,14 +643,20 @@ impl<'a> CompletionContext<'a> {
641643
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
642644
let syntax_element = NodeOrToken::Token(fake_ident_token);
643645
self.previous_token = previous_token(syntax_element.clone());
644-
self.attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
645646
self.no_completion_required = {
646647
let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
647648
let fn_is_prev = self.previous_token_is(T![fn]);
648649
let for_is_prev2 = for_is_prev2(syntax_element.clone());
649650
(fn_is_prev && !inside_impl_trait_block) || for_is_prev2
650651
};
651652

653+
self.attr = self
654+
.sema
655+
.token_ancestors_with_macros(self.token.clone())
656+
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
657+
.find_map(ast::Attr::cast);
658+
self.fake_attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
659+
652660
self.incomplete_let =
653661
syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
654662
it.syntax().text_range().end() == syntax_element.text_range().end()

0 commit comments

Comments
 (0)