move call-info to a separate file

This commit is contained in:
Aleksey Kladov 2019-01-08 18:16:26 +03:00
parent 2f07976cb5
commit e6a4383bb4
3 changed files with 130 additions and 118 deletions

View file

@ -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<Option<(FnSignatureInfo, Option<usize>)>> {
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<FnCallNode<'a>> {
if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
return Some(FnCallNode::CallExpr(expr));
}
if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(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(),
}
}
}

View file

@ -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<Option<(FnSignatureInfo, Option<usize>)>> {
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<FnCallNode<'a>> {
if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
return Some(FnCallNode::CallExpr(expr));
}
if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(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(),
}
}
}

View file

@ -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<Option<RangeInfo<String>>> {
hover::hover(&*self.db, position)
}
/// Computes parameter information for the given call expression.
pub fn call_info(
&self,
position: FilePosition,
) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
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<Vec<NavigationTarget>> {
self.db.parent_module(position)
@ -425,13 +433,6 @@ impl Analysis {
pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
self.db.diagnostics(file_id)
}
/// Computes parameter information for the given call expression.
pub fn resolve_callable(
&self,
position: FilePosition,
) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
self.db.resolve_callable(position)
}
/// Computes the type of the expression at the given position.
pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> {
hover::type_of(&*self.db, frange)