Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
-rw-r--r--crates/hir/src/source_analyzer.rs54
1 files changed, 30 insertions, 24 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8e71a54f80..81c57f6cae 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -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.text_range().contains_inclusive(offset),
+ "{:?} not in {:?}",
+ offset,
+ node.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,15 @@ 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.kind()) || ast::MacroCall::can_cast(it.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))
}
@@ -988,8 +994,8 @@ fn scope_for_offset(
Some(it.file_id.macro_file()?.call_node(db.upcast()))
})
.find(|it| it.file_id == from_file)
- .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
- Some((source.value.text_range(), scope))
+ .filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?;
+ Some((source.text_range(), scope))
})
.filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
// find containing scope