aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/completion.rs31
-rw-r--r--crates/ra_analysis/src/imp.rs78
-rw-r--r--crates/ra_analysis/src/lib.rs64
-rw-r--r--crates/ra_analysis/src/mock_analysis.rs9
-rw-r--r--crates/ra_analysis/tests/tests.rs26
-rw-r--r--crates/ra_lsp_server/src/conv.rs13
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs76
7 files changed, 132 insertions, 165 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs
index 766df1d96..7c3476e5c 100644
--- a/crates/ra_analysis/src/completion.rs
+++ b/crates/ra_analysis/src/completion.rs
@@ -14,7 +14,7 @@ use crate::{
14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, 14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource},
15 descriptors::DescriptorDatabase, 15 descriptors::DescriptorDatabase,
16 input::FilesDatabase, 16 input::FilesDatabase,
17 Cancelable, FileId, 17 Cancelable, FilePosition,
18}; 18};
19 19
20#[derive(Debug)] 20#[derive(Debug)]
@@ -29,21 +29,21 @@ pub struct CompletionItem {
29 29
30pub(crate) fn resolve_based_completion( 30pub(crate) fn resolve_based_completion(
31 db: &db::RootDatabase, 31 db: &db::RootDatabase,
32 file_id: FileId, 32 position: FilePosition,
33 offset: TextUnit,
34) -> Cancelable<Option<Vec<CompletionItem>>> { 33) -> Cancelable<Option<Vec<CompletionItem>>> {
35 let source_root_id = db.file_source_root(file_id); 34 let source_root_id = db.file_source_root(position.file_id);
36 let file = db.file_syntax(file_id); 35 let file = db.file_syntax(position.file_id);
37 let module_tree = db.module_tree(source_root_id)?; 36 let module_tree = db.module_tree(source_root_id)?;
38 let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) { 37 let module_id = match module_tree.any_module_for_source(ModuleSource::File(position.file_id)) {
39 None => return Ok(None), 38 None => return Ok(None),
40 Some(it) => it, 39 Some(it) => it,
41 }; 40 };
42 let file = { 41 let file = {
43 let edit = AtomEdit::insert(offset, "intellijRulezz".to_string()); 42 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string());
44 file.reparse(&edit) 43 file.reparse(&edit)
45 }; 44 };
46 let target_module_id = match find_target_module(&module_tree, module_id, &file, offset) { 45 let target_module_id = match find_target_module(&module_tree, module_id, &file, position.offset)
46 {
47 None => return Ok(None), 47 None => return Ok(None),
48 Some(it) => it, 48 Some(it) => it,
49 }; 49 };
@@ -99,18 +99,17 @@ fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
99 99
100pub(crate) fn scope_completion( 100pub(crate) fn scope_completion(
101 db: &db::RootDatabase, 101 db: &db::RootDatabase,
102 file_id: FileId, 102 position: FilePosition,
103 offset: TextUnit,
104) -> Option<Vec<CompletionItem>> { 103) -> Option<Vec<CompletionItem>> {
105 let original_file = db.file_syntax(file_id); 104 let original_file = db.file_syntax(position.file_id);
106 // Insert a fake ident to get a valid parse tree 105 // Insert a fake ident to get a valid parse tree
107 let file = { 106 let file = {
108 let edit = AtomEdit::insert(offset, "intellijRulezz".to_string()); 107 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string());
109 original_file.reparse(&edit) 108 original_file.reparse(&edit)
110 }; 109 };
111 let mut has_completions = false; 110 let mut has_completions = false;
112 let mut res = Vec::new(); 111 let mut res = Vec::new();
113 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), offset) { 112 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
114 has_completions = true; 113 has_completions = true;
115 complete_name_ref(&file, name_ref, &mut res); 114 complete_name_ref(&file, name_ref, &mut res);
116 // special case, `trait T { fn foo(i_am_a_name_ref) {} }` 115 // special case, `trait T { fn foo(i_am_a_name_ref) {} }`
@@ -129,7 +128,7 @@ pub(crate) fn scope_completion(
129 _ => (), 128 _ => (),
130 } 129 }
131 } 130 }
132 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), offset) { 131 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) {
133 if is_node::<ast::Param>(name.syntax()) { 132 if is_node::<ast::Param>(name.syntax()) {
134 has_completions = true; 133 has_completions = true;
135 param_completions(name.syntax(), &mut res); 134 param_completions(name.syntax(), &mut res);
@@ -383,7 +382,7 @@ mod tests {
383 382
384 fn check_scope_completion(code: &str, expected_completions: &str) { 383 fn check_scope_completion(code: &str, expected_completions: &str) {
385 let (analysis, position) = single_file_with_position(code); 384 let (analysis, position) = single_file_with_position(code);
386 let completions = scope_completion(&analysis.imp.db, position.file_id, position.offset) 385 let completions = scope_completion(&analysis.imp.db, position)
387 .unwrap() 386 .unwrap()
388 .into_iter() 387 .into_iter()
389 .filter(|c| c.snippet.is_none()) 388 .filter(|c| c.snippet.is_none())
@@ -393,7 +392,7 @@ mod tests {
393 392
394 fn check_snippet_completion(code: &str, expected_completions: &str) { 393 fn check_snippet_completion(code: &str, expected_completions: &str) {
395 let (analysis, position) = single_file_with_position(code); 394 let (analysis, position) = single_file_with_position(code);
396 let completions = scope_completion(&analysis.imp.db, position.file_id, position.offset) 395 let completions = scope_completion(&analysis.imp.db, position)
397 .unwrap() 396 .unwrap()
398 .into_iter() 397 .into_iter()
399 .filter(|c| c.snippet.is_some()) 398 .filter(|c| c.snippet.is_some())
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 704648b59..f2482559f 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -27,7 +27,7 @@ use crate::{
27 input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, 27 input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
28 symbol_index::SymbolIndex, 28 symbol_index::SymbolIndex,
29 AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver, 29 AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver,
30 FileSystemEdit, Position, Query, SourceChange, SourceFileEdit, 30 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileEdit,
31}; 31};
32 32
33#[derive(Clone, Debug)] 33#[derive(Clone, Debug)]
@@ -220,16 +220,13 @@ impl AnalysisImpl {
220 let source_root = self.db.file_source_root(file_id); 220 let source_root = self.db.file_source_root(file_id);
221 self.db.module_tree(source_root) 221 self.db.module_tree(source_root)
222 } 222 }
223 pub fn parent_module( 223 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
224 &self, 224 let module_tree = self.module_tree(position.file_id)?;
225 file_id: FileId, 225 let file = self.db.file_syntax(position.file_id);
226 offset: TextUnit, 226 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
227 ) -> Cancelable<Vec<(FileId, FileSymbol)>> { 227 {
228 let module_tree = self.module_tree(file_id)?; 228 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
229 let file = self.db.file_syntax(file_id); 229 _ => ModuleSource::File(position.file_id),
230 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), offset) {
231 Some(m) if !m.has_semi() => ModuleSource::new_inline(file_id, m),
232 _ => ModuleSource::File(file_id),
233 }; 230 };
234 231
235 let res = module_tree 232 let res = module_tree
@@ -269,18 +266,14 @@ impl AnalysisImpl {
269 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 266 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
270 self.db.crate_graph().crate_roots[&crate_id] 267 self.db.crate_graph().crate_roots[&crate_id]
271 } 268 }
272 pub fn completions( 269 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
273 &self,
274 file_id: FileId,
275 offset: TextUnit,
276 ) -> Cancelable<Option<Vec<CompletionItem>>> {
277 let mut res = Vec::new(); 270 let mut res = Vec::new();
278 let mut has_completions = false; 271 let mut has_completions = false;
279 if let Some(scope_based) = scope_completion(&self.db, file_id, offset) { 272 if let Some(scope_based) = scope_completion(&self.db, position) {
280 res.extend(scope_based); 273 res.extend(scope_based);
281 has_completions = true; 274 has_completions = true;
282 } 275 }
283 if let Some(scope_based) = resolve_based_completion(&self.db, file_id, offset)? { 276 if let Some(scope_based) = resolve_based_completion(&self.db, position)? {
284 res.extend(scope_based); 277 res.extend(scope_based);
285 has_completions = true; 278 has_completions = true;
286 } 279 }
@@ -289,18 +282,19 @@ impl AnalysisImpl {
289 } 282 }
290 pub fn approximately_resolve_symbol( 283 pub fn approximately_resolve_symbol(
291 &self, 284 &self,
292 file_id: FileId, 285 position: FilePosition,
293 offset: TextUnit,
294 ) -> Cancelable<Vec<(FileId, FileSymbol)>> { 286 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
295 let module_tree = self.module_tree(file_id)?; 287 let module_tree = self.module_tree(position.file_id)?;
296 let file = self.db.file_syntax(file_id); 288 let file = self.db.file_syntax(position.file_id);
297 let syntax = file.syntax(); 289 let syntax = file.syntax();
298 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { 290 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
299 // First try to resolve the symbol locally 291 // First try to resolve the symbol locally
300 return if let Some((name, range)) = resolve_local_name(&self.db, file_id, name_ref) { 292 return if let Some((name, range)) =
293 resolve_local_name(&self.db, position.file_id, name_ref)
294 {
301 let mut vec = vec![]; 295 let mut vec = vec![];
302 vec.push(( 296 vec.push((
303 file_id, 297 position.file_id,
304 FileSymbol { 298 FileSymbol {
305 name, 299 name,
306 node_range: range, 300 node_range: range,
@@ -313,10 +307,10 @@ impl AnalysisImpl {
313 self.index_resolve(name_ref) 307 self.index_resolve(name_ref)
314 }; 308 };
315 } 309 }
316 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { 310 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
317 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 311 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
318 if module.has_semi() { 312 if module.has_semi() {
319 let file_ids = self.resolve_module(&*module_tree, file_id, module); 313 let file_ids = self.resolve_module(&*module_tree, position.file_id, module);
320 314
321 let res = file_ids 315 let res = file_ids
322 .into_iter() 316 .into_iter()
@@ -341,16 +335,17 @@ impl AnalysisImpl {
341 Ok(vec![]) 335 Ok(vec![])
342 } 336 }
343 337
344 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> { 338 pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
345 let file = self.db.file_syntax(file_id); 339 let file = self.db.file_syntax(position.file_id);
346 let syntax = file.syntax(); 340 let syntax = file.syntax();
347 341
348 // Find the binding associated with the offset 342 // Find the binding associated with the offset
349 let maybe_binding = find_node_at_offset::<ast::BindPat>(syntax, offset).or_else(|| { 343 let maybe_binding =
350 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, offset)?; 344 find_node_at_offset::<ast::BindPat>(syntax, position.offset).or_else(|| {
351 let resolved = resolve_local_name(&self.db, file_id, name_ref)?; 345 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
352 find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end()) 346 let resolved = resolve_local_name(&self.db, position.file_id, name_ref)?;
353 }); 347 find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end())
348 });
354 349
355 let binding = match maybe_binding { 350 let binding = match maybe_binding {
356 None => return Vec::new(), 351 None => return Vec::new(),
@@ -359,11 +354,11 @@ impl AnalysisImpl {
359 354
360 let decl = DeclarationDescriptor::new(binding); 355 let decl = DeclarationDescriptor::new(binding);
361 356
362 let mut ret = vec![(file_id, decl.range)]; 357 let mut ret = vec![(position.file_id, decl.range)];
363 ret.extend( 358 ret.extend(
364 decl.find_all_refs() 359 decl.find_all_refs()
365 .into_iter() 360 .into_iter()
366 .map(|ref_desc| (file_id, ref_desc.range)), 361 .map(|ref_desc| (position.file_id, ref_desc.range)),
367 ); 362 );
368 363
369 ret 364 ret
@@ -457,14 +452,13 @@ impl AnalysisImpl {
457 452
458 pub fn resolve_callable( 453 pub fn resolve_callable(
459 &self, 454 &self,
460 file_id: FileId, 455 position: FilePosition,
461 offset: TextUnit,
462 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { 456 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> {
463 let file = self.db.file_syntax(file_id); 457 let file = self.db.file_syntax(position.file_id);
464 let syntax = file.syntax(); 458 let syntax = file.syntax();
465 459
466 // Find the calling expression and it's NameRef 460 // Find the calling expression and it's NameRef
467 let calling_node = match FnCallNode::with_node(syntax, offset) { 461 let calling_node = match FnCallNode::with_node(syntax, position.offset) {
468 Some(node) => node, 462 Some(node) => node,
469 None => return Ok(None), 463 None => return Ok(None),
470 }; 464 };
@@ -499,7 +493,7 @@ impl AnalysisImpl {
499 if let Some(ref arg_list) = calling_node.arg_list() { 493 if let Some(ref arg_list) = calling_node.arg_list() {
500 let start = arg_list.syntax().range().start(); 494 let start = arg_list.syntax().range().start();
501 495
502 let range_search = TextRange::from_to(start, offset); 496 let range_search = TextRange::from_to(start, position.offset);
503 let mut commas: usize = arg_list 497 let mut commas: usize = arg_list
504 .syntax() 498 .syntax()
505 .text() 499 .text()
@@ -568,7 +562,7 @@ impl SourceChange {
568 file_system_edits: vec![], 562 file_system_edits: vec![],
569 cursor_position: edit 563 cursor_position: edit
570 .cursor_position 564 .cursor_position
571 .map(|offset| Position { offset, file_id }), 565 .map(|offset| FilePosition { offset, file_id }),
572 } 566 }
573 } 567 }
574} 568}
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index fee382151..0ea9ebee7 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -119,18 +119,18 @@ impl AnalysisHost {
119 } 119 }
120} 120}
121 121
122#[derive(Clone, Copy, Debug)]
123pub struct FilePosition {
124 pub file_id: FileId,
125 pub offset: TextUnit,
126}
127
122#[derive(Debug)] 128#[derive(Debug)]
123pub struct SourceChange { 129pub struct SourceChange {
124 pub label: String, 130 pub label: String,
125 pub source_file_edits: Vec<SourceFileEdit>, 131 pub source_file_edits: Vec<SourceFileEdit>,
126 pub file_system_edits: Vec<FileSystemEdit>, 132 pub file_system_edits: Vec<FileSystemEdit>,
127 pub cursor_position: Option<Position>, 133 pub cursor_position: Option<FilePosition>,
128}
129
130#[derive(Debug)]
131pub struct Position {
132 pub file_id: FileId,
133 pub offset: TextUnit,
134} 134}
135 135
136#[derive(Debug)] 136#[derive(Debug)]
@@ -224,18 +224,18 @@ impl Analysis {
224 let file = self.imp.file_syntax(file_id); 224 let file = self.imp.file_syntax(file_id);
225 SourceChange::from_local_edit(file_id, "join lines", ra_editor::join_lines(&file, range)) 225 SourceChange::from_local_edit(file_id, "join lines", ra_editor::join_lines(&file, range))
226 } 226 }
227 pub fn on_enter(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { 227 pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> {
228 let file = self.imp.file_syntax(file_id); 228 let file = self.imp.file_syntax(position.file_id);
229 let edit = ra_editor::on_enter(&file, offset)?; 229 let edit = ra_editor::on_enter(&file, position.offset)?;
230 let res = SourceChange::from_local_edit(file_id, "on enter", edit); 230 let res = SourceChange::from_local_edit(position.file_id, "on enter", edit);
231 Some(res) 231 Some(res)
232 } 232 }
233 pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { 233 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> {
234 let file = self.imp.file_syntax(file_id); 234 let file = self.imp.file_syntax(position.file_id);
235 Some(SourceChange::from_local_edit( 235 Some(SourceChange::from_local_edit(
236 file_id, 236 position.file_id,
237 "add semicolon", 237 "add semicolon",
238 ra_editor::on_eq_typed(&file, offset)?, 238 ra_editor::on_eq_typed(&file, position.offset)?,
239 )) 239 ))
240 } 240 }
241 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { 241 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
@@ -251,24 +251,15 @@ impl Analysis {
251 } 251 }
252 pub fn approximately_resolve_symbol( 252 pub fn approximately_resolve_symbol(
253 &self, 253 &self,
254 file_id: FileId, 254 position: FilePosition,
255 offset: TextUnit,
256 ) -> Cancelable<Vec<(FileId, FileSymbol)>> { 255 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
257 self.imp.approximately_resolve_symbol(file_id, offset) 256 self.imp.approximately_resolve_symbol(position)
258 } 257 }
259 pub fn find_all_refs( 258 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
260 &self, 259 Ok(self.imp.find_all_refs(position))
261 file_id: FileId,
262 offset: TextUnit,
263 ) -> Cancelable<Vec<(FileId, TextRange)>> {
264 Ok(self.imp.find_all_refs(file_id, offset))
265 } 260 }
266 pub fn parent_module( 261 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
267 &self, 262 self.imp.parent_module(position)
268 file_id: FileId,
269 offset: TextUnit,
270 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
271 self.imp.parent_module(file_id, offset)
272 } 263 }
273 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 264 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
274 self.imp.crate_for(file_id) 265 self.imp.crate_for(file_id)
@@ -284,12 +275,8 @@ impl Analysis {
284 let file = self.imp.file_syntax(file_id); 275 let file = self.imp.file_syntax(file_id);
285 Ok(ra_editor::highlight(&file)) 276 Ok(ra_editor::highlight(&file))
286 } 277 }
287 pub fn completions( 278 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
288 &self, 279 self.imp.completions(position)
289 file_id: FileId,
290 offset: TextUnit,
291 ) -> Cancelable<Option<Vec<CompletionItem>>> {
292 self.imp.completions(file_id, offset)
293 } 280 }
294 pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> { 281 pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> {
295 Ok(self.imp.assists(file_id, range)) 282 Ok(self.imp.assists(file_id, range))
@@ -299,10 +286,9 @@ impl Analysis {
299 } 286 }
300 pub fn resolve_callable( 287 pub fn resolve_callable(
301 &self, 288 &self,
302 file_id: FileId, 289 position: FilePosition,
303 offset: TextUnit,
304 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { 290 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> {
305 self.imp.resolve_callable(file_id, offset) 291 self.imp.resolve_callable(position)
306 } 292 }
307} 293}
308 294
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs
index a7134a0e6..8e8f969f4 100644
--- a/crates/ra_analysis/src/mock_analysis.rs
+++ b/crates/ra_analysis/src/mock_analysis.rs
@@ -1,16 +1,9 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::TextUnit;
4use relative_path::{RelativePath, RelativePathBuf}; 3use relative_path::{RelativePath, RelativePathBuf};
5use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
6 5
7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FileResolver}; 6use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FileResolver, FilePosition};
8
9#[derive(Debug)]
10pub struct FilePosition {
11 pub file_id: FileId,
12 pub offset: TextUnit,
13}
14 7
15/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
16/// from a set of in-memory files. 9/// from a set of in-memory files.
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 7f7bb8e6b..c605d34f0 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -15,10 +15,7 @@ use ra_analysis::{
15 15
16fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) { 16fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
17 let (analysis, position) = single_file_with_position(text); 17 let (analysis, position) = single_file_with_position(text);
18 analysis 18 analysis.resolve_callable(position).unwrap().unwrap()
19 .resolve_callable(position.file_id, position.offset)
20 .unwrap()
21 .unwrap()
22} 19}
23 20
24#[test] 21#[test]
@@ -32,9 +29,7 @@ fn test_resolve_module() {
32 ", 29 ",
33 ); 30 );
34 31
35 let symbols = analysis 32 let symbols = analysis.approximately_resolve_symbol(pos).unwrap();
36 .approximately_resolve_symbol(pos.file_id, pos.offset)
37 .unwrap();
38 assert_eq_dbg( 33 assert_eq_dbg(
39 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, 34 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
40 &symbols, 35 &symbols,
@@ -49,9 +44,7 @@ fn test_resolve_module() {
49 ", 44 ",
50 ); 45 );
51 46
52 let symbols = analysis 47 let symbols = analysis.approximately_resolve_symbol(pos).unwrap();
53 .approximately_resolve_symbol(pos.file_id, pos.offset)
54 .unwrap();
55 assert_eq_dbg( 48 assert_eq_dbg(
56 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, 49 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
57 &symbols, 50 &symbols,
@@ -92,7 +85,7 @@ fn test_resolve_parent_module() {
92 <|>// empty 85 <|>// empty
93 ", 86 ",
94 ); 87 );
95 let symbols = analysis.parent_module(pos.file_id, pos.offset).unwrap(); 88 let symbols = analysis.parent_module(pos).unwrap();
96 assert_eq_dbg( 89 assert_eq_dbg(
97 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [4; 7), kind: MODULE })]"#, 90 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [4; 7), kind: MODULE })]"#,
98 &symbols, 91 &symbols,
@@ -111,7 +104,7 @@ fn test_resolve_parent_module_for_inline() {
111 } 104 }
112 ", 105 ",
113 ); 106 );
114 let symbols = analysis.parent_module(pos.file_id, pos.offset).unwrap(); 107 let symbols = analysis.parent_module(pos).unwrap();
115 assert_eq_dbg( 108 assert_eq_dbg(
116 r#"[(FileId(1), FileSymbol { name: "bar", node_range: [18; 21), kind: MODULE })]"#, 109 r#"[(FileId(1), FileSymbol { name: "bar", node_range: [18; 21), kind: MODULE })]"#,
117 &symbols, 110 &symbols,
@@ -397,9 +390,7 @@ By default this method stops actor's `Context`."#
397 390
398fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> { 391fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
399 let (analysis, position) = single_file_with_position(text); 392 let (analysis, position) = single_file_with_position(text);
400 analysis 393 analysis.find_all_refs(position).unwrap()
401 .find_all_refs(position.file_id, position.offset)
402 .unwrap()
403} 394}
404 395
405#[test] 396#[test]
@@ -454,10 +445,7 @@ fn test_complete_crate_path() {
454 use crate::Sp<|> 445 use crate::Sp<|>
455 ", 446 ",
456 ); 447 );
457 let completions = analysis 448 let completions = analysis.completions(position).unwrap().unwrap();
458 .completions(position.file_id, position.offset)
459 .unwrap()
460 .unwrap();
461 assert_eq_dbg( 449 assert_eq_dbg(
462 r#"[CompletionItem { label: "foo", lookup: None, snippet: None }, 450 r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
463 CompletionItem { label: "Spam", lookup: None, snippet: None }]"#, 451 CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 84ffac2da..fa04f4b00 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
3 TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier, 3 TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier,
4}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition};
6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex}; 6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex};
7use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 7use ra_syntax::{SyntaxKind, TextRange, TextUnit};
8 8
@@ -165,6 +165,17 @@ impl<'a> TryConvWith for &'a TextDocumentIdentifier {
165 } 165 }
166} 166}
167 167
168impl<'a> TryConvWith for &'a TextDocumentPositionParams {
169 type Ctx = ServerWorld;
170 type Output = FilePosition;
171 fn try_conv_with(self, world: &ServerWorld) -> Result<FilePosition> {
172 let file_id = self.text_document.try_conv_with(world)?;
173 let line_index = world.analysis().file_line_index(file_id);
174 let offset = self.position.conv_with(&line_index);
175 Ok(FilePosition { file_id, offset })
176 }
177}
178
168impl<T: TryConvWith> TryConvWith for Vec<T> { 179impl<T: TryConvWith> TryConvWith for Vec<T> {
169 type Ctx = <T as TryConvWith>::Ctx; 180 type Ctx = <T as TryConvWith>::Ctx;
170 type Output = Vec<<T as TryConvWith>::Output>; 181 type Output = Vec<<T as TryConvWith>::Output>;
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 2219a0036..5314a333e 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -6,9 +6,9 @@ use languageserver_types::{
6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, Position, 7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, Position,
8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, 8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
9 WorkspaceEdit, 9 WorkspaceEdit, ParameterInformation, SignatureInformation,
10}; 10};
11use ra_analysis::{FileId, FoldKind, Query, RunnableKind}; 11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition};
12use ra_syntax::text_utils::contains_offset_nonstrict; 12use ra_syntax::text_utils::contains_offset_nonstrict;
13use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
14use serde_json::to_value; 14use serde_json::to_value;
@@ -83,10 +83,8 @@ pub fn handle_on_enter(
83 world: ServerWorld, 83 world: ServerWorld,
84 params: req::TextDocumentPositionParams, 84 params: req::TextDocumentPositionParams,
85) -> Result<Option<req::SourceChange>> { 85) -> Result<Option<req::SourceChange>> {
86 let file_id = params.text_document.try_conv_with(&world)?; 86 let position = params.try_conv_with(&world)?;
87 let line_index = world.analysis().file_line_index(file_id); 87 match world.analysis().on_enter(position) {
88 let offset = params.position.conv_with(&line_index);
89 match world.analysis().on_enter(file_id, offset) {
90 None => Ok(None), 88 None => Ok(None),
91 Some(edit) => Ok(Some(edit.try_conv_with(&world)?)), 89 Some(edit) => Ok(Some(edit.try_conv_with(&world)?)),
92 } 90 }
@@ -102,8 +100,11 @@ pub fn handle_on_type_formatting(
102 100
103 let file_id = params.text_document.try_conv_with(&world)?; 101 let file_id = params.text_document.try_conv_with(&world)?;
104 let line_index = world.analysis().file_line_index(file_id); 102 let line_index = world.analysis().file_line_index(file_id);
105 let offset = params.position.conv_with(&line_index); 103 let position = FilePosition {
106 let edits = match world.analysis().on_eq_typed(file_id, offset) { 104 file_id,
105 offset: params.position.conv_with(&line_index),
106 };
107 let edits = match world.analysis().on_eq_typed(position) {
107 None => return Ok(None), 108 None => return Ok(None),
108 Some(mut action) => action.source_file_edits.pop().unwrap().edits, 109 Some(mut action) => action.source_file_edits.pop().unwrap().edits,
109 }; 110 };
@@ -201,14 +202,9 @@ pub fn handle_goto_definition(
201 world: ServerWorld, 202 world: ServerWorld,
202 params: req::TextDocumentPositionParams, 203 params: req::TextDocumentPositionParams,
203) -> Result<Option<req::GotoDefinitionResponse>> { 204) -> Result<Option<req::GotoDefinitionResponse>> {
204 let file_id = params.text_document.try_conv_with(&world)?; 205 let position = params.try_conv_with(&world)?;
205 let line_index = world.analysis().file_line_index(file_id);
206 let offset = params.position.conv_with(&line_index);
207 let mut res = Vec::new(); 206 let mut res = Vec::new();
208 for (file_id, symbol) in world 207 for (file_id, symbol) in world.analysis().approximately_resolve_symbol(position)? {
209 .analysis()
210 .approximately_resolve_symbol(file_id, offset)?
211 {
212 let line_index = world.analysis().file_line_index(file_id); 208 let line_index = world.analysis().file_line_index(file_id);
213 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 209 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
214 res.push(location) 210 res.push(location)
@@ -220,11 +216,9 @@ pub fn handle_parent_module(
220 world: ServerWorld, 216 world: ServerWorld,
221 params: req::TextDocumentPositionParams, 217 params: req::TextDocumentPositionParams,
222) -> Result<Vec<Location>> { 218) -> Result<Vec<Location>> {
223 let file_id = params.text_document.try_conv_with(&world)?; 219 let position = params.try_conv_with(&world)?;
224 let line_index = world.analysis().file_line_index(file_id);
225 let offset = params.position.conv_with(&line_index);
226 let mut res = Vec::new(); 220 let mut res = Vec::new();
227 for (file_id, symbol) in world.analysis().parent_module(file_id, offset)? { 221 for (file_id, symbol) in world.analysis().parent_module(position)? {
228 let line_index = world.analysis().file_line_index(file_id); 222 let line_index = world.analysis().file_line_index(file_id);
229 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 223 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
230 res.push(location); 224 res.push(location);
@@ -381,10 +375,13 @@ pub fn handle_completion(
381 world: ServerWorld, 375 world: ServerWorld,
382 params: req::CompletionParams, 376 params: req::CompletionParams,
383) -> Result<Option<req::CompletionResponse>> { 377) -> Result<Option<req::CompletionResponse>> {
384 let file_id = params.text_document.try_conv_with(&world)?; 378 let position = {
385 let line_index = world.analysis().file_line_index(file_id); 379 let file_id = params.text_document.try_conv_with(&world)?;
386 let offset = params.position.conv_with(&line_index); 380 let line_index = world.analysis().file_line_index(file_id);
387 let items = match world.analysis().completions(file_id, offset)? { 381 let offset = params.position.conv_with(&line_index);
382 FilePosition { file_id, offset }
383 };
384 let items = match world.analysis().completions(position)? {
388 None => return Ok(None), 385 None => return Ok(None),
389 Some(items) => items, 386 Some(items) => items,
390 }; 387 };
@@ -444,13 +441,9 @@ pub fn handle_signature_help(
444 world: ServerWorld, 441 world: ServerWorld,
445 params: req::TextDocumentPositionParams, 442 params: req::TextDocumentPositionParams,
446) -> Result<Option<req::SignatureHelp>> { 443) -> Result<Option<req::SignatureHelp>> {
447 use languageserver_types::{ParameterInformation, SignatureInformation}; 444 let position = params.try_conv_with(&world)?;
448 445
449 let file_id = params.text_document.try_conv_with(&world)?; 446 if let Some((descriptor, active_param)) = world.analysis().resolve_callable(position)? {
450 let line_index = world.analysis().file_line_index(file_id);
451 let offset = params.position.conv_with(&line_index);
452
453 if let Some((descriptor, active_param)) = world.analysis().resolve_callable(file_id, offset)? {
454 let parameters: Vec<ParameterInformation> = descriptor 447 let parameters: Vec<ParameterInformation> = descriptor
455 .params 448 .params
456 .iter() 449 .iter()
@@ -489,18 +482,17 @@ pub fn handle_prepare_rename(
489 world: ServerWorld, 482 world: ServerWorld,
490 params: req::TextDocumentPositionParams, 483 params: req::TextDocumentPositionParams,
491) -> Result<Option<PrepareRenameResponse>> { 484) -> Result<Option<PrepareRenameResponse>> {
492 let file_id = params.text_document.try_conv_with(&world)?; 485 let position = params.try_conv_with(&world)?;
493 let line_index = world.analysis().file_line_index(file_id);
494 let offset = params.position.conv_with(&line_index);
495 486
496 // We support renaming references like handle_rename does. 487 // We support renaming references like handle_rename does.
497 // In the future we may want to reject the renaming of things like keywords here too. 488 // In the future we may want to reject the renaming of things like keywords here too.
498 let refs = world.analysis().find_all_refs(file_id, offset)?; 489 let refs = world.analysis().find_all_refs(position)?;
499 if refs.is_empty() { 490 let r = match refs.first() {
500 return Ok(None); 491 Some(r) => r,
501 } 492 None => return Ok(None),
502 493 };
503 let r = refs.first().unwrap(); 494 let file_id = params.text_document.try_conv_with(&world)?;
495 let line_index = world.analysis().file_line_index(file_id);
504 let loc = to_location(r.0, r.1, &world, &line_index)?; 496 let loc = to_location(r.0, r.1, &world, &line_index)?;
505 497
506 Ok(Some(PrepareRenameResponse::Range(loc.range))) 498 Ok(Some(PrepareRenameResponse::Range(loc.range)))
@@ -519,7 +511,9 @@ pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result<Option<
519 .into()); 511 .into());
520 } 512 }
521 513
522 let refs = world.analysis().find_all_refs(file_id, offset)?; 514 let refs = world
515 .analysis()
516 .find_all_refs(FilePosition { file_id, offset })?;
523 if refs.is_empty() { 517 if refs.is_empty() {
524 return Ok(None); 518 return Ok(None);
525 } 519 }
@@ -550,7 +544,9 @@ pub fn handle_references(
550 let line_index = world.analysis().file_line_index(file_id); 544 let line_index = world.analysis().file_line_index(file_id);
551 let offset = params.position.conv_with(&line_index); 545 let offset = params.position.conv_with(&line_index);
552 546
553 let refs = world.analysis().find_all_refs(file_id, offset)?; 547 let refs = world
548 .analysis()
549 .find_all_refs(FilePosition { file_id, offset })?;
554 550
555 Ok(Some( 551 Ok(Some(
556 refs.into_iter() 552 refs.into_iter()