Fix expression scope calculation when within macro expansions

This commit is contained in:
Lukas Wirth 2024-06-30 13:26:17 +02:00
parent 882ae7105d
commit bfb187aacd
7 changed files with 99 additions and 33 deletions

View file

@ -68,38 +68,44 @@ impl SourceAnalyzer {
pub(crate) fn new_for_body(
db: &dyn HirDatabase,
def: DefWithBodyId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
) -> SourceAnalyzer {
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
let scope = match offset {
None => scope_for(&scopes, &source_map, node),
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
};
let resolver = resolver_for_scope(db.upcast(), def, scope);
SourceAnalyzer {
resolver,
def: Some((def, body, source_map)),
infer: Some(db.infer(def)),
file_id,
}
Self::new_for_body_(db, def, node, offset, Some(db.infer(def)))
}
pub(crate) fn new_for_body_no_infer(
db: &dyn HirDatabase,
def: DefWithBodyId,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
) -> SourceAnalyzer {
Self::new_for_body_(db, def, node, offset, None)
}
pub(crate) fn new_for_body_(
db: &dyn HirDatabase,
def: DefWithBodyId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
offset: Option<TextSize>,
infer: Option<Arc<InferenceResult>>,
) -> SourceAnalyzer {
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
let scope = match offset {
None => scope_for(&scopes, &source_map, node),
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
None => scope_for(db, &scopes, &source_map, node),
Some(offset) => {
debug_assert!(
node.value.text_range().contains_inclusive(offset),
"{:?} not in {:?}",
offset,
node.value.text_range()
);
scope_for_offset(db, &scopes, &source_map, node.file_id, offset)
}
};
let resolver = resolver_for_scope(db.upcast(), def, scope);
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer, file_id }
}
pub(crate) fn new_for_resolver(
@ -662,7 +668,6 @@ impl SourceAnalyzer {
return resolved;
}
// This must be a normal source file rather than macro file.
let ctx = LowerCtx::new(db.upcast(), self.file_id);
let hir_path = Path::from_src(&ctx, path.clone())?;
@ -955,14 +960,17 @@ impl SourceAnalyzer {
}
fn scope_for(
db: &dyn HirDatabase,
scopes: &ExprScopes,
source_map: &BodySourceMap,
node: InFile<&SyntaxNode>,
) -> Option<ScopeId> {
node.value
.ancestors()
.filter_map(ast::Expr::cast)
.filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
node.ancestors_with_macros(db.upcast())
.take_while(|it| {
!ast::Item::can_cast(it.value.kind()) || ast::MacroCall::can_cast(it.value.kind())
})
.filter_map(|it| it.map(ast::Expr::cast).transpose())
.filter_map(|it| source_map.node_expr(it.as_ref()))
.find_map(|it| scopes.scope_for(it))
}