diff options
-rw-r--r-- | crates/ra_analysis/src/call_info.rs | 119 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 114 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 15 |
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 @@ | |||
1 | use ra_db::{SyntaxDatabase, Cancelable}; | ||
2 | use ra_syntax::{ | ||
3 | AstNode, SyntaxNode, TextUnit, TextRange, | ||
4 | SyntaxKind::FN_DEF, | ||
5 | ast::{self, ArgListOwner}, | ||
6 | }; | ||
7 | use ra_editor::find_node_at_offset; | ||
8 | use hir::FnSignatureInfo; | ||
9 | |||
10 | use crate::{FilePosition, db::RootDatabase}; | ||
11 | |||
12 | /// Computes parameter information for the given call expression. | ||
13 | pub(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 | |||
82 | enum FnCallNode<'a> { | ||
83 | CallExpr(&'a ast::CallExpr), | ||
84 | MethodCallExpr(&'a ast::MethodCallExpr), | ||
85 | } | ||
86 | |||
87 | impl<'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; | |||
3 | use salsa::Database; | 3 | use salsa::Database; |
4 | 4 | ||
5 | use hir::{ | 5 | use hir::{ |
6 | self, FnSignatureInfo, Problem, source_binder, | 6 | self, Problem, source_binder, |
7 | }; | 7 | }; |
8 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; | 8 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; |
9 | use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity}; | 9 | use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity}; |
10 | use ra_syntax::{ | 10 | use 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 | |||
379 | enum FnCallNode<'a> { | ||
380 | CallExpr(&'a ast::CallExpr), | ||
381 | MethodCallExpr(&'a ast::MethodCallExpr), | ||
382 | } | ||
383 | |||
384 | impl<'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 | ||
23 | mod extend_selection; | 23 | mod extend_selection; |
24 | mod hover; | 24 | mod hover; |
25 | mod call_info; | ||
25 | mod syntax_highlighting; | 26 | mod syntax_highlighting; |
26 | 27 | ||
27 | use std::{fmt, sync::Arc}; | 28 | use 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) |