From e6a4383bb475b866b67df6bb83ecbdf823d73667 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 8 Jan 2019 18:16:26 +0300 Subject: move call-info to a separate file --- crates/ra_analysis/src/call_info.rs | 119 ++++++++++++++++++++++++++++++++++++ crates/ra_analysis/src/imp.rs | 114 +--------------------------------- crates/ra_analysis/src/lib.rs | 15 ++--- 3 files changed, 130 insertions(+), 118 deletions(-) create mode 100644 crates/ra_analysis/src/call_info.rs (limited to 'crates/ra_analysis') diff --git a/crates/ra_analysis/src/call_info.rs b/crates/ra_analysis/src/call_info.rs new file mode 100644 index 000000000..a31a54ef6 --- /dev/null +++ b/crates/ra_analysis/src/call_info.rs @@ -0,0 +1,119 @@ +use ra_db::{SyntaxDatabase, Cancelable}; +use ra_syntax::{ + AstNode, SyntaxNode, TextUnit, TextRange, + SyntaxKind::FN_DEF, + ast::{self, ArgListOwner}, +}; +use ra_editor::find_node_at_offset; +use hir::FnSignatureInfo; + +use crate::{FilePosition, db::RootDatabase}; + +/// Computes parameter information for the given call expression. +pub(crate) fn call_info( + db: &RootDatabase, + position: FilePosition, +) -> Cancelable)>> { + let file = db.source_file(position.file_id); + let syntax = file.syntax(); + + // Find the calling expression and it's NameRef + let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset)); + let name_ref = ctry!(calling_node.name_ref()); + + // Resolve the function's NameRef (NOTE: this isn't entirely accurate). + let file_symbols = db.index_resolve(name_ref)?; + for symbol in file_symbols { + if symbol.ptr.kind() == FN_DEF { + let fn_file = db.source_file(symbol.file_id); + let fn_def = symbol.ptr.resolve(&fn_file); + let fn_def = ast::FnDef::cast(&fn_def).unwrap(); + let descr = ctry!(hir::source_binder::function_from_source( + db, + symbol.file_id, + fn_def + )?); + if let Some(descriptor) = descr.signature_info(db) { + // If we have a calling expression let's find which argument we are on + let mut current_parameter = None; + + let num_params = descriptor.params.len(); + let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); + + if num_params == 1 { + if !has_self { + current_parameter = Some(0); + } + } else if num_params > 1 { + // Count how many parameters into the call we are. + // TODO: This is best effort for now and should be fixed at some point. + // It may be better to see where we are in the arg_list and then check + // where offset is in that list (or beyond). + // Revisit this after we get documentation comments in. + if let Some(ref arg_list) = calling_node.arg_list() { + let start = arg_list.syntax().range().start(); + + let range_search = TextRange::from_to(start, position.offset); + let mut commas: usize = arg_list + .syntax() + .text() + .slice(range_search) + .to_string() + .matches(',') + .count(); + + // If we have a method call eat the first param since it's just self. + if has_self { + commas += 1; + } + + current_parameter = Some(commas); + } + } + + return Ok(Some((descriptor, current_parameter))); + } + } + } + + Ok(None) +} + +enum FnCallNode<'a> { + CallExpr(&'a ast::CallExpr), + MethodCallExpr(&'a ast::MethodCallExpr), +} + +impl<'a> FnCallNode<'a> { + pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option> { + if let Some(expr) = find_node_at_offset::(syntax, offset) { + return Some(FnCallNode::CallExpr(expr)); + } + if let Some(expr) = find_node_at_offset::(syntax, offset) { + return Some(FnCallNode::MethodCallExpr(expr)); + } + None + } + + pub 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()?, + _ => return None, + }), + + FnCallNode::MethodCallExpr(call_expr) => call_expr + .syntax() + .children() + .filter_map(ast::NameRef::cast) + .nth(0), + } + } + + pub fn arg_list(&self) -> Option<&'a ast::ArgList> { + match *self { + FnCallNode::CallExpr(expr) => expr.arg_list(), + FnCallNode::MethodCallExpr(expr) => expr.arg_list(), + } + } +} diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 98554dd4c..b3f75fdbe 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -3,13 +3,13 @@ use std::sync::Arc; use salsa::Database; use hir::{ - self, FnSignatureInfo, Problem, source_binder, + self, Problem, source_binder, }; use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity}; use ra_syntax::{ - SyntaxNode, TextRange, TextUnit, AstNode, SourceFile, - ast::{self, ArgListOwner, NameOwner}, + TextRange, AstNode, SourceFile, + ast::{self, NameOwner}, SyntaxKind::*, }; @@ -262,75 +262,6 @@ impl db::RootDatabase { .collect() } - pub(crate) fn resolve_callable( - &self, - position: FilePosition, - ) -> Cancelable)>> { - let file = self.source_file(position.file_id); - let syntax = file.syntax(); - - // Find the calling expression and it's NameRef - let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset)); - let name_ref = ctry!(calling_node.name_ref()); - - // Resolve the function's NameRef (NOTE: this isn't entirely accurate). - let file_symbols = self.index_resolve(name_ref)?; - for symbol in file_symbols { - if symbol.ptr.kind() == FN_DEF { - let fn_file = self.source_file(symbol.file_id); - let fn_def = symbol.ptr.resolve(&fn_file); - let fn_def = ast::FnDef::cast(&fn_def).unwrap(); - let descr = ctry!(source_binder::function_from_source( - self, - symbol.file_id, - fn_def - )?); - if let Some(descriptor) = descr.signature_info(self) { - // If we have a calling expression let's find which argument we are on - let mut current_parameter = None; - - let num_params = descriptor.params.len(); - let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); - - if num_params == 1 { - if !has_self { - current_parameter = Some(0); - } - } else if num_params > 1 { - // Count how many parameters into the call we are. - // TODO: This is best effort for now and should be fixed at some point. - // It may be better to see where we are in the arg_list and then check - // where offset is in that list (or beyond). - // Revisit this after we get documentation comments in. - if let Some(ref arg_list) = calling_node.arg_list() { - let start = arg_list.syntax().range().start(); - - let range_search = TextRange::from_to(start, position.offset); - let mut commas: usize = arg_list - .syntax() - .text() - .slice(range_search) - .to_string() - .matches(',') - .count(); - - // If we have a method call eat the first param since it's just self. - if has_self { - commas += 1; - } - - current_parameter = Some(commas); - } - } - - return Ok(Some((descriptor, current_parameter))); - } - } - } - - Ok(None) - } - pub(crate) fn rename( &self, position: FilePosition, @@ -375,42 +306,3 @@ impl SourceChange { } } } - -enum FnCallNode<'a> { - CallExpr(&'a ast::CallExpr), - MethodCallExpr(&'a ast::MethodCallExpr), -} - -impl<'a> FnCallNode<'a> { - pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option> { - if let Some(expr) = find_node_at_offset::(syntax, offset) { - return Some(FnCallNode::CallExpr(expr)); - } - if let Some(expr) = find_node_at_offset::(syntax, offset) { - return Some(FnCallNode::MethodCallExpr(expr)); - } - None - } - - pub 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()?, - _ => return None, - }), - - FnCallNode::MethodCallExpr(call_expr) => call_expr - .syntax() - .children() - .filter_map(ast::NameRef::cast) - .nth(0), - } - } - - pub fn arg_list(&self) -> Option<&'a ast::ArgList> { - match *self { - FnCallNode::CallExpr(expr) => expr.arg_list(), - FnCallNode::MethodCallExpr(expr) => expr.arg_list(), - } - } -} diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index ec400ffe2..9192f66e8 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -22,6 +22,7 @@ mod symbol_index; mod extend_selection; mod hover; +mod call_info; mod syntax_highlighting; use std::{fmt, sync::Arc}; @@ -391,6 +392,13 @@ impl Analysis { pub fn hover(&self, position: FilePosition) -> Cancelable>> { hover::hover(&*self.db, position) } + /// Computes parameter information for the given call expression. + pub fn call_info( + &self, + position: FilePosition, + ) -> Cancelable)>> { + call_info::call_info(&*self.db, position) + } /// Returns a `mod name;` declaration which created the current module. pub fn parent_module(&self, position: FilePosition) -> Cancelable> { self.db.parent_module(position) @@ -425,13 +433,6 @@ impl Analysis { pub fn diagnostics(&self, file_id: FileId) -> Cancelable> { self.db.diagnostics(file_id) } - /// Computes parameter information for the given call expression. - pub fn resolve_callable( - &self, - position: FilePosition, - ) -> Cancelable)>> { - self.db.resolve_callable(position) - } /// Computes the type of the expression at the given position. pub fn type_of(&self, frange: FileRange) -> Cancelable> { hover::type_of(&*self.db, frange) -- cgit v1.2.3