aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/imp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/imp.rs')
-rw-r--r--crates/ra_analysis/src/imp.rs169
1 files changed, 139 insertions, 30 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 47bc0032b..5efcaeca0 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -1,8 +1,8 @@
1use std::{ 1use std::{
2 sync::{ 2 sync::{
3 Arc, 3 Arc,
4 atomic::{AtomicBool, Ordering::SeqCst},
5 }, 4 },
5 hash::{Hash, Hasher},
6 fmt, 6 fmt,
7 collections::VecDeque, 7 collections::VecDeque,
8 iter, 8 iter,
@@ -12,24 +12,38 @@ use relative_path::RelativePath;
12use rustc_hash::FxHashSet; 12use rustc_hash::FxHashSet;
13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name}; 13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name};
14use ra_syntax::{ 14use ra_syntax::{
15 TextUnit, TextRange, SmolStr, File, AstNode, 15 TextUnit, TextRange, SmolStr, File, AstNode, SyntaxNodeRef,
16 SyntaxKind::*, 16 SyntaxKind::*,
17 ast::{self, NameOwner}, 17 ast::{self, NameOwner, ArgListOwner, Expr},
18}; 18};
19 19
20use { 20use crate::{
21 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, 21 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
22 JobToken, CrateGraph, CrateId, 22 JobToken, CrateGraph, CrateId,
23 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, 23 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
24 descriptors::{ModuleTreeDescriptor, Problem}, 24 descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem},
25}; 25};
26 26
27
28#[derive(Clone, Debug)] 27#[derive(Clone, Debug)]
29pub(crate) struct FileResolverImp { 28pub(crate) struct FileResolverImp {
30 inner: Arc<FileResolver> 29 inner: Arc<FileResolver>
31} 30}
32 31
32impl PartialEq for FileResolverImp {
33 fn eq(&self, other: &FileResolverImp) -> bool {
34 self.inner() == other.inner()
35 }
36}
37
38impl Eq for FileResolverImp {
39}
40
41impl Hash for FileResolverImp {
42 fn hash<H: Hasher>(&self, hasher: &mut H) {
43 self.inner().hash(hasher);
44 }
45}
46
33impl FileResolverImp { 47impl FileResolverImp {
34 pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp { 48 pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp {
35 FileResolverImp { inner } 49 FileResolverImp { inner }
@@ -40,6 +54,9 @@ impl FileResolverImp {
40 pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { 54 pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> {
41 self.inner.resolve(file_id, path) 55 self.inner.resolve(file_id, path)
42 } 56 }
57 fn inner(&self) -> *const FileResolver {
58 &*self.inner
59 }
43} 60}
44 61
45impl Default for FileResolverImp { 62impl Default for FileResolverImp {
@@ -60,29 +77,27 @@ impl Default for FileResolverImp {
60 77
61#[derive(Debug)] 78#[derive(Debug)]
62pub(crate) struct AnalysisHostImpl { 79pub(crate) struct AnalysisHostImpl {
63 data: Arc<WorldData> 80 data: WorldData
64} 81}
65 82
66impl AnalysisHostImpl { 83impl AnalysisHostImpl {
67 pub fn new() -> AnalysisHostImpl { 84 pub fn new() -> AnalysisHostImpl {
68 AnalysisHostImpl { 85 AnalysisHostImpl {
69 data: Arc::new(WorldData::default()), 86 data: WorldData::default(),
70 } 87 }
71 } 88 }
72 pub fn analysis(&self) -> AnalysisImpl { 89 pub fn analysis(&self) -> AnalysisImpl {
73 AnalysisImpl { 90 AnalysisImpl {
74 needs_reindex: AtomicBool::new(false),
75 data: self.data.clone(), 91 data: self.data.clone(),
76 } 92 }
77 } 93 }
78 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { 94 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
79 let data = self.data_mut(); 95 self.data_mut()
80 data.root = Arc::new(data.root.apply_changes(changes, None)); 96 .root.apply_changes(changes, None);
81 } 97 }
82 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { 98 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) {
83 let data = self.data_mut(); 99 self.data_mut()
84 data.file_resolver = resolver.clone(); 100 .root.apply_changes(&mut iter::empty(), Some(resolver));
85 data.root = Arc::new(data.root.apply_changes(&mut iter::empty(), Some(resolver)));
86 } 101 }
87 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 102 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
88 let mut visited = FxHashSet::default(); 103 let mut visited = FxHashSet::default();
@@ -97,34 +112,24 @@ impl AnalysisHostImpl {
97 self.data_mut().libs.push(Arc::new(root)); 112 self.data_mut().libs.push(Arc::new(root));
98 } 113 }
99 fn data_mut(&mut self) -> &mut WorldData { 114 fn data_mut(&mut self) -> &mut WorldData {
100 Arc::make_mut(&mut self.data) 115 &mut self.data
101 } 116 }
102} 117}
103 118
104pub(crate) struct AnalysisImpl { 119pub(crate) struct AnalysisImpl {
105 needs_reindex: AtomicBool, 120 data: WorldData,
106 data: Arc<WorldData>,
107} 121}
108 122
109impl fmt::Debug for AnalysisImpl { 123impl fmt::Debug for AnalysisImpl {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 (&*self.data).fmt(f) 125 self.data.fmt(f)
112 }
113}
114
115impl Clone for AnalysisImpl {
116 fn clone(&self) -> AnalysisImpl {
117 AnalysisImpl {
118 needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
119 data: Arc::clone(&self.data),
120 }
121 } 126 }
122} 127}
123 128
124impl AnalysisImpl { 129impl AnalysisImpl {
125 fn root(&self, file_id: FileId) -> &SourceRoot { 130 fn root(&self, file_id: FileId) -> &SourceRoot {
126 if self.data.root.contains(file_id) { 131 if self.data.root.contains(file_id) {
127 return &*self.data.root; 132 return &self.data.root;
128 } 133 }
129 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() 134 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
130 } 135 }
@@ -306,6 +311,68 @@ impl AnalysisImpl {
306 .collect() 311 .collect()
307 } 312 }
308 313
314 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken)
315 -> Option<(FnDescriptor, Option<usize>)> {
316
317 let root = self.root(file_id);
318 let file = root.syntax(file_id);
319 let syntax = file.syntax();
320
321 // Find the calling expression and it's NameRef
322 let calling_node = FnCallNode::with_node(syntax, offset)?;
323 let name_ref = calling_node.name_ref()?;
324
325 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
326 let file_symbols = self.index_resolve(name_ref, token);
327 for (_, fs) in file_symbols {
328 if fs.kind == FN_DEF {
329 if let Some(fn_def) = find_node_at_offset(syntax, fs.node_range.start()) {
330 if let Some(descriptor) = FnDescriptor::new(fn_def) {
331 // If we have a calling expression let's find which argument we are on
332 let mut current_parameter = None;
333
334 let num_params = descriptor.params.len();
335 let has_self = fn_def.param_list()
336 .and_then(|l| l.self_param())
337 .is_some();
338
339 if num_params == 1 {
340 if !has_self {
341 current_parameter = Some(1);
342 }
343 } else if num_params > 1 {
344 // Count how many parameters into the call we are.
345 // TODO: This is best effort for now and should be fixed at some point.
346 // It may be better to see where we are in the arg_list and then check
347 // where offset is in that list (or beyond).
348 // Revisit this after we get documentation comments in.
349 if let Some(ref arg_list) = calling_node.arg_list() {
350 let start = arg_list.syntax().range().start();
351
352 let range_search = TextRange::from_to(start, offset);
353 let mut commas: usize = arg_list.syntax().text()
354 .slice(range_search).to_string()
355 .matches(",")
356 .count();
357
358 // If we have a method call eat the first param since it's just self.
359 if has_self {
360 commas = commas + 1;
361 }
362
363 current_parameter = Some(commas);
364 }
365 }
366
367 return Some((descriptor, current_parameter));
368 }
369 }
370 }
371 }
372
373 None
374 }
375
309 fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 376 fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
310 let name = name_ref.text(); 377 let name = name_ref.text();
311 let mut query = Query::new(name.to_string()); 378 let mut query = Query::new(name.to_string());
@@ -325,9 +392,8 @@ impl AnalysisImpl {
325 392
326#[derive(Default, Clone, Debug)] 393#[derive(Default, Clone, Debug)]
327struct WorldData { 394struct WorldData {
328 file_resolver: FileResolverImp,
329 crate_graph: CrateGraph, 395 crate_graph: CrateGraph,
330 root: Arc<WritableSourceRoot>, 396 root: WritableSourceRoot,
331 libs: Vec<Arc<ReadonlySourceRoot>>, 397 libs: Vec<Arc<ReadonlySourceRoot>>,
332} 398}
333 399
@@ -355,3 +421,46 @@ impl CrateGraph {
355 Some(crate_id) 421 Some(crate_id)
356 } 422 }
357} 423}
424
425enum FnCallNode<'a> {
426 CallExpr(ast::CallExpr<'a>),
427 MethodCallExpr(ast::MethodCallExpr<'a>)
428}
429
430impl<'a> FnCallNode<'a> {
431 pub fn with_node(syntax: SyntaxNodeRef, offset: TextUnit) -> Option<FnCallNode> {
432 if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
433 return Some(FnCallNode::CallExpr(expr));
434 }
435 if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(syntax, offset) {
436 return Some(FnCallNode::MethodCallExpr(expr));
437 }
438 None
439 }
440
441 pub fn name_ref(&self) -> Option<ast::NameRef> {
442 match *self {
443 FnCallNode::CallExpr(call_expr) => {
444 Some(match call_expr.expr()? {
445 Expr::PathExpr(path_expr) => {
446 path_expr.path()?.segment()?.name_ref()?
447 },
448 _ => return None
449 })
450 },
451
452 FnCallNode::MethodCallExpr(call_expr) => {
453 call_expr.syntax().children()
454 .filter_map(ast::NameRef::cast)
455 .nth(0)
456 }
457 }
458 }
459
460 pub fn arg_list(&self) -> Option<ast::ArgList> {
461 match *self {
462 FnCallNode::CallExpr(expr) => expr.arg_list(),
463 FnCallNode::MethodCallExpr(expr) => expr.arg_list()
464 }
465 }
466}