From c3a4c4429de83450654795534e64e878a774a088 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Feb 2020 18:35:10 +0100 Subject: Refactor primary IDE API This introduces the new type -- Semantics. Semantics maps SyntaxNodes to various semantic info, such as type, name resolution or macro expansions. To do so, Semantics maintains a HashMap which maps every node it saw to the file from which the node originated. This is enough to get all the necessary hir bits just from syntax. --- crates/ra_hir/src/source_analyzer.rs | 194 +++++++++++++---------------------- 1 file changed, 73 insertions(+), 121 deletions(-) (limited to 'crates/ra_hir/src/source_analyzer.rs') diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index efa3f8a79..bff1ecd14 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -14,29 +14,27 @@ use hir_def::{ BodySourceMap, }, expr::{ExprId, PatId}, - resolver::{self, resolver_for_scope, Resolver, TypeNs, ValueNs}, - AsMacroCall, DefWithBodyId, TraitId, + resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, + AsMacroCall, DefWithBodyId, }; -use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile, MacroCallId}; +use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; use ra_syntax::{ ast::{self, AstNode}, - AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, + AstPtr, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, }; -use rustc_hash::FxHashSet; use crate::{ - db::HirDatabase, Adt, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, Name, Path, - ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, + db::HirDatabase, Adt, Const, EnumVariant, Function, Local, MacroDef, Name, Path, 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. #[derive(Debug)] -pub struct SourceAnalyzer { +pub(crate) struct SourceAnalyzer { file_id: HirFileId, - resolver: Resolver, - body_owner: Option, + pub(crate) resolver: Resolver, body_source_map: Option>, infer: Option>, scopes: Option>, @@ -77,35 +75,7 @@ pub struct ReferenceDescriptor { pub name: String, } -#[derive(Debug)] -pub struct Expansion { - macro_call_id: MacroCallId, -} - -impl Expansion { - pub fn map_token_down( - &self, - db: &impl HirDatabase, - token: InFile<&SyntaxToken>, - ) -> Option> { - let exp_info = self.file_id().expansion_info(db)?; - exp_info.map_token_down(token) - } - - pub fn file_id(&self) -> HirFileId { - self.macro_call_id.as_file() - } -} - impl SourceAnalyzer { - pub fn new( - db: &impl HirDatabase, - node: InFile<&SyntaxNode>, - offset: Option, - ) -> SourceAnalyzer { - crate::source_binder::SourceBinder::new(db).analyze(node, offset) - } - pub(crate) fn new_for_body( db: &impl HirDatabase, def: DefWithBodyId, @@ -121,7 +91,6 @@ impl SourceAnalyzer { 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), @@ -135,7 +104,6 @@ impl SourceAnalyzer { ) -> SourceAnalyzer { SourceAnalyzer { resolver, - body_owner: None, body_source_map: None, infer: None, scopes: None, @@ -143,10 +111,6 @@ impl SourceAnalyzer { } } - pub fn module(&self) -> Option { - Some(crate::code_model::Module { id: self.resolver.module()? }) - } - fn expr_id(&self, expr: &ast::Expr) -> Option { let src = InFile { file_id: self.file_id, value: expr }; self.body_source_map.as_ref()?.node_expr(src) @@ -180,7 +144,7 @@ impl SourceAnalyzer { TraitEnvironment::lower(db, &self.resolver) } - pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { + pub(crate) fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) { self.body_source_map.as_ref()?.node_expr(expr.as_ref())? } else { @@ -192,24 +156,27 @@ impl SourceAnalyzer { Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } - pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option { + pub(crate) fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option { let pat_id = self.pat_id(pat)?; let ty = self.infer.as_ref()?[pat_id].clone(); let environment = self.trait_env(db); Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } - pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { + pub(crate) fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { let expr_id = self.expr_id(&call.clone().into())?; self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) } - pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option { + pub(crate) fn resolve_field(&self, field: &ast::FieldExpr) -> Option { let expr_id = self.expr_id(&field.clone().into())?; self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) } - pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option { + pub(crate) fn resolve_record_field( + &self, + field: &ast::RecordField, + ) -> Option { let expr_id = match field.expr() { Some(it) => self.expr_id(&it)?, None => { @@ -220,17 +187,23 @@ impl SourceAnalyzer { self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into()) } - pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option { + pub(crate) fn resolve_record_literal( + &self, + record_lit: &ast::RecordLit, + ) -> Option { let expr_id = self.expr_id(&record_lit.clone().into())?; self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into()) } - pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option { + pub(crate) fn resolve_record_pattern( + &self, + record_pat: &ast::RecordPat, + ) -> Option { let pat_id = self.pat_id(&record_pat.clone().into())?; self.infer.as_ref()?.variant_resolution_for_pat(pat_id).map(|it| it.into()) } - pub fn resolve_macro_call( + pub(crate) fn resolve_macro_call( &self, db: &impl HirDatabase, macro_call: InFile<&ast::MacroCall>, @@ -240,52 +213,11 @@ impl SourceAnalyzer { self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into()) } - pub fn resolve_hir_path( + pub(crate) fn resolve_path( &self, db: &impl HirDatabase, - path: &crate::Path, + path: &ast::Path, ) -> Option { - let types = - self.resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty { - TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), - TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), - TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { - PathResolution::Def(Adt::from(it).into()) - } - TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), - TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), - TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), - TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), - }); - let values = - self.resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| { - let res = match val { - ValueNs::LocalBinding(pat_id) => { - let var = Local { parent: self.body_owner?, pat_id }; - PathResolution::Local(var) - } - ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), - ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), - ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), - ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), - ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), - }; - Some(res) - }); - - let items = self - .resolver - .resolve_module_path_in_items(db, path.mod_path()) - .take_types() - .map(|it| PathResolution::Def(it.into())); - types.or(values).or(items).or_else(|| { - self.resolver - .resolve_path_as_macro(db, path.mod_path()) - .map(|def| PathResolution::Macro(def.into())) - }) - } - - pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option { if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { let expr_id = self.expr_id(&path_expr.into())?; if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { @@ -300,7 +232,7 @@ impl SourceAnalyzer { } // This must be a normal source file rather than macro file. let hir_path = crate::Path::from_ast(path.clone())?; - self.resolve_hir_path(db, &hir_path) + resolve_hir_path(db, &self.resolver, &hir_path) } fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option { @@ -315,25 +247,9 @@ impl SourceAnalyzer { }) } - pub fn process_all_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { - self.resolver.process_all_names(db, &mut |name, def| { - let def = match def { - resolver::ScopeDef::PerNs(it) => it.into(), - resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), - resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), - resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), - resolver::ScopeDef::Local(pat_id) => { - let parent = self.resolver.body_owner().unwrap().into(); - ScopeDef::Local(Local { parent, pat_id }) - } - }; - f(name, def) - }) - } - // FIXME: we only use this in `inline_local_variable` assist, ideally, we // should switch to general reference search infra there. - pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec { + pub(crate) fn find_all_refs(&self, pat: &ast::BindPat) -> Vec { let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); let ptr = Either::Left(AstPtr::new(&ast::Pat::from(pat.clone()))); fn_def @@ -351,19 +267,14 @@ impl SourceAnalyzer { .collect() } - /// Note: `FxHashSet` should be treated as an opaque type, passed into `Type - pub fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet { - self.resolver.traits_in_scope(db) - } - - pub fn expand( + pub(crate) fn expand( &self, db: &impl HirDatabase, macro_call: InFile<&ast::MacroCall>, - ) -> Option { + ) -> Option { let macro_call_id = macro_call.as_call_id(db, |path| self.resolver.resolve_path_as_macro(db, &path))?; - Some(Expansion { macro_call_id }) + Some(macro_call_id.as_file()) } } @@ -409,6 +320,47 @@ fn scope_for_offset( }) } +pub(crate) fn resolve_hir_path( + db: &impl HirDatabase, + resolver: &Resolver, + path: &crate::Path, +) -> Option { + let types = resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty { + TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), + TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), + TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()), + TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), + TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), + TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), + TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), + }); + let body_owner = resolver.body_owner(); + let values = resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| { + let res = match val { + ValueNs::LocalBinding(pat_id) => { + let var = Local { parent: body_owner?.into(), pat_id }; + PathResolution::Local(var) + } + ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), + ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), + ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), + ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), + ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), + }; + Some(res) + }); + + let items = resolver + .resolve_module_path_in_items(db, path.mod_path()) + .take_types() + .map(|it| PathResolution::Def(it.into())); + types.or(values).or(items).or_else(|| { + resolver + .resolve_path_as_macro(db, path.mod_path()) + .map(|def| PathResolution::Macro(def.into())) + }) +} + // XXX: during completion, cursor might be outside of any particular // expression. Try to figure out the correct scope... fn adjust( -- cgit v1.2.3