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. --- .../ra_assists/src/handlers/add_explicit_type.rs | 5 ++- .../src/handlers/add_missing_impl_members.rs | 29 ++++++--------- crates/ra_assists/src/handlers/add_new.rs | 11 ++---- crates/ra_assists/src/handlers/auto_import.rs | 42 ++++++++-------------- crates/ra_assists/src/handlers/fill_match_arms.rs | 23 +++++------- .../src/handlers/inline_local_variable.rs | 3 +- 6 files changed, 39 insertions(+), 74 deletions(-) (limited to 'crates/ra_assists/src/handlers') diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 2cb9d2f48..a63ef48b1 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs @@ -51,14 +51,13 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option { } } // Infer type - let db = ctx.db; - let analyzer = ctx.source_analyzer(stmt.syntax(), None); - let ty = analyzer.type_of(db, &expr)?; + let ty = ctx.sema.type_of_expr(&expr)?; // Assist not applicable if the type is unknown if ty.contains_unknown() { return None; } + let db = ctx.db; ctx.add_assist( AssistId("add_explicit_type"), format!("Insert explicit type '{}'", ty.display(db)), diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index ab21388c8..4005014bd 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs @@ -1,4 +1,4 @@ -use hir::{HasSource, InFile}; +use hir::HasSource; use ra_syntax::{ ast::{self, edit, make, AstNode, NameOwner}, SmolStr, @@ -104,9 +104,7 @@ fn add_missing_impl_members_inner( let impl_node = ctx.find_node_at_offset::()?; let impl_item_list = impl_node.item_list()?; - let analyzer = ctx.source_analyzer(impl_node.syntax(), None); - - let trait_ = resolve_target_trait(ctx.db, &analyzer, &impl_node)?; + let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?; let def_name = |item: &ast::ImplItem| -> Option { match item { @@ -117,7 +115,7 @@ fn add_missing_impl_members_inner( .map(|it| it.text().clone()) }; - let missing_items = get_missing_impl_items(ctx.db, &analyzer, &impl_node) + let missing_items = get_missing_impl_items(&ctx.sema, &impl_node) .iter() .map(|i| match i { hir::AssocItem::Function(i) => ast::ImplItem::FnDef(i.source(ctx.db).value), @@ -138,23 +136,17 @@ fn add_missing_impl_members_inner( return None; } - let db = ctx.db; - let file_id = ctx.frange.file_id; - let trait_file_id = trait_.source(db).file_id; + let sema = ctx.sema; ctx.add_assist(AssistId(assist_id), label, |edit| { let n_existing_items = impl_item_list.impl_items().count(); - let module = hir::SourceAnalyzer::new( - db, - hir::InFile::new(file_id.into(), impl_node.syntax()), - None, - ) - .module(); - let ast_transform = QualifyPaths::new(db, module) - .or(SubstituteTypeParams::for_trait_impl(db, trait_, impl_node)); + let source_scope = sema.scope_for_def(trait_); + let target_scope = sema.scope(impl_item_list.syntax()); + let ast_transform = QualifyPaths::new(&target_scope, &source_scope, sema.db) + .or(SubstituteTypeParams::for_trait_impl(&source_scope, sema.db, trait_, impl_node)); let items = missing_items .into_iter() - .map(|it| ast_transform::apply(&*ast_transform, InFile::new(trait_file_id, it))) + .map(|it| ast_transform::apply(&*ast_transform, it)) .map(|it| match it { ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), _ => it, @@ -181,9 +173,10 @@ fn add_body(fn_def: ast::FnDef) -> ast::FnDef { #[cfg(test)] mod tests { - use super::*; use crate::helpers::{check_assist, check_assist_not_applicable}; + use super::*; + #[test] fn test_add_missing_impl_members() { check_assist( diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index dd070e8ec..166e907fb 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs @@ -1,5 +1,5 @@ use format_buf::format; -use hir::{Adt, InFile}; +use hir::Adt; use join_to_string::join; use ra_syntax::{ ast::{ @@ -133,16 +133,11 @@ fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option; impl S {}` // (we currently use the wrong type parameter) diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index c4aea2a06..edf0cf6d0 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs @@ -3,8 +3,8 @@ use crate::{ insert_use_statement, AssistId, }; use hir::{ - db::HirDatabase, AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, - SourceAnalyzer, Trait, Type, + AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, + Type, }; use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; use ra_prof::profile; @@ -78,14 +78,9 @@ impl AutoImportAssets { fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistCtx) -> Option { let syntax_under_caret = method_call.syntax().to_owned(); - let source_analyzer = ctx.source_analyzer(&syntax_under_caret, None); - let module_with_name_to_import = source_analyzer.module()?; + let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; Some(Self { - import_candidate: ImportCandidate::for_method_call( - &method_call, - &source_analyzer, - ctx.db, - )?, + import_candidate: ImportCandidate::for_method_call(&ctx.sema, &method_call)?, module_with_name_to_import, syntax_under_caret, }) @@ -97,14 +92,9 @@ impl AutoImportAssets { return None; } - let source_analyzer = ctx.source_analyzer(&syntax_under_caret, None); - let module_with_name_to_import = source_analyzer.module()?; + let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; Some(Self { - import_candidate: ImportCandidate::for_regular_path( - &path_under_caret, - &source_analyzer, - ctx.db, - )?, + import_candidate: ImportCandidate::for_regular_path(&ctx.sema, &path_under_caret)?, module_with_name_to_import, syntax_under_caret, }) @@ -229,25 +219,23 @@ enum ImportCandidate { impl ImportCandidate { fn for_method_call( + sema: &Semantics, method_call: &ast::MethodCallExpr, - source_analyzer: &SourceAnalyzer, - db: &impl HirDatabase, ) -> Option { - if source_analyzer.resolve_method_call(method_call).is_some() { + if sema.resolve_method_call(method_call).is_some() { return None; } Some(Self::TraitMethod( - source_analyzer.type_of(db, &method_call.expr()?)?, + sema.type_of_expr(&method_call.expr()?)?, method_call.name_ref()?.syntax().to_string(), )) } fn for_regular_path( + sema: &Semantics, path_under_caret: &ast::Path, - source_analyzer: &SourceAnalyzer, - db: &impl HirDatabase, ) -> Option { - if source_analyzer.resolve_path(db, path_under_caret).is_some() { + if sema.resolve_path(path_under_caret).is_some() { return None; } @@ -256,17 +244,15 @@ impl ImportCandidate { let qualifier_start = qualifier.syntax().descendants().find_map(ast::NameRef::cast)?; let qualifier_start_path = qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?; - if let Some(qualifier_start_resolution) = - source_analyzer.resolve_path(db, &qualifier_start_path) - { + if let Some(qualifier_start_resolution) = sema.resolve_path(&qualifier_start_path) { let qualifier_resolution = if qualifier_start_path == qualifier { qualifier_start_resolution } else { - source_analyzer.resolve_path(db, &qualifier)? + sema.resolve_path(&qualifier)? }; if let PathResolution::Def(ModuleDef::Adt(assoc_item_path)) = qualifier_resolution { Some(ImportCandidate::TraitAssocItem( - assoc_item_path.ty(db), + assoc_item_path.ty(sema.db), segment.syntax().to_string(), )) } else { diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index ae2437ed3..e5d8c639d 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs @@ -2,10 +2,11 @@ use std::iter; -use hir::{db::HirDatabase, Adt, HasSource}; +use hir::{db::HirDatabase, Adt, HasSource, Semantics}; use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner}; use crate::{Assist, AssistCtx, AssistId}; +use ra_ide_db::RootDatabase; // Assist: fill_match_arms // @@ -46,10 +47,9 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option { }; let expr = match_expr.expr()?; - let (enum_def, module) = { - let analyzer = ctx.source_analyzer(expr.syntax(), None); - (resolve_enum_def(ctx.db, &analyzer, &expr)?, analyzer.module()?) - }; + let enum_def = resolve_enum_def(&ctx.sema, &expr)?; + let module = ctx.sema.scope(expr.syntax()).module()?; + let variants = enum_def.variants(ctx.db); if variants.is_empty() { return None; @@ -81,18 +81,11 @@ fn is_trivial(arm: &ast::MatchArm) -> bool { } } -fn resolve_enum_def( - db: &impl HirDatabase, - analyzer: &hir::SourceAnalyzer, - expr: &ast::Expr, -) -> Option { - let expr_ty = analyzer.type_of(db, &expr)?; - - let result = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() { +fn resolve_enum_def(sema: &Semantics, expr: &ast::Expr) -> Option { + sema.type_of_expr(&expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() { Some(Adt::Enum(e)) => Some(e), _ => None, - }); - result + }) } fn build_pat( diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 91b588243..53a72309b 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs @@ -44,8 +44,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option { } else { let_stmt.syntax().text_range() }; - let analyzer = ctx.source_analyzer(bind_pat.syntax(), None); - let refs = analyzer.find_all_refs(&bind_pat); + let refs = ctx.sema.find_all_refs(&bind_pat); if refs.is_empty() { return None; }; -- cgit v1.2.3