Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 85724ef

Browse files
authored
Merge pull request #181 from jonasbb/find-impls
Implement find implementations extension
2 parents 6dcaede + 67fb3a4 commit 85724ef

File tree

7 files changed

+154
-6
lines changed

7 files changed

+154
-6
lines changed

contributing.md

+24-5
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,29 @@ the RLS.
301301

302302
The RLS uses some custom extensions to the Language Server Protocol.
303303

304-
* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent from the RLS
305-
to a client before a build starts and before any diagnostics from a build are sent.
306-
* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent from the RLS
307-
to a client when a build is complete (successfully or not, or even skipped)
308-
and all post-build analysis by the RLS is complete.
304+
#### RLS to LSP Client
305+
306+
These are all sent from the RLS to an LSP client and are only used to improve
307+
the user experience by showing progress indicators.
308+
309+
* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent before a
310+
build starts and before any diagnostics from a build are sent.
311+
* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent when a build
312+
is complete (successfully or not, or even skipped) and all post-build analysis
313+
by the RLS is complete.
309314
* `rustWorkspace/deglob`: message sent from the client to the RLS to initiate a
310315
deglob refactoring.
316+
317+
#### LSP Client to RLS
318+
319+
The following request is to support Rust specific features.
320+
321+
* `rustDocument/implementations`: request
322+
params: [`TextDocumentPositionParams`]
323+
result: [`Location`]`[]`
324+
325+
List all implementation blocks for a trait, struct, or enum denoted by the
326+
given text document position.
327+
328+
[`TextDocumentPositionParams`]: (https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textdocumentpositionparams)
329+
[`Location`]: (https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#location)

src/actions/mod.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,32 @@ impl ActionHandler {
253253
});
254254
}
255255

256+
pub fn find_impls<O: Output>(&self, id: usize, params: TextDocumentPositionParams, out: O) {
257+
let t = thread::current();
258+
let file_path = parse_file_path!(&params.text_document.uri, "find_impls");
259+
let span = self.convert_pos_to_span(file_path, params.position);
260+
let type_id = self.analysis.id(&span).expect("Analysis: Getting typeid from span");
261+
let analysis = self.analysis.clone();
262+
263+
let handle = thread::spawn(move || {
264+
let result = analysis.find_impls(type_id).map(|spans| {
265+
spans.into_iter().map(|x| ls_util::rls_to_location(&x)).collect()
266+
});
267+
t.unpark();
268+
result
269+
});
270+
thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT));
271+
272+
let result = handle.join();
273+
trace!("find_impls: {:?}", result);
274+
match result {
275+
Ok(Ok(r)) => out.success(id, ResponseData::Locations(r)),
276+
_ => out.failure_message(id, ErrorCode::InternalError, "Find Implementations failed to complete successfully"),
277+
}
278+
}
279+
256280
pub fn on_open<O: Output>(&self, open: DidOpenTextDocumentParams, _out: O) {
257281
trace!("on_open: {:?}", open.text_document.uri);
258-
259282
let file_path = parse_file_path!(&open.text_document.uri, "on_open");
260283

261284
self.vfs.set_file(&file_path, &open.text_document.text);

src/server.rs

+7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ pub fn server_failure(id: jsonrpc::Id, error: jsonrpc::Error) -> jsonrpc::Failur
3636
#[allow(non_upper_case_globals)]
3737
pub const REQUEST__Deglob: &'static str = "rustWorkspace/deglob";
3838

39+
#[cfg(test)]
40+
#[allow(non_upper_case_globals)]
41+
pub const REQUEST__FindImpls: &'static str = "rustDocument/implementations";
42+
43+
3944
#[derive(Debug, Serialize)]
4045
pub struct Ack;
4146

@@ -290,6 +295,7 @@ messages! {
290295
"textDocument/codeAction" => CodeAction(CodeActionParams);
291296
"workspace/executeCommand" => ExecuteCommand(ExecuteCommandParams);
292297
"rustWorkspace/deglob" => Deglob(Location);
298+
"rustDocument/implementations" => FindImpls(TextDocumentPositionParams);
293299
}
294300
notifications {
295301
"initialized" => Initialized;
@@ -518,6 +524,7 @@ impl<O: Output> LsService<O> {
518524
Deglob(params) => { action: deglob };
519525
ExecuteCommand(params) => { action: execute_command };
520526
CodeAction(params) => { action: code_action };
527+
FindImpls(params) => { action: find_impls };
521528
}
522529
notifications {
523530
Initialized => {{ self.handler.inited().initialized(self.output.clone()) }};

src/test/mod.rs

+66
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,69 @@ fn test_parse_error_on_malformed_input() {
581581

582582
assert!(failure.error.code == jsonrpc_core::ErrorCode::ParseError);
583583
}
584+
585+
#[test]
586+
fn test_find_impls() {
587+
let (mut cache, _tc) = init_env("find_impls");
588+
589+
let source_file_path = Path::new("src").join("main.rs");
590+
591+
let root_path = cache.abs_path(Path::new("."));
592+
let url = Url::from_file_path(cache.abs_path(&source_file_path))
593+
.expect("couldn't convert file path to URL");
594+
595+
// This test contains code for testing implementations of `Eq`. However, `rust-analysis` is not
596+
// installed on Travis making rls-analysis fail why retrieving the typeid. Installing
597+
// `rust-analysis` is also not an option, because this makes other test timeout.
598+
// e.g., https://travis-ci.org/rust-lang-nursery/rls/jobs/265339002
599+
600+
let messages = vec![
601+
ServerMessage::initialize(0,root_path.as_os_str().to_str().map(|x| x.to_owned())),
602+
ServerMessage::request(1, Method::FindImpls(TextDocumentPositionParams {
603+
text_document: TextDocumentIdentifier::new(url.clone()),
604+
position: cache.mk_ls_position(src(&source_file_path, 13, "Bar"))
605+
})),
606+
ServerMessage::request(2, Method::FindImpls(TextDocumentPositionParams {
607+
text_document: TextDocumentIdentifier::new(url.clone()),
608+
position: cache.mk_ls_position(src(&source_file_path, 16, "Super"))
609+
})),
610+
// Does not work on Travis
611+
// ServerMessage::request(3, Method::FindImpls(TextDocumentPositionParams {
612+
// text_document: TextDocumentIdentifier::new(url),
613+
// position: cache.mk_ls_position(src(&source_file_path, 20, "Eq"))
614+
// })),
615+
];
616+
617+
let (mut server, results) = mock_server(messages);
618+
// Initialise and build.
619+
assert_eq!(ls_server::LsService::handle_message(&mut server),
620+
ls_server::ServerStateChange::Continue);
621+
expect_messages(results.clone(),
622+
&[ExpectedMessage::new(Some(0)).expect_contains("capabilities"),
623+
ExpectedMessage::new(None).expect_contains("diagnosticsBegin"),
624+
ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]);
625+
626+
assert_eq!(ls_server::LsService::handle_message(&mut server),
627+
ls_server::ServerStateChange::Continue);
628+
// TODO structural checking of result, rather than looking for a string - src(&source_file_path, 12, "world")
629+
expect_messages(results.clone(), &[
630+
ExpectedMessage::new(Some(1))
631+
.expect_contains(r#""range":{"start":{"line":18,"character":15},"end":{"line":18,"character":18}}"#)
632+
.expect_contains(r#""range":{"start":{"line":19,"character":12},"end":{"line":19,"character":15}}"#)
633+
]);
634+
assert_eq!(ls_server::LsService::handle_message(&mut server),
635+
ls_server::ServerStateChange::Continue);
636+
expect_messages(results.clone(), &[
637+
ExpectedMessage::new(Some(2))
638+
.expect_contains(r#""range":{"start":{"line":18,"character":15},"end":{"line":18,"character":18}}"#)
639+
.expect_contains(r#""range":{"start":{"line":22,"character":15},"end":{"line":22,"character":18}}"#)
640+
]);
641+
// Does not work on Travis
642+
// assert_eq!(ls_server::LsService::handle_message(&mut server),
643+
// ls_server::ServerStateChange::Continue);
644+
// expect_messages(results.clone(), &[
645+
// // TODO assert that only one position is returned
646+
// ExpectedMessage::new(Some(3))
647+
// .expect_contains(r#""range":{"start":{"line":19,"character":12},"end":{"line":19,"character":15}}"#)
648+
// ]);
649+
}

test_data/find_impls/Cargo.lock

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test_data/find_impls/Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "find_impls"
3+
version = "0.1.0"
4+
authors = ["Jonas Bushart <[email protected]>"]
5+
6+
[dependencies]

test_data/find_impls/src/main.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#![allow(dead_code)]
11+
12+
#[derive(PartialEq)]
13+
struct Bar;
14+
struct Foo;
15+
16+
trait Super{}
17+
trait Sub: Super {}
18+
19+
impl Super for Bar {}
20+
impl Eq for Bar {}
21+
22+
impl Sub for Foo {}
23+
impl Super for Foo {}

0 commit comments

Comments
 (0)