mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Introduce SourceBinder
This commit is contained in:
parent
c0661ce744
commit
ccfe53376a
5 changed files with 217 additions and 101 deletions
|
@ -14,30 +14,26 @@ use hir_def::{
|
|||
BodySourceMap,
|
||||
},
|
||||
expr::{ExprId, PatId},
|
||||
nameres::ModuleSource,
|
||||
resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
|
||||
resolver::{self, resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||
DefWithBodyId, TraitId,
|
||||
};
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
|
||||
};
|
||||
use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment};
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode},
|
||||
match_ast, AstPtr,
|
||||
SyntaxKind::*,
|
||||
SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit,
|
||||
AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit,
|
||||
};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, Adt, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, ImplBlock,
|
||||
Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam,
|
||||
db::HirDatabase, Adt, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, Name, Path,
|
||||
ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam,
|
||||
};
|
||||
|
||||
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
|
||||
/// original source files. It should not be used inside the HIR itself.
|
||||
/// original source files. It should not be used pinside the HIR itself.
|
||||
#[derive(Debug)]
|
||||
pub struct SourceAnalyzer {
|
||||
file_id: HirFileId,
|
||||
|
@ -109,37 +105,43 @@ impl SourceAnalyzer {
|
|||
node: InFile<&SyntaxNode>,
|
||||
offset: Option<TextUnit>,
|
||||
) -> SourceAnalyzer {
|
||||
let _p = profile("SourceAnalyzer::new");
|
||||
let def_with_body = def_with_body_from_child_node(db, node);
|
||||
if let Some(def) = def_with_body {
|
||||
let (_body, source_map) = db.body_with_source_map(def.into());
|
||||
let scopes = db.expr_scopes(def.into());
|
||||
let scope = match offset {
|
||||
None => scope_for(&scopes, &source_map, node),
|
||||
Some(offset) => scope_for_offset(&scopes, &source_map, node.with_value(offset)),
|
||||
};
|
||||
let resolver = resolver_for_scope(db, def.into(), scope);
|
||||
SourceAnalyzer {
|
||||
resolver,
|
||||
body_owner: Some(def),
|
||||
body_source_map: Some(source_map),
|
||||
infer: Some(db.infer(def.into())),
|
||||
scopes: Some(scopes),
|
||||
file_id: node.file_id,
|
||||
}
|
||||
} else {
|
||||
SourceAnalyzer {
|
||||
resolver: node
|
||||
.value
|
||||
.ancestors()
|
||||
.find_map(|it| try_get_resolver_for_node(db, node.with_value(&it)))
|
||||
.unwrap_or_default(),
|
||||
body_owner: None,
|
||||
body_source_map: None,
|
||||
infer: None,
|
||||
scopes: None,
|
||||
file_id: node.file_id,
|
||||
}
|
||||
crate::source_binder::SourceBinder::default().analyze(db, node, offset)
|
||||
}
|
||||
|
||||
pub(crate) fn new_for_body(
|
||||
db: &impl HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
node: InFile<&SyntaxNode>,
|
||||
offset: Option<TextUnit>,
|
||||
) -> 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(&scopes, &source_map, node.with_value(offset)),
|
||||
};
|
||||
let resolver = resolver_for_scope(db, def, scope);
|
||||
SourceAnalyzer {
|
||||
resolver,
|
||||
body_owner: Some(def.into()),
|
||||
body_source_map: Some(source_map),
|
||||
infer: Some(db.infer(def)),
|
||||
scopes: Some(scopes),
|
||||
file_id: node.file_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_for_resolver(
|
||||
resolver: Resolver,
|
||||
node: InFile<&SyntaxNode>,
|
||||
) -> SourceAnalyzer {
|
||||
SourceAnalyzer {
|
||||
resolver,
|
||||
body_owner: None,
|
||||
body_source_map: None,
|
||||
infer: None,
|
||||
scopes: None,
|
||||
file_id: node.file_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,64 +368,6 @@ impl SourceAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> Option<Resolver> {
|
||||
match_ast! {
|
||||
match (node.value) {
|
||||
ast::Module(it) => {
|
||||
let src = node.with_value(it);
|
||||
Some(crate::Module::from_declaration(db, src)?.id.resolver(db))
|
||||
},
|
||||
ast::SourceFile(it) => {
|
||||
let src = node.with_value(ModuleSource::SourceFile(it));
|
||||
Some(crate::Module::from_definition(db, src)?.id.resolver(db))
|
||||
},
|
||||
ast::StructDef(it) => {
|
||||
let src = node.with_value(it);
|
||||
Some(Struct::from_source(db, src)?.id.resolver(db))
|
||||
},
|
||||
ast::EnumDef(it) => {
|
||||
let src = node.with_value(it);
|
||||
Some(Enum::from_source(db, src)?.id.resolver(db))
|
||||
},
|
||||
ast::ImplBlock(it) => {
|
||||
let src = node.with_value(it);
|
||||
Some(ImplBlock::from_source(db, src)?.id.resolver(db))
|
||||
},
|
||||
ast::TraitDef(it) => {
|
||||
let src = node.with_value(it);
|
||||
Some(Trait::from_source(db, src)?.id.resolver(db))
|
||||
},
|
||||
_ => match node.value.kind() {
|
||||
FN_DEF | CONST_DEF | STATIC_DEF => {
|
||||
let def = def_with_body_from_child_node(db, node)?;
|
||||
let def = DefWithBodyId::from(def);
|
||||
Some(def.resolver(db))
|
||||
}
|
||||
// FIXME add missing cases
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn def_with_body_from_child_node(
|
||||
db: &impl HirDatabase,
|
||||
child: InFile<&SyntaxNode>,
|
||||
) -> Option<DefWithBody> {
|
||||
let _p = profile("def_with_body_from_child_node");
|
||||
child.cloned().ancestors_with_macros(db).find_map(|node| {
|
||||
let n = &node.value;
|
||||
match_ast! {
|
||||
match n {
|
||||
ast::FnDef(def) => { return Function::from_source(db, node.with_value(def)).map(DefWithBody::from); },
|
||||
ast::ConstDef(def) => { return Const::from_source(db, node.with_value(def)).map(DefWithBody::from); },
|
||||
ast::StaticDef(def) => { return Static::from_source(db, node.with_value(def)).map(DefWithBody::from); },
|
||||
_ => { None },
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn scope_for(
|
||||
scopes: &ExprScopes,
|
||||
source_map: &BodySourceMap,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue