Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9eaf96c

Browse files
committed
Auto merge of rust-lang#12643 - Veykril:macro-compl, r=Veykril
fix: Fix completions for locals not working properly inside macro calls
2 parents 4c39546 + bdbffdd commit 9eaf96c

File tree

3 files changed

+45
-19
lines changed

3 files changed

+45
-19
lines changed

crates/hir/src/source_analyzer.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,7 @@ impl SourceAnalyzer {
6767
let scopes = db.expr_scopes(def);
6868
let scope = match offset {
6969
None => scope_for(&scopes, &source_map, node),
70-
Some(offset) => {
71-
let file_id = node.file_id.original_file(db.upcast());
72-
scope_for_offset(db, &scopes, &source_map, InFile::new(file_id.into(), offset))
73-
}
70+
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
7471
};
7572
let resolver = resolver_for_scope(db.upcast(), def, scope);
7673
SourceAnalyzer {
@@ -91,10 +88,7 @@ impl SourceAnalyzer {
9188
let scopes = db.expr_scopes(def);
9289
let scope = match offset {
9390
None => scope_for(&scopes, &source_map, node),
94-
Some(offset) => {
95-
let file_id = node.file_id.original_file(db.upcast());
96-
scope_for_offset(db, &scopes, &source_map, InFile::new(file_id.into(), offset))
97-
}
91+
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
9892
};
9993
let resolver = resolver_for_scope(db.upcast(), def, scope);
10094
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
@@ -585,14 +579,15 @@ fn scope_for_offset(
585579
db: &dyn HirDatabase,
586580
scopes: &ExprScopes,
587581
source_map: &BodySourceMap,
588-
offset: InFile<TextSize>,
582+
from_file: HirFileId,
583+
offset: TextSize,
589584
) -> Option<ScopeId> {
590585
scopes
591586
.scope_by_expr()
592587
.iter()
593588
.filter_map(|(id, scope)| {
594589
let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?;
595-
if offset.file_id == file_id {
590+
if from_file == file_id {
596591
let root = db.parse_or_expand(file_id)?;
597592
let node = value.to_node(&root);
598593
return Some((node.syntax().text_range(), scope));
@@ -602,17 +597,15 @@ fn scope_for_offset(
602597
let source = iter::successors(file_id.call_node(db.upcast()), |it| {
603598
it.file_id.call_node(db.upcast())
604599
})
605-
.find(|it| it.file_id == offset.file_id)
600+
.find(|it| it.file_id == from_file)
606601
.filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
607602
Some((source.value.text_range(), scope))
608603
})
609-
.filter(|(expr_range, _scope)| {
610-
expr_range.start() <= offset.value && offset.value <= expr_range.end()
611-
})
604+
.filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
612605
// find containing scope
613606
.min_by_key(|(expr_range, _scope)| expr_range.len())
614607
.map(|(expr_range, scope)| {
615-
adjust(db, scopes, source_map, expr_range, offset).unwrap_or(*scope)
608+
adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
616609
})
617610
}
618611

@@ -623,23 +616,24 @@ fn adjust(
623616
scopes: &ExprScopes,
624617
source_map: &BodySourceMap,
625618
expr_range: TextRange,
626-
offset: InFile<TextSize>,
619+
from_file: HirFileId,
620+
offset: TextSize,
627621
) -> Option<ScopeId> {
628622
let child_scopes = scopes
629623
.scope_by_expr()
630624
.iter()
631625
.filter_map(|(id, scope)| {
632626
let source = source_map.expr_syntax(*id).ok()?;
633627
// FIXME: correctly handle macro expansion
634-
if source.file_id != offset.file_id {
628+
if source.file_id != from_file {
635629
return None;
636630
}
637631
let root = source.file_syntax(db.upcast());
638632
let node = source.value.to_node(&root);
639633
Some((node.syntax().text_range(), scope))
640634
})
641635
.filter(|&(range, _)| {
642-
range.start() <= offset.value && expr_range.contains_range(range) && range != expr_range
636+
range.start() <= offset && expr_range.contains_range(range) && range != expr_range
643637
});
644638

645639
child_scopes

crates/ide-completion/src/context.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,11 @@ impl<'a> CompletionContext<'a> {
506506

507507
let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
508508
let token = sema.descend_into_macros_single(original_token.clone());
509-
let scope = sema.scope_at_offset(&token.parent()?, offset)?;
509+
510+
// adjust for macro input, this still fails if there is no token written yet
511+
let scope_offset = if original_token == token { offset } else { token.text_range().end() };
512+
let scope = sema.scope_at_offset(&token.parent()?, scope_offset)?;
513+
510514
let krate = scope.krate();
511515
let module = scope.module();
512516

crates/ide-completion/src/tests/special.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,3 +782,31 @@ fn main() {
782782
"#]],
783783
)
784784
}
785+
786+
#[test]
787+
fn completes_locals_from_macros() {
788+
check(
789+
r#"
790+
791+
macro_rules! x {
792+
($x:ident, $expr:expr) => {
793+
let $x = 0;
794+
$expr
795+
};
796+
}
797+
fn main() {
798+
x! {
799+
foobar, {
800+
f$0
801+
}
802+
};
803+
}
804+
"#,
805+
expect![[r#"
806+
fn main() fn()
807+
lc foobar i32
808+
ma x!(…) macro_rules! x
809+
bt u32
810+
"#]],
811+
)
812+
}

0 commit comments

Comments
 (0)