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.rs462
1 files changed, 232 insertions, 230 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5ed374c79..eae73c2c4 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -1,59 +1,42 @@
1use std::{ 1use std::sync::Arc;
2 fmt,
3 sync::Arc,
4};
5 2
6use rayon::prelude::*; 3use salsa::Database;
7use salsa::{Database, ParallelDatabase};
8 4
9use hir::{ 5use hir::{
10 self, FnSignatureInfo, Problem, source_binder, 6 self, FnSignatureInfo, Problem, source_binder,
11}; 7};
12use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; 8use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
13use ra_editor::{self, FileSymbol, find_node_at_offset, LineIndex, LocalEdit, Severity}; 9use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity};
14use ra_syntax::{ 10use ra_syntax::{
15 algo::find_covering_node, 11 algo::{find_covering_node, visit::{visitor, Visitor}},
16 ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, 12 ast::{self, ArgListOwner, Expr, FnDef, NameOwner},
17 AstNode, SourceFileNode, 13 AstNode, SourceFileNode,
18 SyntaxKind::*, 14 SyntaxKind::*,
19 SyntaxNodeRef, TextRange, TextUnit, 15 SyntaxNode, SyntaxNodeRef, TextRange, TextUnit,
20}; 16};
21 17
22use crate::{ 18use crate::{
23 AnalysisChange, 19 AnalysisChange,
24 Cancelable, 20 Cancelable, NavigationTarget,
25 completion::{CompletionItem, completions},
26 CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, 21 CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit,
27 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, 22 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit,
28 symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase}, 23 symbol_index::{LibrarySymbolsQuery, FileSymbol},
29}; 24};
30 25
31#[derive(Debug, Default)] 26impl db::RootDatabase {
32pub(crate) struct AnalysisHostImpl { 27 pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
33 db: db::RootDatabase,
34}
35
36impl AnalysisHostImpl {
37 pub fn analysis(&self) -> AnalysisImpl {
38 AnalysisImpl {
39 db: self.db.snapshot(),
40 }
41 }
42 pub fn apply_change(&mut self, change: AnalysisChange) {
43 log::info!("apply_change {:?}", change); 28 log::info!("apply_change {:?}", change);
44 // self.gc_syntax_trees(); 29 // self.gc_syntax_trees();
45 if !change.new_roots.is_empty() { 30 if !change.new_roots.is_empty() {
46 let mut local_roots = Vec::clone(&self.db.local_roots()); 31 let mut local_roots = Vec::clone(&self.local_roots());
47 for (root_id, is_local) in change.new_roots { 32 for (root_id, is_local) in change.new_roots {
48 self.db 33 self.query_mut(ra_db::SourceRootQuery)
49 .query_mut(ra_db::SourceRootQuery)
50 .set(root_id, Default::default()); 34 .set(root_id, Default::default());
51 if is_local { 35 if is_local {
52 local_roots.push(root_id); 36 local_roots.push(root_id);
53 } 37 }
54 } 38 }
55 self.db 39 self.query_mut(ra_db::LocalRootsQuery)
56 .query_mut(ra_db::LocalRootsQuery)
57 .set((), Arc::new(local_roots)); 40 .set((), Arc::new(local_roots));
58 } 41 }
59 42
@@ -61,53 +44,44 @@ impl AnalysisHostImpl {
61 self.apply_root_change(root_id, root_change); 44 self.apply_root_change(root_id, root_change);
62 } 45 }
63 for (file_id, text) in change.files_changed { 46 for (file_id, text) in change.files_changed {
64 self.db.query_mut(ra_db::FileTextQuery).set(file_id, text) 47 self.query_mut(ra_db::FileTextQuery).set(file_id, text)
65 } 48 }
66 if !change.libraries_added.is_empty() { 49 if !change.libraries_added.is_empty() {
67 let mut libraries = Vec::clone(&self.db.library_roots()); 50 let mut libraries = Vec::clone(&self.library_roots());
68 for library in change.libraries_added { 51 for library in change.libraries_added {
69 libraries.push(library.root_id); 52 libraries.push(library.root_id);
70 self.db 53 self.query_mut(ra_db::SourceRootQuery)
71 .query_mut(ra_db::SourceRootQuery)
72 .set(library.root_id, Default::default()); 54 .set(library.root_id, Default::default());
73 self.db 55 self.query_mut(LibrarySymbolsQuery)
74 .query_mut(LibrarySymbolsQuery)
75 .set_constant(library.root_id, Arc::new(library.symbol_index)); 56 .set_constant(library.root_id, Arc::new(library.symbol_index));
76 self.apply_root_change(library.root_id, library.root_change); 57 self.apply_root_change(library.root_id, library.root_change);
77 } 58 }
78 self.db 59 self.query_mut(ra_db::LibraryRootsQuery)
79 .query_mut(ra_db::LibraryRootsQuery)
80 .set((), Arc::new(libraries)); 60 .set((), Arc::new(libraries));
81 } 61 }
82 if let Some(crate_graph) = change.crate_graph { 62 if let Some(crate_graph) = change.crate_graph {
83 self.db 63 self.query_mut(ra_db::CrateGraphQuery)
84 .query_mut(ra_db::CrateGraphQuery)
85 .set((), Arc::new(crate_graph)) 64 .set((), Arc::new(crate_graph))
86 } 65 }
87 } 66 }
88 67
89 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { 68 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
90 let mut source_root = SourceRoot::clone(&self.db.source_root(root_id)); 69 let mut source_root = SourceRoot::clone(&self.source_root(root_id));
91 for add_file in root_change.added { 70 for add_file in root_change.added {
92 self.db 71 self.query_mut(ra_db::FileTextQuery)
93 .query_mut(ra_db::FileTextQuery)
94 .set(add_file.file_id, add_file.text); 72 .set(add_file.file_id, add_file.text);
95 self.db 73 self.query_mut(ra_db::FileRelativePathQuery)
96 .query_mut(ra_db::FileRelativePathQuery)
97 .set(add_file.file_id, add_file.path.clone()); 74 .set(add_file.file_id, add_file.path.clone());
98 self.db 75 self.query_mut(ra_db::FileSourceRootQuery)
99 .query_mut(ra_db::FileSourceRootQuery)
100 .set(add_file.file_id, root_id); 76 .set(add_file.file_id, root_id);
101 source_root.files.insert(add_file.path, add_file.file_id); 77 source_root.files.insert(add_file.path, add_file.file_id);
102 } 78 }
103 for remove_file in root_change.removed { 79 for remove_file in root_change.removed {
104 self.db 80 self.query_mut(ra_db::FileTextQuery)
105 .query_mut(ra_db::FileTextQuery)
106 .set(remove_file.file_id, Default::default()); 81 .set(remove_file.file_id, Default::default());
107 source_root.files.remove(&remove_file.path); 82 source_root.files.remove(&remove_file.path);
108 } 83 }
109 self.db 84 self.query_mut(ra_db::SourceRootQuery)
110 .query_mut(ra_db::SourceRootQuery)
111 .set(root_id, Arc::new(source_root)); 85 .set(root_id, Arc::new(source_root));
112 } 86 }
113 87
@@ -116,142 +90,86 @@ impl AnalysisHostImpl {
116 /// syntax trees. However, if we actually do that, everything is recomputed 90 /// syntax trees. However, if we actually do that, everything is recomputed
117 /// for some reason. Needs investigation. 91 /// for some reason. Needs investigation.
118 fn gc_syntax_trees(&mut self) { 92 fn gc_syntax_trees(&mut self) {
119 self.db 93 self.query(ra_db::SourceFileQuery)
120 .query(ra_db::SourceFileQuery)
121 .sweep(salsa::SweepStrategy::default().discard_values()); 94 .sweep(salsa::SweepStrategy::default().discard_values());
122 self.db 95 self.query(hir::db::SourceFileItemsQuery)
123 .query(hir::db::SourceFileItemsQuery)
124 .sweep(salsa::SweepStrategy::default().discard_values()); 96 .sweep(salsa::SweepStrategy::default().discard_values());
125 self.db 97 self.query(hir::db::FileItemQuery)
126 .query(hir::db::FileItemQuery)
127 .sweep(salsa::SweepStrategy::default().discard_values()); 98 .sweep(salsa::SweepStrategy::default().discard_values());
128 } 99 }
129} 100}
130 101
131pub(crate) struct AnalysisImpl { 102impl db::RootDatabase {
132 pub(crate) db: salsa::Snapshot<db::RootDatabase>,
133}
134
135impl fmt::Debug for AnalysisImpl {
136 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
137 let db: &db::RootDatabase = &self.db;
138 fmt.debug_struct("AnalysisImpl").field("db", db).finish()
139 }
140}
141
142impl AnalysisImpl {
143 pub fn file_text(&self, file_id: FileId) -> Arc<String> {
144 self.db.file_text(file_id)
145 }
146 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
147 self.db.source_file(file_id)
148 }
149 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
150 self.db.file_lines(file_id)
151 }
152 pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> {
153 /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
154 struct Snap(salsa::Snapshot<db::RootDatabase>);
155 impl Clone for Snap {
156 fn clone(&self) -> Snap {
157 Snap(self.0.snapshot())
158 }
159 }
160
161 let buf: Vec<Arc<SymbolIndex>> = if query.libs {
162 let snap = Snap(self.db.snapshot());
163 self.db
164 .library_roots()
165 .par_iter()
166 .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
167 .collect()
168 } else {
169 let mut files = Vec::new();
170 for &root in self.db.local_roots().iter() {
171 let sr = self.db.source_root(root);
172 files.extend(sr.files.values().map(|&it| it))
173 }
174
175 let snap = Snap(self.db.snapshot());
176 files
177 .par_iter()
178 .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
179 .filter_map(|it| it.ok())
180 .collect()
181 };
182 Ok(query.search(&buf))
183 }
184 /// This returns `Vec` because a module may be included from several places. We 103 /// This returns `Vec` because a module may be included from several places. We
185 /// don't handle this case yet though, so the Vec has length at most one. 104 /// don't handle this case yet though, so the Vec has length at most one.
186 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 105 pub(crate) fn parent_module(
187 let descr = match source_binder::module_from_position(&*self.db, position)? { 106 &self,
107 position: FilePosition,
108 ) -> Cancelable<Vec<NavigationTarget>> {
109 let descr = match source_binder::module_from_position(self, position)? {
188 None => return Ok(Vec::new()), 110 None => return Ok(Vec::new()),
189 Some(it) => it, 111 Some(it) => it,
190 }; 112 };
191 let (file_id, decl) = match descr.parent_link_source(&*self.db) { 113 let (file_id, decl) = match descr.parent_link_source(self) {
192 None => return Ok(Vec::new()), 114 None => return Ok(Vec::new()),
193 Some(it) => it, 115 Some(it) => it,
194 }; 116 };
195 let decl = decl.borrowed(); 117 let decl = decl.borrowed();
196 let decl_name = decl.name().unwrap(); 118 let decl_name = decl.name().unwrap();
197 let sym = FileSymbol { 119 Ok(vec![NavigationTarget {
120 file_id,
198 name: decl_name.text(), 121 name: decl_name.text(),
199 node_range: decl_name.syntax().range(), 122 range: decl_name.syntax().range(),
200 kind: MODULE, 123 kind: MODULE,
201 }; 124 ptr: None,
202 Ok(vec![(file_id, sym)]) 125 }])
203 } 126 }
204 /// Returns `Vec` for the same reason as `parent_module` 127 /// Returns `Vec` for the same reason as `parent_module`
205 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 128 pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
206 let descr = match source_binder::module_from_file_id(&*self.db, file_id)? { 129 let descr = match source_binder::module_from_file_id(self, file_id)? {
207 None => return Ok(Vec::new()), 130 None => return Ok(Vec::new()),
208 Some(it) => it, 131 Some(it) => it,
209 }; 132 };
210 let root = descr.crate_root(); 133 let root = descr.crate_root();
211 let file_id = root.source().file_id(); 134 let file_id = root.file_id();
212 135
213 let crate_graph = self.db.crate_graph(); 136 let crate_graph = self.crate_graph();
214 let crate_id = crate_graph.crate_id_for_crate_root(file_id); 137 let crate_id = crate_graph.crate_id_for_crate_root(file_id);
215 Ok(crate_id.into_iter().collect()) 138 Ok(crate_id.into_iter().collect())
216 } 139 }
217 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 140 pub(crate) fn crate_root(&self, crate_id: CrateId) -> FileId {
218 self.db.crate_graph().crate_root(crate_id) 141 self.crate_graph().crate_root(crate_id)
219 } 142 }
220 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { 143 pub(crate) fn approximately_resolve_symbol(
221 let completions = completions(&self.db, position)?;
222 Ok(completions.map(|it| it.into()))
223 }
224 pub fn approximately_resolve_symbol(
225 &self, 144 &self,
226 position: FilePosition, 145 position: FilePosition,
227 ) -> Cancelable<Option<ReferenceResolution>> { 146 ) -> Cancelable<Option<ReferenceResolution>> {
228 let file = self.db.source_file(position.file_id); 147 let file = self.source_file(position.file_id);
229 let syntax = file.syntax(); 148 let syntax = file.syntax();
230 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 149 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
231 let mut rr = ReferenceResolution::new(name_ref.syntax().range()); 150 let mut rr = ReferenceResolution::new(name_ref.syntax().range());
232 if let Some(fn_descr) = source_binder::function_from_child_node( 151 if let Some(fn_descr) =
233 &*self.db, 152 source_binder::function_from_child_node(self, position.file_id, name_ref.syntax())?
234 position.file_id, 153 {
235 name_ref.syntax(), 154 let scope = fn_descr.scopes(self);
236 )? {
237 let scope = fn_descr.scopes(&*self.db);
238 // First try to resolve the symbol locally 155 // First try to resolve the symbol locally
239 if let Some(entry) = scope.resolve_local_name(name_ref) { 156 if let Some(entry) = scope.resolve_local_name(name_ref) {
240 rr.add_resolution( 157 rr.resolves_to.push(NavigationTarget {
241 position.file_id, 158 file_id: position.file_id,
242 FileSymbol { 159 name: entry.name().to_string().into(),
243 name: entry.name().to_string().into(), 160 range: entry.ptr().range(),
244 node_range: entry.ptr().range(), 161 kind: NAME,
245 kind: NAME, 162 ptr: None,
246 }, 163 });
247 );
248 return Ok(Some(rr)); 164 return Ok(Some(rr));
249 }; 165 };
250 } 166 }
251 // If that fails try the index based approach. 167 // If that fails try the index based approach.
252 for (file_id, symbol) in self.index_resolve(name_ref)? { 168 rr.resolves_to.extend(
253 rr.add_resolution(file_id, symbol); 169 self.index_resolve(name_ref)?
254 } 170 .into_iter()
171 .map(NavigationTarget::from_symbol),
172 );
255 return Ok(Some(rr)); 173 return Ok(Some(rr));
256 } 174 }
257 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { 175 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
@@ -259,19 +177,21 @@ impl AnalysisImpl {
259 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 177 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
260 if module.has_semi() { 178 if module.has_semi() {
261 if let Some(child_module) = 179 if let Some(child_module) =
262 source_binder::module_from_declaration(&*self.db, position.file_id, module)? 180 source_binder::module_from_declaration(self, position.file_id, module)?
263 { 181 {
264 let file_id = child_module.source().file_id(); 182 let file_id = child_module.file_id();
265 let name = match child_module.name() { 183 let name = match child_module.name() {
266 Some(name) => name.to_string().into(), 184 Some(name) => name.to_string().into(),
267 None => "".into(), 185 None => "".into(),
268 }; 186 };
269 let symbol = FileSymbol { 187 let symbol = NavigationTarget {
188 file_id,
270 name, 189 name,
271 node_range: TextRange::offset_len(0.into(), 0.into()), 190 range: TextRange::offset_len(0.into(), 0.into()),
272 kind: MODULE, 191 kind: MODULE,
192 ptr: None,
273 }; 193 };
274 rr.add_resolution(file_id, symbol); 194 rr.resolves_to.push(symbol);
275 return Ok(Some(rr)); 195 return Ok(Some(rr));
276 } 196 }
277 } 197 }
@@ -280,10 +200,13 @@ impl AnalysisImpl {
280 Ok(None) 200 Ok(None)
281 } 201 }
282 202
283 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 203 pub(crate) fn find_all_refs(
284 let file = self.db.source_file(position.file_id); 204 &self,
205 position: FilePosition,
206 ) -> Cancelable<Vec<(FileId, TextRange)>> {
207 let file = self.source_file(position.file_id);
285 // Find the binding associated with the offset 208 // Find the binding associated with the offset
286 let (binding, descr) = match find_binding(&self.db, &file, position)? { 209 let (binding, descr) = match find_binding(self, &file, position)? {
287 None => return Ok(Vec::new()), 210 None => return Ok(Vec::new()),
288 Some(it) => it, 211 Some(it) => it,
289 }; 212 };
@@ -295,7 +218,7 @@ impl AnalysisImpl {
295 .collect::<Vec<_>>(); 218 .collect::<Vec<_>>();
296 ret.extend( 219 ret.extend(
297 descr 220 descr
298 .scopes(&*self.db) 221 .scopes(self)
299 .find_all_refs(binding) 222 .find_all_refs(binding)
300 .into_iter() 223 .into_iter()
301 .map(|ref_desc| (position.file_id, ref_desc.range)), 224 .map(|ref_desc| (position.file_id, ref_desc.range)),
@@ -333,9 +256,8 @@ impl AnalysisImpl {
333 Ok(Some((binding, descr))) 256 Ok(Some((binding, descr)))
334 } 257 }
335 } 258 }
336 pub fn doc_text_for(&self, file_id: FileId, symbol: FileSymbol) -> Cancelable<Option<String>> { 259 pub(crate) fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> {
337 let file = self.db.source_file(file_id); 260 let result = match (nav.description(self), nav.docs(self)) {
338 let result = match (symbol.description(&file), symbol.docs(&file)) {
339 (Some(desc), Some(docs)) => { 261 (Some(desc), Some(docs)) => {
340 Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs) 262 Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs)
341 } 263 }
@@ -347,8 +269,8 @@ impl AnalysisImpl {
347 Ok(result) 269 Ok(result)
348 } 270 }
349 271
350 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 272 pub(crate) fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
351 let syntax = self.db.source_file(file_id); 273 let syntax = self.source_file(file_id);
352 274
353 let mut res = ra_editor::diagnostics(&syntax) 275 let mut res = ra_editor::diagnostics(&syntax)
354 .into_iter() 276 .into_iter()
@@ -359,9 +281,9 @@ impl AnalysisImpl {
359 fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)), 281 fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)),
360 }) 282 })
361 .collect::<Vec<_>>(); 283 .collect::<Vec<_>>();
362 if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? { 284 if let Some(m) = source_binder::module_from_file_id(self, file_id)? {
363 for (name_node, problem) in m.problems(&*self.db) { 285 for (name_node, problem) in m.problems(self) {
364 let source_root = self.db.file_source_root(file_id); 286 let source_root = self.file_source_root(file_id);
365 let diag = match problem { 287 let diag = match problem {
366 Problem::UnresolvedModule { candidate } => { 288 Problem::UnresolvedModule { candidate } => {
367 let create_file = FileSystemEdit::CreateFile { 289 let create_file = FileSystemEdit::CreateFile {
@@ -411,29 +333,19 @@ impl AnalysisImpl {
411 Ok(res) 333 Ok(res)
412 } 334 }
413 335
414 pub fn assists(&self, frange: FileRange) -> Vec<SourceChange> { 336 pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> {
415 let file = self.file_syntax(frange.file_id); 337 let file = self.source_file(frange.file_id);
416 let offset = frange.range.start(); 338 assists::assists(&file, frange.range)
417 let actions = vec![
418 ra_editor::flip_comma(&file, offset).map(|f| f()),
419 ra_editor::add_derive(&file, offset).map(|f| f()),
420 ra_editor::add_impl(&file, offset).map(|f| f()),
421 ra_editor::make_pub_crate(&file, offset).map(|f| f()),
422 ra_editor::introduce_variable(&file, frange.range).map(|f| f()),
423 ];
424 actions
425 .into_iter() 339 .into_iter()
426 .filter_map(|local_edit| { 340 .map(|local_edit| SourceChange::from_local_edit(frange.file_id, local_edit))
427 Some(SourceChange::from_local_edit(frange.file_id, local_edit?))
428 })
429 .collect() 341 .collect()
430 } 342 }
431 343
432 pub fn resolve_callable( 344 pub(crate) fn resolve_callable(
433 &self, 345 &self,
434 position: FilePosition, 346 position: FilePosition,
435 ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { 347 ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
436 let file = self.db.source_file(position.file_id); 348 let file = self.source_file(position.file_id);
437 let syntax = file.syntax(); 349 let syntax = file.syntax();
438 350
439 // Find the calling expression and it's NameRef 351 // Find the calling expression and it's NameRef
@@ -442,53 +354,55 @@ impl AnalysisImpl {
442 354
443 // Resolve the function's NameRef (NOTE: this isn't entirely accurate). 355 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
444 let file_symbols = self.index_resolve(name_ref)?; 356 let file_symbols = self.index_resolve(name_ref)?;
445 for (fn_file_id, fs) in file_symbols { 357 for symbol in file_symbols {
446 if fs.kind == FN_DEF { 358 if symbol.ptr.kind() == FN_DEF {
447 let fn_file = self.db.source_file(fn_file_id); 359 let fn_file = self.source_file(symbol.file_id);
448 if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { 360 let fn_def = symbol.ptr.resolve(&fn_file);
449 let descr = ctry!(source_binder::function_from_source( 361 let fn_def = ast::FnDef::cast(fn_def.borrowed()).unwrap();
450 &*self.db, fn_file_id, fn_def 362 let descr = ctry!(source_binder::function_from_source(
451 )?); 363 self,
452 if let Some(descriptor) = descr.signature_info(&*self.db) { 364 symbol.file_id,
453 // If we have a calling expression let's find which argument we are on 365 fn_def
454 let mut current_parameter = None; 366 )?);
455 367 if let Some(descriptor) = descr.signature_info(self) {
456 let num_params = descriptor.params.len(); 368 // If we have a calling expression let's find which argument we are on
457 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 369 let mut current_parameter = None;
458 370
459 if num_params == 1 { 371 let num_params = descriptor.params.len();
460 if !has_self { 372 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
461 current_parameter = Some(0); 373
462 } 374 if num_params == 1 {
463 } else if num_params > 1 { 375 if !has_self {
464 // Count how many parameters into the call we are. 376 current_parameter = Some(0);
465 // TODO: This is best effort for now and should be fixed at some point.
466 // It may be better to see where we are in the arg_list and then check
467 // where offset is in that list (or beyond).
468 // Revisit this after we get documentation comments in.
469 if let Some(ref arg_list) = calling_node.arg_list() {
470 let start = arg_list.syntax().range().start();
471
472 let range_search = TextRange::from_to(start, position.offset);
473 let mut commas: usize = arg_list
474 .syntax()
475 .text()
476 .slice(range_search)
477 .to_string()
478 .matches(',')
479 .count();
480
481 // If we have a method call eat the first param since it's just self.
482 if has_self {
483 commas += 1;
484 }
485
486 current_parameter = Some(commas);
487 }
488 } 377 }
378 } else if num_params > 1 {
379 // Count how many parameters into the call we are.
380 // TODO: This is best effort for now and should be fixed at some point.
381 // It may be better to see where we are in the arg_list and then check
382 // where offset is in that list (or beyond).
383 // Revisit this after we get documentation comments in.
384 if let Some(ref arg_list) = calling_node.arg_list() {
385 let start = arg_list.syntax().range().start();
386
387 let range_search = TextRange::from_to(start, position.offset);
388 let mut commas: usize = arg_list
389 .syntax()
390 .text()
391 .slice(range_search)
392 .to_string()
393 .matches(',')
394 .count();
395
396 // If we have a method call eat the first param since it's just self.
397 if has_self {
398 commas += 1;
399 }
489 400
490 return Ok(Some((descriptor, current_parameter))); 401 current_parameter = Some(commas);
402 }
491 } 403 }
404
405 return Ok(Some((descriptor, current_parameter)));
492 } 406 }
493 } 407 }
494 } 408 }
@@ -496,20 +410,20 @@ impl AnalysisImpl {
496 Ok(None) 410 Ok(None)
497 } 411 }
498 412
499 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { 413 pub(crate) fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> {
500 let file = self.db.source_file(frange.file_id); 414 let file = self.source_file(frange.file_id);
501 let syntax = file.syntax(); 415 let syntax = file.syntax();
502 let node = find_covering_node(syntax, frange.range); 416 let node = find_covering_node(syntax, frange.range);
503 let parent_fn = ctry!(node.ancestors().find_map(FnDef::cast)); 417 let parent_fn = ctry!(node.ancestors().find_map(FnDef::cast));
504 let function = ctry!(source_binder::function_from_source( 418 let function = ctry!(source_binder::function_from_source(
505 &*self.db, 419 self,
506 frange.file_id, 420 frange.file_id,
507 parent_fn 421 parent_fn
508 )?); 422 )?);
509 let infer = function.infer(&*self.db)?; 423 let infer = function.infer(self)?;
510 Ok(infer.type_of_node(node).map(|t| t.to_string())) 424 Ok(infer.type_of_node(node).map(|t| t.to_string()))
511 } 425 }
512 pub fn rename( 426 pub(crate) fn rename(
513 &self, 427 &self,
514 position: FilePosition, 428 position: FilePosition,
515 new_name: &str, 429 new_name: &str,
@@ -520,7 +434,7 @@ impl AnalysisImpl {
520 .map(|(file_id, text_range)| SourceFileEdit { 434 .map(|(file_id, text_range)| SourceFileEdit {
521 file_id: *file_id, 435 file_id: *file_id,
522 edit: { 436 edit: {
523 let mut builder = ra_text_edit::TextEditBuilder::new(); 437 let mut builder = ra_text_edit::TextEditBuilder::default();
524 builder.replace(*text_range, new_name.into()); 438 builder.replace(*text_range, new_name.into());
525 builder.finish() 439 builder.finish()
526 }, 440 },
@@ -528,12 +442,12 @@ impl AnalysisImpl {
528 .collect::<Vec<_>>(); 442 .collect::<Vec<_>>();
529 Ok(res) 443 Ok(res)
530 } 444 }
531 fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable<Vec<(FileId, FileSymbol)>> { 445 fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable<Vec<FileSymbol>> {
532 let name = name_ref.text(); 446 let name = name_ref.text();
533 let mut query = Query::new(name.to_string()); 447 let mut query = Query::new(name.to_string());
534 query.exact(); 448 query.exact();
535 query.limit(4); 449 query.limit(4);
536 self.world_symbols(query) 450 crate::symbol_index::world_symbols(self, query)
537 } 451 }
538} 452}
539 453
@@ -592,3 +506,91 @@ impl<'a> FnCallNode<'a> {
592 } 506 }
593 } 507 }
594} 508}
509
510impl NavigationTarget {
511 fn node(&self, db: &db::RootDatabase) -> Option<SyntaxNode> {
512 let source_file = db.source_file(self.file_id);
513 let source_file = source_file.syntax();
514 let node = source_file
515 .descendants()
516 .find(|node| node.kind() == self.kind && node.range() == self.range)?
517 .owned();
518 Some(node)
519 }
520
521 fn docs(&self, db: &db::RootDatabase) -> Option<String> {
522 let node = self.node(db)?;
523 let node = node.borrowed();
524 fn doc_comments<'a, N: ast::DocCommentsOwner<'a>>(node: N) -> Option<String> {
525 let comments = node.doc_comment_text();
526 if comments.is_empty() {
527 None
528 } else {
529 Some(comments)
530 }
531 }
532
533 visitor()
534 .visit(doc_comments::<ast::FnDef>)
535 .visit(doc_comments::<ast::StructDef>)
536 .visit(doc_comments::<ast::EnumDef>)
537 .visit(doc_comments::<ast::TraitDef>)
538 .visit(doc_comments::<ast::Module>)
539 .visit(doc_comments::<ast::TypeDef>)
540 .visit(doc_comments::<ast::ConstDef>)
541 .visit(doc_comments::<ast::StaticDef>)
542 .accept(node)?
543 }
544
545 /// Get a description of this node.
546 ///
547 /// e.g. `struct Name`, `enum Name`, `fn Name`
548 fn description(&self, db: &db::RootDatabase) -> Option<String> {
549 // TODO: After type inference is done, add type information to improve the output
550 let node = self.node(db)?;
551 let node = node.borrowed();
552 // TODO: Refactor to be have less repetition
553 visitor()
554 .visit(|node: ast::FnDef| {
555 let mut string = "fn ".to_string();
556 node.name()?.syntax().text().push_to(&mut string);
557 Some(string)
558 })
559 .visit(|node: ast::StructDef| {
560 let mut string = "struct ".to_string();
561 node.name()?.syntax().text().push_to(&mut string);
562 Some(string)
563 })
564 .visit(|node: ast::EnumDef| {
565 let mut string = "enum ".to_string();
566 node.name()?.syntax().text().push_to(&mut string);
567 Some(string)
568 })
569 .visit(|node: ast::TraitDef| {
570 let mut string = "trait ".to_string();
571 node.name()?.syntax().text().push_to(&mut string);
572 Some(string)
573 })
574 .visit(|node: ast::Module| {
575 let mut string = "mod ".to_string();
576 node.name()?.syntax().text().push_to(&mut string);
577 Some(string)
578 })
579 .visit(|node: ast::TypeDef| {
580 let mut string = "type ".to_string();
581 node.name()?.syntax().text().push_to(&mut string);
582 Some(string)
583 })
584 .visit(|node: ast::ConstDef| {
585 let mut string = "const ".to_string();
586 node.name()?.syntax().text().push_to(&mut string);
587 Some(string)
588 })
589 .visit(|node: ast::StaticDef| {
590 let mut string = "static ".to_string();
591 node.name()?.syntax().text().push_to(&mut string);
592 Some(string)
593 })
594 .accept(node)?
595 }
596}