aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-10-20 13:51:30 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-10-20 13:51:30 +0100
commit2ded93a78a108c1f7e0dd0a9036c88c786f21dce (patch)
tree4656be95dde6ebd9a38e680dba161aa53357acfb
parent4dbf0379ccd5c7643d48658f0ecc224add5a5c5c (diff)
parent3de77908eb52362e1acc3feed6186a18d8026f6e (diff)
Merge #143
143: Implement Find All References and Rename for local variables r=matklad a=kjeremy Expose `find_all_refs` in `Analysis`. This currently only works for local variables. Use this in the LSP to implement find all references and rename. Co-authored-by: Jeremy A. Kolb <[email protected]>
-rw-r--r--crates/ra_analysis/src/imp.rs32
-rw-r--r--crates/ra_analysis/src/lib.rs3
-rw-r--r--crates/ra_analysis/tests/tests.rs42
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs1
-rw-r--r--crates/ra_lsp_server/src/caps.rs8
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs78
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs3
-rw-r--r--crates/ra_lsp_server/src/req.rs2
-rw-r--r--editors/code/package-lock.json16
-rw-r--r--editors/code/package.json4
10 files changed, 174 insertions, 15 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index f1403cb5d..a67b1717a 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -257,6 +257,38 @@ impl AnalysisImpl {
257 vec![] 257 vec![]
258 } 258 }
259 259
260 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, _token: &JobToken) -> Vec<(FileId, TextRange)> {
261 let root = self.root(file_id);
262 let file = root.syntax(file_id);
263 let syntax = file.syntax();
264
265 let mut ret = vec![];
266
267 // Find the symbol we are looking for
268 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
269
270 // We are only handing local references for now
271 if let Some(resolved) = resolve_local_name(&file, offset, name_ref) {
272
273 ret.push((file_id, resolved.1));
274
275 if let Some(fn_def) = find_node_at_offset::<ast::FnDef>(syntax, offset) {
276
277 let refs : Vec<_> = fn_def.syntax().descendants()
278 .filter_map(ast::NameRef::cast)
279 .filter(|n: &ast::NameRef| resolve_local_name(&file, n.syntax().range().start(), *n) == Some(resolved.clone()))
280 .collect();
281
282 for r in refs {
283 ret.push((file_id, r.syntax().range()));
284 }
285 }
286 }
287 }
288
289 ret
290 }
291
260 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 292 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
261 let root = self.root(file_id); 293 let root = self.root(file_id);
262 let module_tree = root.module_tree(); 294 let module_tree = root.module_tree();
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 2eeacaabe..46cc0722b 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -217,6 +217,9 @@ impl Analysis {
217 self.imp 217 self.imp
218 .approximately_resolve_symbol(file_id, offset, token) 218 .approximately_resolve_symbol(file_id, offset, token)
219 } 219 }
220 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, TextRange)> {
221 self.imp.find_all_refs(file_id, offset, token)
222 }
220 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 223 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
221 self.imp.parent_module(file_id) 224 self.imp.parent_module(file_id)
222 } 225 }
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index e0c637d65..0c2c69ea0 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -10,6 +10,8 @@ use std::sync::Arc;
10use ra_analysis::{ 10use ra_analysis::{
11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle, 11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle,
12}; 12};
13use ra_syntax::TextRange;
14
13use relative_path::{RelativePath, RelativePathBuf}; 15use relative_path::{RelativePath, RelativePathBuf};
14use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
15use test_utils::{assert_eq_dbg, extract_offset}; 17use test_utils::{assert_eq_dbg, extract_offset};
@@ -225,3 +227,43 @@ fn bar() {
225 assert_eq!(desc.ret_type, None); 227 assert_eq!(desc.ret_type, None);
226 assert_eq!(param, Some(1)); 228 assert_eq!(param, Some(1));
227} 229}
230
231fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
232 let (offset, code) = extract_offset(text);
233 let code = code.as_str();
234
235 let (_handle, token) = JobHandle::new();
236 let snap = analysis(&[("/lib.rs", code)]);
237
238 snap.find_all_refs(FileId(1), offset, &token)
239}
240
241#[test]
242fn test_find_all_refs_for_local() {
243 let code = r#"
244 fn main() {
245 let mut i = 1;
246 let j = 1;
247 i = i<|> + j;
248
249 {
250 i = 0;
251 }
252
253 i = 5;
254 }"#;
255
256 let refs = get_all_refs(code);
257 assert_eq!(refs.len(), 5);
258}
259
260#[test]
261fn test_find_all_refs_for_param_inside() {
262 let code = r#"
263 fn foo(i : u32) -> u32 {
264 i<|>
265 }"#;
266
267 let refs = get_all_refs(code);
268 assert_eq!(refs.len(), 2);
269} \ No newline at end of file
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index 9088e5a60..f10bdf657 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -270,7 +270,6 @@ pub fn resolve_local_name<'a>(
270 .filter(|entry| shadowed.insert(entry.name())) 270 .filter(|entry| shadowed.insert(entry.name()))
271 .filter(|entry| entry.name() == name_ref.text()) 271 .filter(|entry| entry.name() == name_ref.text())
272 .nth(0); 272 .nth(0);
273 eprintln!("ret = {:?}", ret);
274 ret 273 ret
275} 274}
276 275
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 1dd495791..b6436b646 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, 2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions,
3 ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities, 3 ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities,
4 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 4 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
5 TextDocumentSyncOptions, 5 TextDocumentSyncOptions, RenameProviderCapability, RenameOptions
6}; 6};
7 7
8pub fn server_capabilities() -> ServerCapabilities { 8pub fn server_capabilities() -> ServerCapabilities {
@@ -27,7 +27,7 @@ pub fn server_capabilities() -> ServerCapabilities {
27 definition_provider: Some(true), 27 definition_provider: Some(true),
28 type_definition_provider: None, 28 type_definition_provider: None,
29 implementation_provider: None, 29 implementation_provider: None,
30 references_provider: None, 30 references_provider: Some(true),
31 document_highlight_provider: None, 31 document_highlight_provider: None,
32 document_symbol_provider: Some(true), 32 document_symbol_provider: Some(true),
33 workspace_symbol_provider: Some(true), 33 workspace_symbol_provider: Some(true),
@@ -40,7 +40,9 @@ pub fn server_capabilities() -> ServerCapabilities {
40 more_trigger_character: None, 40 more_trigger_character: None,
41 }), 41 }),
42 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 42 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
43 rename_provider: None, 43 rename_provider: Some(RenameProviderCapability::Options(RenameOptions{
44 prepare_provider: Some(true)
45 })),
44 color_provider: None, 46 color_provider: None,
45 execute_command_provider: Some(ExecuteCommandOptions { 47 execute_command_provider: Some(ExecuteCommandOptions {
46 commands: vec!["apply_code_action".to_string()], 48 commands: vec!["apply_code_action".to_string()],
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index c25b63852..639fe4553 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -4,6 +4,7 @@ use languageserver_types::{
4 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, 4 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
5 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, 5 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams,
6 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit, 6 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit,
7 RenameParams, WorkspaceEdit, PrepareRenameResponse
7}; 8};
8use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind}; 9use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind};
9use ra_syntax::text_utils::contains_offset_nonstrict; 10use ra_syntax::text_utils::contains_offset_nonstrict;
@@ -17,6 +18,8 @@ use crate::{
17 Result, 18 Result,
18}; 19};
19 20
21use std::collections::HashMap;
22
20pub fn handle_syntax_tree( 23pub fn handle_syntax_tree(
21 world: ServerWorld, 24 world: ServerWorld,
22 params: req::SyntaxTreeParams, 25 params: req::SyntaxTreeParams,
@@ -460,6 +463,81 @@ pub fn handle_signature_help(
460 } 463 }
461} 464}
462 465
466pub fn handle_prepare_rename(
467 world: ServerWorld,
468 params: req::TextDocumentPositionParams,
469 token: JobToken,
470) -> Result<Option<PrepareRenameResponse>> {
471 let file_id = params.text_document.try_conv_with(&world)?;
472 let line_index = world.analysis().file_line_index(file_id);
473 let offset = params.position.conv_with(&line_index);
474
475 // We support renaming references like handle_rename does.
476 // In the future we may want to reject the renaming of things like keywords here too.
477 let refs = world.analysis().find_all_refs(file_id, offset, &token);
478 if refs.is_empty() {
479 return Ok(None);
480 }
481
482 let r = refs.first().unwrap();
483 let loc = to_location(r.0, r.1, &world, &line_index)?;
484
485 Ok(Some(PrepareRenameResponse::Range(loc.range)))
486}
487
488pub fn handle_rename(
489 world: ServerWorld,
490 params: RenameParams,
491 token: JobToken,
492) -> Result<Option<WorkspaceEdit>> {
493 let file_id = params.text_document.try_conv_with(&world)?;
494 let line_index = world.analysis().file_line_index(file_id);
495 let offset = params.position.conv_with(&line_index);
496
497 if params.new_name.is_empty() {
498 return Ok(None);
499 }
500
501 let refs = world.analysis().find_all_refs(file_id, offset, &token);
502 if refs.is_empty() {
503 return Ok(None);
504 }
505
506 let mut changes = HashMap::new();
507 for r in refs {
508 if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
509 changes.entry(loc.uri).or_insert(Vec::new()).push(
510 TextEdit {
511 range: loc.range,
512 new_text: params.new_name.clone()
513 });
514 }
515 }
516
517 Ok(Some(WorkspaceEdit {
518 changes: Some(changes),
519
520 // TODO: return this instead if client/server support it. See #144
521 document_changes : None,
522 }))
523}
524
525pub fn handle_references(
526 world: ServerWorld,
527 params: req::ReferenceParams,
528 token: JobToken,
529) -> Result<Option<Vec<Location>>> {
530 let file_id = params.text_document.try_conv_with(&world)?;
531 let line_index = world.analysis().file_line_index(file_id);
532 let offset = params.position.conv_with(&line_index);
533
534 let refs = world.analysis().find_all_refs(file_id, offset, &token);
535
536 Ok(Some(refs.into_iter()
537 .filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
538 .collect()))
539}
540
463pub fn handle_code_action( 541pub fn handle_code_action(
464 world: ServerWorld, 542 world: ServerWorld,
465 params: req::CodeActionParams, 543 params: req::CodeActionParams,
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index a11baf4aa..165f2e78f 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -248,6 +248,9 @@ fn on_request(
248 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 248 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
249 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 249 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
250 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? 250 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
251 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
252 .on::<req::Rename>(handlers::handle_rename)?
253 .on::<req::References>(handlers::handle_references)?
251 .finish(); 254 .finish();
252 match req { 255 match req {
253 Ok((id, handle)) => { 256 Ok((id, handle)) => {
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index b76bfbcbc..6cd04d84c 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -7,7 +7,7 @@ pub use languageserver_types::{
7 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 7 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
8 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, 8 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
9 PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, 9 PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams,
10 TextEdit, WorkspaceSymbolParams, 10 TextEdit, WorkspaceSymbolParams, ReferenceParams,
11}; 11};
12 12
13pub enum SyntaxTree {} 13pub enum SyntaxTree {}
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 33c5203b2..fe304623f 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -2074,8 +2074,7 @@
2074 "semver": { 2074 "semver": {
2075 "version": "5.5.1", 2075 "version": "5.5.1",
2076 "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", 2076 "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
2077 "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", 2077 "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw=="
2078 "dev": true
2079 }, 2078 },
2080 "source-map": { 2079 "source-map": {
2081 "version": "0.6.1", 2080 "version": "0.6.1",
@@ -2509,9 +2508,9 @@
2509 } 2508 }
2510 }, 2509 },
2511 "vsce": { 2510 "vsce": {
2512 "version": "1.51.1", 2511 "version": "1.52.0",
2513 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.51.1.tgz", 2512 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.52.0.tgz",
2514 "integrity": "sha512-Hf2HE9O/MRQHxUUgWHAm7mOkz0K5swuF2smaE/sP7+OWp/5DdIPFwmLEYCCZHxG25l3GBRoO0dAL8S5w//et+g==", 2513 "integrity": "sha512-k+KYoTx1sacpYf2BHTA7GN82MNSlf2N4EuppFWwtTN/Sh6fWzIJafxxCNBCDK0H+5NDWfRGZheBY8C3/HOE2ZA==",
2515 "dev": true, 2514 "dev": true,
2516 "requires": { 2515 "requires": {
2517 "cheerio": "1.0.0-rc.2", 2516 "cheerio": "1.0.0-rc.2",
@@ -2561,10 +2560,11 @@
2561 "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==" 2560 "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg=="
2562 }, 2561 },
2563 "vscode-languageclient": { 2562 "vscode-languageclient": {
2564 "version": "4.4.2", 2563 "version": "5.1.1",
2565 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-4.4.2.tgz", 2564 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.1.1.tgz",
2566 "integrity": "sha512-9TUzsg1UM6n1UEyPlWbDf7tK1wJAK7UGFRmGDN8sz4KmbbDiVRh6YicaB/5oRSVTpuV47PdJpYlOl3SJ0RiK1Q==", 2565 "integrity": "sha512-jMxshi+BPRQFNG8GB00dJv7ldqMda0be26laYYll/udtJuHbog6RqK10GSxHWDN0PgY0b0m5fePyTk3bq8a0TA==",
2567 "requires": { 2566 "requires": {
2567 "semver": "5.5.1",
2568 "vscode-languageserver-protocol": "3.13.0" 2568 "vscode-languageserver-protocol": "3.13.0"
2569 } 2569 }
2570 }, 2570 },
diff --git a/editors/code/package.json b/editors/code/package.json
index eeb6dd816..ea84a1ccb 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -28,7 +28,7 @@
28 "singleQuote": true 28 "singleQuote": true
29 }, 29 },
30 "dependencies": { 30 "dependencies": {
31 "vscode-languageclient": "^4.4.0" 31 "vscode-languageclient": "^5.1.1"
32 }, 32 },
33 "devDependencies": { 33 "devDependencies": {
34 "@types/mocha": "^2.2.42", 34 "@types/mocha": "^2.2.42",
@@ -37,7 +37,7 @@
37 "tslint": "^5.11.0", 37 "tslint": "^5.11.0",
38 "tslint-config-prettier": "^1.15.0", 38 "tslint-config-prettier": "^1.15.0",
39 "typescript": "^2.6.1", 39 "typescript": "^2.6.1",
40 "vsce": "^1.51.1", 40 "vsce": "^1.52.0",
41 "vscode": "^1.1.21" 41 "vscode": "^1.1.21"
42 }, 42 },
43 "activationEvents": [ 43 "activationEvents": [