From 10d66d63d716a10ba7a5a8d1b69c9066249caf69 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 10 Apr 2019 11:15:55 +0300 Subject: introduce SourceAnalyzer --- crates/ra_ide_api/src/completion/complete_dot.rs | 11 +- .../src/completion/complete_struct_literal.rs | 11 +- .../src/completion/completion_context.rs | 3 + crates/ra_ide_api/src/display/navigation_target.rs | 25 +++- crates/ra_ide_api/src/goto_definition.rs | 152 +++++++-------------- crates/ra_ide_api/src/hover.rs | 18 ++- 6 files changed, 81 insertions(+), 139 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index c093d5cfb..358057364 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -4,17 +4,10 @@ use crate::completion::{CompletionContext, Completions}; /// Complete dot accesses, i.e. fields or methods (currently only fields). pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { - let (function, receiver) = match (&ctx.function, ctx.dot_receiver) { - (Some(function), Some(receiver)) => (function, receiver), - _ => return, - }; - let infer_result = function.infer(ctx.db); - let source_map = function.body_source_map(ctx.db); - let expr = match source_map.node_expr(receiver) { - Some(expr) => expr, + let receiver_ty = match ctx.dot_receiver.and_then(|it| ctx.analyzer.type_of(ctx.db, it)) { + Some(it) => it, None => return, }; - let receiver_ty = infer_result[expr].clone(); if !ctx.is_call { complete_fields(acc, ctx, receiver_ty.clone()); } diff --git a/crates/ra_ide_api/src/completion/complete_struct_literal.rs b/crates/ra_ide_api/src/completion/complete_struct_literal.rs index f58bcd03e..48fbf67f7 100644 --- a/crates/ra_ide_api/src/completion/complete_struct_literal.rs +++ b/crates/ra_ide_api/src/completion/complete_struct_literal.rs @@ -4,17 +4,10 @@ use crate::completion::{CompletionContext, Completions}; /// Complete fields in fields literals. pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { - let (function, struct_lit) = match (&ctx.function, ctx.struct_lit_syntax) { - (Some(function), Some(struct_lit)) => (function, struct_lit), - _ => return, - }; - let infer_result = function.infer(ctx.db); - let source_map = function.body_source_map(ctx.db); - let expr = match source_map.node_expr(struct_lit.into()) { - Some(expr) => expr, + let ty = match ctx.struct_lit_syntax.and_then(|it| ctx.analyzer.type_of(ctx.db, it.into())) { + Some(it) => it, None => return, }; - let ty = infer_result[expr].clone(); let (adt, substs) = match ty.as_adt() { Some(res) => res, _ => return, diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 65dffa470..ce21fca9b 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -14,6 +14,7 @@ use crate::{db, FilePosition}; #[derive(Debug)] pub(crate) struct CompletionContext<'a> { pub(super) db: &'a db::RootDatabase, + pub(super) analyzer: hir::SourceAnalyser, pub(super) offset: TextUnit, pub(super) token: SyntaxToken<'a>, pub(super) resolver: Resolver, @@ -50,8 +51,10 @@ impl<'a> CompletionContext<'a> { let resolver = source_binder::resolver_for_position(db, position); let module = source_binder::module_from_position(db, position); let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?; + let analyzer = hir::SourceAnalyser::new(db, position.file_id, token.parent()); let mut ctx = CompletionContext { db, + analyzer, token, offset: position.offset, resolver, diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 3c518faf5..84645287d 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs @@ -1,11 +1,11 @@ use ra_db::{FileId, SourceDatabase}; use ra_syntax::{ - SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, TreeArc, + SyntaxNode, AstNode, SmolStr, TextRange, TreeArc, AstPtr, SyntaxKind::{self, NAME}, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, algo::visit::{visitor, Visitor}, }; -use hir::{ModuleSource, FieldSource, Name, ImplItem}; +use hir::{ModuleSource, FieldSource, ImplItem, Either}; use crate::{FileSymbol, db::RootDatabase}; @@ -74,15 +74,25 @@ impl NavigationTarget { } } - pub(crate) fn from_scope_entry( + pub(crate) fn from_pat( + db: &RootDatabase, file_id: FileId, - name: Name, - ptr: SyntaxNodePtr, + pat: Either, AstPtr>, ) -> NavigationTarget { + let file = db.parse(file_id); + let (name, full_range) = match pat { + Either::A(pat) => match pat.to_node(&file).kind() { + ast::PatKind::BindPat(pat) => { + return NavigationTarget::from_bind_pat(file_id, &pat) + } + _ => ("_".into(), pat.syntax_node_ptr().range()), + }, + Either::B(slf) => ("self".into(), slf.syntax_node_ptr().range()), + }; NavigationTarget { file_id, - name: name.to_string().into(), - full_range: ptr.range(), + name, + full_range, focus_range: None, kind: NAME, container_name: None, @@ -229,6 +239,7 @@ impl NavigationTarget { /// Allows `NavigationTarget` to be created from a `NameOwner` pub(crate) fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget { + //FIXME: use `_` instead of empty string let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); let focus_range = node.name().map(|it| it.syntax().range()); NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax()) diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 60c1f5085..7f93f50c4 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -5,7 +5,6 @@ use ra_syntax::{ SyntaxNode, }; use test_utils::tested_by; -use hir::Resolution; use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; @@ -48,127 +47,72 @@ pub(crate) fn reference_definition( ) -> ReferenceResult { use self::ReferenceResult::*; - let function = hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()); - - if let Some(function) = function { - // Check if it is a method - if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { - tested_by!(goto_definition_works_for_methods); - let infer_result = function.infer(db); - let source_map = function.body_source_map(db); - let expr = ast::Expr::cast(method_call.syntax()).unwrap(); - if let Some(func) = - source_map.node_expr(expr).and_then(|it| infer_result.method_resolution(it)) - { - return Exact(NavigationTarget::from_function(db, func)); - }; - } - // It could also be a field access - if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { - tested_by!(goto_definition_works_for_fields); - let infer_result = function.infer(db); - let source_map = function.body_source_map(db); - let expr = ast::Expr::cast(field_expr.syntax()).unwrap(); - if let Some(field) = - source_map.node_expr(expr).and_then(|it| infer_result.field_resolution(it)) - { - return Exact(NavigationTarget::from_field(db, field)); - }; - } + let analyzer = hir::SourceAnalyser::new(db, file_id, name_ref.syntax()); - // It could also be a named field - if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) { - tested_by!(goto_definition_works_for_named_fields); + // Special cases: - let infer_result = function.infer(db); - let source_map = function.body_source_map(db); + // Check if it is a method + if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { + tested_by!(goto_definition_works_for_methods); + if let Some(func) = analyzer.resolve_method_call(method_call) { + return Exact(NavigationTarget::from_function(db, func)); + } + } + // It could also be a field access + if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { + tested_by!(goto_definition_works_for_fields); + if let Some(field) = analyzer.resolve_field(field_expr) { + return Exact(NavigationTarget::from_field(db, field)); + }; + } - let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast); + // It could also be a named field + if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) { + tested_by!(goto_definition_works_for_named_fields); - if let Some(expr) = struct_lit.and_then(|lit| source_map.node_expr(lit.into())) { - let ty = infer_result[expr].clone(); - if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() { - let hir_path = hir::Path::from_name_ref(name_ref); - let hir_name = hir_path.as_ident().unwrap(); + let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast); - if let Some(field) = s.field(db, hir_name) { - return Exact(NavigationTarget::from_field(db, field)); - } + if let Some(ty) = struct_lit.and_then(|lit| analyzer.type_of(db, lit.into())) { + if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() { + let hir_path = hir::Path::from_name_ref(name_ref); + let hir_name = hir_path.as_ident().unwrap(); + + if let Some(field) = s.field(db, hir_name) { + return Exact(NavigationTarget::from_field(db, field)); } } } } - // Try name resolution - let resolver = hir::source_binder::resolver_for_node(db, file_id, name_ref.syntax()); - if let Some(path) = - name_ref.syntax().ancestors().find_map(ast::Path::cast).and_then(hir::Path::from_ast) - { - let resolved = resolver.resolve_path(db, &path); - match resolved.clone().take_types().or_else(|| resolved.take_values()) { - Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)), - Some(Resolution::LocalBinding(pat)) => { - let body = resolver.body().expect("no body for local binding"); - let source_map = body.owner().body_source_map(db); - let ptr = source_map.pat_syntax(pat).expect("pattern not found in syntax mapping"); - let name = - path.as_ident().cloned().expect("local binding from a multi-segment path"); - let ptr = ptr.either(|it| it.into(), |it| it.into()); - let nav = NavigationTarget::from_scope_entry(file_id, name, ptr); - return Exact(nav); - } - Some(Resolution::GenericParam(..)) => { - // FIXME: go to the generic param def - } - Some(Resolution::SelfType(impl_block)) => { - let ty = impl_block.target_ty(db); - - if let Some((def_id, _)) = ty.as_adt() { - return Exact(NavigationTarget::from_adt_def(db, def_id)); - } - } - None => { - // If we failed to resolve then check associated items - if let Some(function) = function { - // Resolve associated item for path expressions - if let Some(path_expr) = - name_ref.syntax().ancestors().find_map(ast::PathExpr::cast) - { - let infer_result = function.infer(db); - let source_map = function.body_source_map(db); - - if let Some(expr) = ast::Expr::cast(path_expr.syntax()) { - if let Some(res) = source_map - .node_expr(expr) - .and_then(|it| infer_result.assoc_resolutions_for_expr(it.into())) - { - return Exact(NavigationTarget::from_impl_item(db, res)); - } - } + // General case, a path or a local: + if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { + if let Some(resolved) = analyzer.resolve_path(db, path) { + match resolved { + hir::PathResolution::Def(def) => return Exact(NavigationTarget::from_def(db, def)), + hir::PathResolution::LocalBinding(pat) => { + if let Some(pat) = analyzer.pat_syntax(db, pat) { + let nav = NavigationTarget::from_pat(db, file_id, pat); + return Exact(nav); } + } + hir::PathResolution::GenericParam(..) => { + // FIXME: go to the generic param def + } + hir::PathResolution::SelfType(impl_block) => { + let ty = impl_block.target_ty(db); - // Resolve associated item for path patterns - if let Some(path_pat) = - name_ref.syntax().ancestors().find_map(ast::PathPat::cast) - { - let infer_result = function.infer(db); - let source_map = function.body_source_map(db); - - let pat: &ast::Pat = path_pat.into(); - - if let Some(res) = source_map - .node_pat(pat) - .and_then(|it| infer_result.assoc_resolutions_for_pat(it.into())) - { - return Exact(NavigationTarget::from_impl_item(db, res)); - } + if let Some((def_id, _)) = ty.as_adt() { + return Exact(NavigationTarget::from_adt_def(db, def_id)); } } + hir::PathResolution::AssocItem(assoc) => { + return Exact(NavigationTarget::from_impl_item(db, assoc)) + } } } } - // If that fails try the index based approach. + // Fallback index based approach: let navs = crate::symbol_index::index_resolve(db, name_ref) .into_iter() .map(NavigationTarget::from_symbol) diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 3a8c93b99..ec167a196 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -132,17 +132,15 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option { .ancestors() .take_while(|it| it.range() == leaf_node.range()) .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())?; - let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?; - let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?; - let infer = function.infer(db); - let source_map = function.body_source_map(db); - if let Some(expr) = ast::Expr::cast(node).and_then(|e| source_map.node_expr(e)) { - Some(infer[expr].display(db).to_string()) - } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| source_map.node_pat(p)) { - Some(infer[pat].display(db).to_string()) + let analyzer = hir::SourceAnalyser::new(db, frange.file_id, node); + let ty = if let Some(ty) = ast::Expr::cast(node).and_then(|e| analyzer.type_of(db, e)) { + ty + } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| analyzer.type_of_pat(db, p)) { + ty } else { - None - } + return None; + }; + Some(ty.display(db).to_string()) } #[cfg(test)] -- cgit v1.2.3 From 505acc973b3b865195d7d0aeb47c419c35f6bbbc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 15:34:13 +0300 Subject: Make call info to use real name resolution --- crates/ra_ide_api/src/call_info.rs | 37 ++++++++++++---------- .../src/completion/completion_context.rs | 6 ---- 2 files changed, 20 insertions(+), 23 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index dbb3853d0..d06876777 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -2,7 +2,6 @@ use test_utils::tested_by; use ra_db::SourceDatabase; use ra_syntax::{ AstNode, SyntaxNode, TextUnit, - SyntaxKind::FN_DEF, ast::{self, ArgListOwner}, algo::find_node_at_offset, }; @@ -18,19 +17,26 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { + //FIXME: apply subst + let (callable_def, _subst) = + analyser.type_of(db, expr.expr()?.into())?.as_callable()?; + match callable_def { + hir::CallableDef::Function(it) => it, + //FIXME: handle other callables + _ => return None, + } + } + FnCallNode::MethodCallExpr(expr) => analyser.resolve_method_call(expr)?, + }; let mut call_info = CallInfo::new(db, function); // If we have a calling expression let's find which argument we are on let num_params = call_info.parameters().len(); - let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); + let has_self = function.signature(db).has_self_param(); if num_params == 1 { if !has_self { @@ -142,7 +148,7 @@ mod tests { } #[test] - fn test_fn_signature_two_args_first() { + fn test_fn_signature_two_args_firstx() { let info = call_info( r#"fn foo(x: u32, y: u32) -> u32 {x + y} fn bar() { foo(<|>3, ); }"#, @@ -382,11 +388,9 @@ assert_eq!(6, my_crate::add_one(5)); fn test_fn_signature_with_docs_from_actix() { let info = call_info( r#" -pub trait WriteHandler -where - Self: Actor, - Self::Context: ActorContext, -{ +struct WriteHandler; + +impl WriteHandler { /// Method is called when writer emits error. /// /// If this method returns `ErrorAction::Continue` writer processing @@ -403,8 +407,7 @@ where } } -pub fn foo() { - WriteHandler r; +pub fn foo(mut r: WriteHandler<()>) { r.finished(<|>); } diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index ce21fca9b..ddcf46b4e 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -19,7 +19,6 @@ pub(crate) struct CompletionContext<'a> { pub(super) token: SyntaxToken<'a>, pub(super) resolver: Resolver, pub(super) module: Option, - pub(super) function: Option, pub(super) function_syntax: Option<&'a ast::FnDef>, pub(super) use_item_syntax: Option<&'a ast::UseItem>, pub(super) struct_lit_syntax: Option<&'a ast::StructLit>, @@ -59,7 +58,6 @@ impl<'a> CompletionContext<'a> { offset: position.offset, resolver, module, - function: None, function_syntax: None, use_item_syntax: None, struct_lit_syntax: None, @@ -150,10 +148,6 @@ impl<'a> CompletionContext<'a> { .ancestors() .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) .find_map(ast::FnDef::cast); - if let (Some(module), Some(fn_def)) = (self.module, self.function_syntax) { - let function = source_binder::function_from_module(self.db, module, fn_def); - self.function = Some(function); - } let parent = match name_ref.syntax().parent() { Some(it) => it, -- cgit v1.2.3 From 6c2ba945ed331f0ce95eddd5b2183aa6fdf0f94b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 15:35:38 +0300 Subject: reduce visibility --- crates/ra_ide_api/src/call_info.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index d06876777..1f1d05409 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -80,7 +80,7 @@ enum FnCallNode<'a> { } impl<'a> FnCallNode<'a> { - pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option> { + fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option> { if let Some(expr) = find_node_at_offset::(syntax, offset) { return Some(FnCallNode::CallExpr(expr)); } @@ -90,7 +90,7 @@ impl<'a> FnCallNode<'a> { None } - pub fn name_ref(&self) -> Option<&'a ast::NameRef> { + fn name_ref(&self) -> Option<&'a ast::NameRef> { match *self { FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()?.kind() { ast::ExprKind::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?, @@ -103,7 +103,7 @@ impl<'a> FnCallNode<'a> { } } - pub fn arg_list(&self) -> Option<&'a ast::ArgList> { + fn arg_list(&self) -> Option<&'a ast::ArgList> { match *self { FnCallNode::CallExpr(expr) => expr.arg_list(), FnCallNode::MethodCallExpr(expr) => expr.arg_list(), -- cgit v1.2.3 From b6809b6695f9c4cec82ff98d73f7ff24f96cbecf Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 15:51:02 +0300 Subject: rename --- crates/ra_ide_api/src/call_info.rs | 2 +- crates/ra_ide_api/src/completion/completion_context.rs | 4 ++-- crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/hover.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 1f1d05409..a6676cad5 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -17,7 +17,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { //FIXME: apply subst diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index ddcf46b4e..98cdccef7 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -14,7 +14,7 @@ use crate::{db, FilePosition}; #[derive(Debug)] pub(crate) struct CompletionContext<'a> { pub(super) db: &'a db::RootDatabase, - pub(super) analyzer: hir::SourceAnalyser, + pub(super) analyzer: hir::SourceAnalyzer, pub(super) offset: TextUnit, pub(super) token: SyntaxToken<'a>, pub(super) resolver: Resolver, @@ -50,7 +50,7 @@ impl<'a> CompletionContext<'a> { let resolver = source_binder::resolver_for_position(db, position); let module = source_binder::module_from_position(db, position); let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?; - let analyzer = hir::SourceAnalyser::new(db, position.file_id, token.parent()); + let analyzer = hir::SourceAnalyzer::new(db, position.file_id, token.parent()); let mut ctx = CompletionContext { db, analyzer, diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 7f93f50c4..1f1a8d126 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -47,7 +47,7 @@ pub(crate) fn reference_definition( ) -> ReferenceResult { use self::ReferenceResult::*; - let analyzer = hir::SourceAnalyser::new(db, file_id, name_ref.syntax()); + let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax()); // Special cases: diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index ec167a196..0cba5a665 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -132,7 +132,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option { .ancestors() .take_while(|it| it.range() == leaf_node.range()) .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())?; - let analyzer = hir::SourceAnalyser::new(db, frange.file_id, node); + let analyzer = hir::SourceAnalyzer::new(db, frange.file_id, node); let ty = if let Some(ty) = ast::Expr::cast(node).and_then(|e| analyzer.type_of(db, e)) { ty } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| analyzer.type_of_pat(db, p)) { -- cgit v1.2.3 From 07cc047b4ffe3049dfe95fc5cd59383336976e2d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 15:58:00 +0300 Subject: minimize the API --- crates/ra_ide_api/src/goto_definition.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 1f1a8d126..abcc682e7 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -90,10 +90,8 @@ pub(crate) fn reference_definition( match resolved { hir::PathResolution::Def(def) => return Exact(NavigationTarget::from_def(db, def)), hir::PathResolution::LocalBinding(pat) => { - if let Some(pat) = analyzer.pat_syntax(db, pat) { - let nav = NavigationTarget::from_pat(db, file_id, pat); - return Exact(nav); - } + let nav = NavigationTarget::from_pat(db, file_id, pat); + return Exact(nav); } hir::PathResolution::GenericParam(..) => { // FIXME: go to the generic param def -- cgit v1.2.3 From 5471c1ef4b2fda2fbaa63f7d8404abf04a3e9da4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 16:22:10 +0300 Subject: generalize SourceAnalyzer to handle all defs with bodies --- crates/ra_ide_api/src/completion/complete_dot.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 358057364..4a111aba5 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -305,6 +305,30 @@ mod tests { kind: Method, detail: "pub fn blah(&self)" } +]"### + ); + } + + #[test] + fn test_completion_works_in_consts() { + assert_debug_snapshot_matches!( + do_ref_completion( + r" + struct A { the_field: u32 } + const X: u32 = { + A { the_field: 92 }.<|> + }; + ", + ), + @r###"[ + CompletionItem { + label: "the_field", + source_range: [106; 106), + delete: [106; 106), + insert: "the_field", + kind: Field, + detail: "u32" + } ]"### ); } -- cgit v1.2.3 From ebb0c377f0ab99a0f5e6d0c776cb9b026b62b0e4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 16:49:35 +0300 Subject: remove resolver from CompletonContext --- crates/ra_ide_api/src/completion/complete_path.rs | 2 +- crates/ra_ide_api/src/completion/complete_pattern.rs | 2 +- crates/ra_ide_api/src/completion/complete_scope.rs | 2 +- crates/ra_ide_api/src/completion/completion_context.rs | 5 +---- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 7e47fa6bd..e9bdf5af2 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -9,7 +9,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { Some(path) => path.clone(), _ => return, }; - let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() { + let def = match ctx.analyzer.resolver().resolve_path(ctx.db, &path).take_types() { Some(Resolution::Def(def)) => def, _ => return, }; diff --git a/crates/ra_ide_api/src/completion/complete_pattern.rs b/crates/ra_ide_api/src/completion/complete_pattern.rs index 7abcd019b..abbb83518 100644 --- a/crates/ra_ide_api/src/completion/complete_pattern.rs +++ b/crates/ra_ide_api/src/completion/complete_pattern.rs @@ -7,7 +7,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { } // FIXME: ideally, we should look at the type we are matching against and // suggest variants + auto-imports - let names = ctx.resolver.all_names(ctx.db); + let names = ctx.analyzer.resolver().all_names(ctx.db); for (name, res) in names.into_iter() { let r = res.as_ref(); let def = match r.take_types().or(r.take_values()) { diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 9d82f2270..4c5d07ce5 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -4,7 +4,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.is_trivial_path { return; } - let names = ctx.resolver.all_names(ctx.db); + let names = ctx.analyzer.resolver().all_names(ctx.db); names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res)); } diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 98cdccef7..86b30e787 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -5,7 +5,7 @@ use ra_syntax::{ algo::{find_token_at_offset, find_covering_element, find_node_at_offset}, SyntaxKind::*, }; -use hir::{source_binder, Resolver}; +use hir::source_binder; use crate::{db, FilePosition}; @@ -17,7 +17,6 @@ pub(crate) struct CompletionContext<'a> { pub(super) analyzer: hir::SourceAnalyzer, pub(super) offset: TextUnit, pub(super) token: SyntaxToken<'a>, - pub(super) resolver: Resolver, pub(super) module: Option, pub(super) function_syntax: Option<&'a ast::FnDef>, pub(super) use_item_syntax: Option<&'a ast::UseItem>, @@ -47,7 +46,6 @@ impl<'a> CompletionContext<'a> { original_file: &'a SourceFile, position: FilePosition, ) -> Option> { - let resolver = source_binder::resolver_for_position(db, position); let module = source_binder::module_from_position(db, position); let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?; let analyzer = hir::SourceAnalyzer::new(db, position.file_id, token.parent()); @@ -56,7 +54,6 @@ impl<'a> CompletionContext<'a> { analyzer, token, offset: position.offset, - resolver, module, function_syntax: None, use_item_syntax: None, -- cgit v1.2.3 From 20013de2abb95bc024f55163b1a5044cfb52a873 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 11 Apr 2019 17:15:20 +0300 Subject: fix typo --- crates/ra_ide_api/src/call_info.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index a6676cad5..a8495ab01 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -17,19 +17,19 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { //FIXME: apply subst let (callable_def, _subst) = - analyser.type_of(db, expr.expr()?.into())?.as_callable()?; + analyzer.type_of(db, expr.expr()?.into())?.as_callable()?; match callable_def { hir::CallableDef::Function(it) => it, //FIXME: handle other callables _ => return None, } } - FnCallNode::MethodCallExpr(expr) => analyser.resolve_method_call(expr)?, + FnCallNode::MethodCallExpr(expr) => analyzer.resolve_method_call(expr)?, }; let mut call_info = CallInfo::new(db, function); -- cgit v1.2.3 From 0fd93bc14a2d0ce2edd682d26c18979c13f181c5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Apr 2019 00:44:47 +0300 Subject: use really correct resolver for expressions --- crates/ra_ide_api/src/call_info.rs | 2 +- crates/ra_ide_api/src/completion/completion_context.rs | 3 ++- crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/hover.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index a8495ab01..4413aec73 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -17,7 +17,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { //FIXME: apply subst diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 86b30e787..359f2cffa 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -48,7 +48,8 @@ impl<'a> CompletionContext<'a> { ) -> Option> { let module = source_binder::module_from_position(db, position); let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?; - let analyzer = hir::SourceAnalyzer::new(db, position.file_id, token.parent()); + let analyzer = + hir::SourceAnalyzer::new(db, position.file_id, token.parent(), Some(position.offset)); let mut ctx = CompletionContext { db, analyzer, diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index abcc682e7..517dffbca 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -47,7 +47,7 @@ pub(crate) fn reference_definition( ) -> ReferenceResult { use self::ReferenceResult::*; - let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax()); + let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); // Special cases: diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 0cba5a665..397b56786 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -132,7 +132,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option { .ancestors() .take_while(|it| it.range() == leaf_node.range()) .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())?; - let analyzer = hir::SourceAnalyzer::new(db, frange.file_id, node); + let analyzer = hir::SourceAnalyzer::new(db, frange.file_id, node, None); let ty = if let Some(ty) = ast::Expr::cast(node).and_then(|e| analyzer.type_of(db, e)) { ty } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| analyzer.type_of_pat(db, p)) { -- cgit v1.2.3 From 3aae223d938e5a36d997c45a0f86cfcabf83b570 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Apr 2019 09:31:03 +0300 Subject: hide some scopes --- crates/ra_ide_api/src/references.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 3e30e047c..ee2c1d0f0 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -61,12 +61,11 @@ pub(crate) fn find_all_refs( position: FilePosition, ) -> Option { let file = db.parse(position.file_id); - let (binding, descr) = find_binding(db, &file, position)?; + let (binding, analyzer) = find_binding(db, &file, position)?; let declaration = NavigationTarget::from_bind_pat(position.file_id, binding); - let references = descr - .scopes(db) - .find_all_refs(binding) + let references = analyzer + .find_all_refs(binding)? .into_iter() .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) .collect::>(); @@ -77,21 +76,18 @@ pub(crate) fn find_all_refs( db: &RootDatabase, source_file: &'a SourceFile, position: FilePosition, - ) -> Option<(&'a ast::BindPat, hir::Function)> { + ) -> Option<(&'a ast::BindPat, hir::SourceAnalyzer)> { let syntax = source_file.syntax(); if let Some(binding) = find_node_at_offset::(syntax, position.offset) { - let descr = - source_binder::function_from_child_node(db, position.file_id, binding.syntax())?; - return Some((binding, descr)); + let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); + return Some((binding, analyzer)); }; let name_ref = find_node_at_offset::(syntax, position.offset)?; - let descr = - source_binder::function_from_child_node(db, position.file_id, name_ref.syntax())?; - let scope = descr.scopes(db); - let resolved = scope.resolve_local_name(name_ref)?; + let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); + let resolved = analyzer.resolve_local_name(name_ref)?; if let Either::A(ptr) = resolved.ptr() { if let ast::PatKind::BindPat(binding) = ptr.to_node(source_file).kind() { - return Some((binding, descr)); + return Some((binding, analyzer)); } } None -- cgit v1.2.3 From cec67b2b652e1ee140635828ba2bca1fb95cd49a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Apr 2019 09:50:02 +0300 Subject: obsolete fixm --- crates/ra_ide_api/src/runnables.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs index 2395930f0..3969076a8 100644 --- a/crates/ra_ide_api/src/runnables.rs +++ b/crates/ra_ide_api/src/runnables.rs @@ -65,7 +65,6 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: &ast::Module) -> Opt let range = module.syntax().range(); let module = hir::source_binder::module_from_child_node(db, file_id, module.syntax())?; - // FIXME: thread cancellation instead of `.ok`ing let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); Some(Runnable { range, kind: RunnableKind::TestMod { path } }) } -- cgit v1.2.3 From f4a94e74bcd6c8f9275a57a775e64314af1878da Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Apr 2019 10:49:01 +0300 Subject: fold ScopeWithSyntax into SourceAnalyzer --- crates/ra_ide_api/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index ee2c1d0f0..9f655d83c 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -65,7 +65,7 @@ pub(crate) fn find_all_refs( let declaration = NavigationTarget::from_bind_pat(position.file_id, binding); let references = analyzer - .find_all_refs(binding)? + .find_all_refs(binding) .into_iter() .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) .collect::>(); -- cgit v1.2.3 From 62d01dd4dfc8feb52c006b84f9d1a1a7142cc060 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Apr 2019 11:00:15 +0300 Subject: hide resolver --- crates/ra_ide_api/src/completion/complete_path.rs | 2 +- crates/ra_ide_api/src/completion/complete_pattern.rs | 2 +- crates/ra_ide_api/src/completion/complete_scope.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index e9bdf5af2..bc03a7095 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -9,7 +9,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { Some(path) => path.clone(), _ => return, }; - let def = match ctx.analyzer.resolver().resolve_path(ctx.db, &path).take_types() { + let def = match ctx.analyzer.resolve_hir_path(ctx.db, &path).take_types() { Some(Resolution::Def(def)) => def, _ => return, }; diff --git a/crates/ra_ide_api/src/completion/complete_pattern.rs b/crates/ra_ide_api/src/completion/complete_pattern.rs index abbb83518..0ef248687 100644 --- a/crates/ra_ide_api/src/completion/complete_pattern.rs +++ b/crates/ra_ide_api/src/completion/complete_pattern.rs @@ -7,7 +7,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { } // FIXME: ideally, we should look at the type we are matching against and // suggest variants + auto-imports - let names = ctx.analyzer.resolver().all_names(ctx.db); + let names = ctx.analyzer.all_names(ctx.db); for (name, res) in names.into_iter() { let r = res.as_ref(); let def = match r.take_types().or(r.take_values()) { diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 4c5d07ce5..fd256fc3b 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -4,7 +4,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.is_trivial_path { return; } - let names = ctx.analyzer.resolver().all_names(ctx.db); + let names = ctx.analyzer.all_names(ctx.db); names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res)); } -- cgit v1.2.3