aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/call_info.rs119
-rw-r--r--crates/ra_analysis/src/imp.rs114
-rw-r--r--crates/ra_analysis/src/lib.rs15
3 files changed, 130 insertions, 118 deletions
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 @@
1use ra_db::{SyntaxDatabase, Cancelable};
2use ra_syntax::{
3 AstNode, SyntaxNode, TextUnit, TextRange,
4 SyntaxKind::FN_DEF,
5 ast::{self, ArgListOwner},
6};
7use ra_editor::find_node_at_offset;
8use hir::FnSignatureInfo;
9
10use crate::{FilePosition, db::RootDatabase};
11
12/// Computes parameter information for the given call expression.
13pub(crate) fn call_info(
14 db: &RootDatabase,
15 position: FilePosition,
16) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
17 let file = db.source_file(position.file_id);
18 let syntax = file.syntax();
19
20 // Find the calling expression and it's NameRef
21 let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset));
22 let name_ref = ctry!(calling_node.name_ref());
23
24 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
25 let file_symbols = db.index_resolve(name_ref)?;
26 for symbol in file_symbols {
27 if symbol.ptr.kind() == FN_DEF {
28 let fn_file = db.source_file(symbol.file_id);
29 let fn_def = symbol.ptr.resolve(&fn_file);
30 let fn_def = ast::FnDef::cast(&fn_def).unwrap();
31 let descr = ctry!(hir::source_binder::function_from_source(
32 db,
33 symbol.file_id,
34 fn_def
35 )?);
36 if let Some(descriptor) = descr.signature_info(db) {
37 // If we have a calling expression let's find which argument we are on
38 let mut current_parameter = None;
39
40 let num_params = descriptor.params.len();
41 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
42
43 if num_params == 1 {
44 if !has_self {
45 current_parameter = Some(0);
46 }
47 } else if num_params > 1 {
48 // Count how many parameters into the call we are.
49 // TODO: This is best effort for now and should be fixed at some point.
50 // It may be better to see where we are in the arg_list and then check
51 // where offset is in that list (or beyond).
52 // Revisit this after we get documentation comments in.
53 if let Some(ref arg_list) = calling_node.arg_list() {
54 let start = arg_list.syntax().range().start();
55
56 let range_search = TextRange::from_to(start, position.offset);
57 let mut commas: usize = arg_list
58 .syntax()
59 .text()
60 .slice(range_search)
61 .to_string()
62 .matches(',')
63 .count();
64
65 // If we have a method call eat the first param since it's just self.
66 if has_self {
67 commas += 1;
68 }
69
70 current_parameter = Some(commas);
71 }
72 }
73
74 return Ok(Some((descriptor, current_parameter)));
75 }
76 }
77 }
78
79 Ok(None)
80}
81
82enum FnCallNode<'a> {
83 CallExpr(&'a ast::CallExpr),
84 MethodCallExpr(&'a ast::MethodCallExpr),
85}
86
87impl<'a> FnCallNode<'a> {
88 pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option<FnCallNode<'a>> {
89 if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
90 return Some(FnCallNode::CallExpr(expr));
91 }
92 if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(syntax, offset) {
93 return Some(FnCallNode::MethodCallExpr(expr));
94 }
95 None
96 }
97
98 pub fn name_ref(&self) -> Option<&'a ast::NameRef> {
99 match *self {
100 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()?.kind() {
101 ast::ExprKind::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
102 _ => return None,
103 }),
104
105 FnCallNode::MethodCallExpr(call_expr) => call_expr
106 .syntax()
107 .children()
108 .filter_map(ast::NameRef::cast)
109 .nth(0),
110 }
111 }
112
113 pub fn arg_list(&self) -> Option<&'a ast::ArgList> {
114 match *self {
115 FnCallNode::CallExpr(expr) => expr.arg_list(),
116 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
117 }
118 }
119}
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;
3use salsa::Database; 3use salsa::Database;
4 4
5use hir::{ 5use hir::{
6 self, FnSignatureInfo, Problem, source_binder, 6 self, Problem, source_binder,
7}; 7};
8use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; 8use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
9use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity}; 9use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity};
10use ra_syntax::{ 10use ra_syntax::{
11 SyntaxNode, TextRange, TextUnit, AstNode, SourceFile, 11 TextRange, AstNode, SourceFile,
12 ast::{self, ArgListOwner, NameOwner}, 12 ast::{self, NameOwner},
13 SyntaxKind::*, 13 SyntaxKind::*,
14}; 14};
15 15
@@ -262,75 +262,6 @@ impl db::RootDatabase {
262 .collect() 262 .collect()
263 } 263 }
264 264
265 pub(crate) fn resolve_callable(
266 &self,
267 position: FilePosition,
268 ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
269 let file = self.source_file(position.file_id);
270 let syntax = file.syntax();
271
272 // Find the calling expression and it's NameRef
273 let calling_node = ctry!(FnCallNode::with_node(syntax, position.offset));
274 let name_ref = ctry!(calling_node.name_ref());
275
276 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
277 let file_symbols = self.index_resolve(name_ref)?;
278 for symbol in file_symbols {
279 if symbol.ptr.kind() == FN_DEF {
280 let fn_file = self.source_file(symbol.file_id);
281 let fn_def = symbol.ptr.resolve(&fn_file);
282 let fn_def = ast::FnDef::cast(&fn_def).unwrap();
283 let descr = ctry!(source_binder::function_from_source(
284 self,
285 symbol.file_id,
286 fn_def
287 )?);
288 if let Some(descriptor) = descr.signature_info(self) {
289 // If we have a calling expression let's find which argument we are on
290 let mut current_parameter = None;
291
292 let num_params = descriptor.params.len();
293 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
294
295 if num_params == 1 {
296 if !has_self {
297 current_parameter = Some(0);
298 }
299 } else if num_params > 1 {
300 // Count how many parameters into the call we are.
301 // TODO: This is best effort for now and should be fixed at some point.
302 // It may be better to see where we are in the arg_list and then check
303 // where offset is in that list (or beyond).
304 // Revisit this after we get documentation comments in.
305 if let Some(ref arg_list) = calling_node.arg_list() {
306 let start = arg_list.syntax().range().start();
307
308 let range_search = TextRange::from_to(start, position.offset);
309 let mut commas: usize = arg_list
310 .syntax()
311 .text()
312 .slice(range_search)
313 .to_string()
314 .matches(',')
315 .count();
316
317 // If we have a method call eat the first param since it's just self.
318 if has_self {
319 commas += 1;
320 }
321
322 current_parameter = Some(commas);
323 }
324 }
325
326 return Ok(Some((descriptor, current_parameter)));
327 }
328 }
329 }
330
331 Ok(None)
332 }
333
334 pub(crate) fn rename( 265 pub(crate) fn rename(
335 &self, 266 &self,
336 position: FilePosition, 267 position: FilePosition,
@@ -375,42 +306,3 @@ impl SourceChange {
375 } 306 }
376 } 307 }
377} 308}
378
379enum FnCallNode<'a> {
380 CallExpr(&'a ast::CallExpr),
381 MethodCallExpr(&'a ast::MethodCallExpr),
382}
383
384impl<'a> FnCallNode<'a> {
385 pub fn with_node(syntax: &'a SyntaxNode, offset: TextUnit) -> Option<FnCallNode<'a>> {
386 if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
387 return Some(FnCallNode::CallExpr(expr));
388 }
389 if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(syntax, offset) {
390 return Some(FnCallNode::MethodCallExpr(expr));
391 }
392 None
393 }
394
395 pub fn name_ref(&self) -> Option<&'a ast::NameRef> {
396 match *self {
397 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()?.kind() {
398 ast::ExprKind::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
399 _ => return None,
400 }),
401
402 FnCallNode::MethodCallExpr(call_expr) => call_expr
403 .syntax()
404 .children()
405 .filter_map(ast::NameRef::cast)
406 .nth(0),
407 }
408 }
409
410 pub fn arg_list(&self) -> Option<&'a ast::ArgList> {
411 match *self {
412 FnCallNode::CallExpr(expr) => expr.arg_list(),
413 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
414 }
415 }
416}
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;
22 22
23mod extend_selection; 23mod extend_selection;
24mod hover; 24mod hover;
25mod call_info;
25mod syntax_highlighting; 26mod syntax_highlighting;
26 27
27use std::{fmt, sync::Arc}; 28use std::{fmt, sync::Arc};
@@ -391,6 +392,13 @@ impl Analysis {
391 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { 392 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> {
392 hover::hover(&*self.db, position) 393 hover::hover(&*self.db, position)
393 } 394 }
395 /// Computes parameter information for the given call expression.
396 pub fn call_info(
397 &self,
398 position: FilePosition,
399 ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
400 call_info::call_info(&*self.db, position)
401 }
394 /// Returns a `mod name;` declaration which created the current module. 402 /// Returns a `mod name;` declaration which created the current module.
395 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { 403 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
396 self.db.parent_module(position) 404 self.db.parent_module(position)
@@ -425,13 +433,6 @@ impl Analysis {
425 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 433 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
426 self.db.diagnostics(file_id) 434 self.db.diagnostics(file_id)
427 } 435 }
428 /// Computes parameter information for the given call expression.
429 pub fn resolve_callable(
430 &self,
431 position: FilePosition,
432 ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
433 self.db.resolve_callable(position)
434 }
435 /// Computes the type of the expression at the given position. 436 /// Computes the type of the expression at the given position.
436 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { 437 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> {
437 hover::type_of(&*self.db, frange) 438 hover::type_of(&*self.db, frange)