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

Implement find implementations extension #181

Merged
merged 3 commits into from
Aug 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,29 @@ the RLS.

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

* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent from the RLS
to a client before a build starts and before any diagnostics from a build are sent.
* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent from the RLS
to a client when a build is complete (successfully or not, or even skipped)
and all post-build analysis by the RLS is complete.
#### RLS to LSP Client

These are all sent from the RLS to an LSP client and are only used to improve
the user experience by showing progress indicators.

* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent before a
build starts and before any diagnostics from a build are sent.
* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent when a build
is complete (successfully or not, or even skipped) and all post-build analysis
by the RLS is complete.
* `rustWorkspace/deglob`: message sent from the client to the RLS to initiate a
deglob refactoring.

#### LSP Client to RLS

The following request is to support Rust specific features.

* `rustDocument/implementations`: request
params: [`TextDocumentPositionParams`]
result: [`Location`]`[]`

List all implementation blocks for a trait, struct, or enum denoted by the
given text document position.

[`TextDocumentPositionParams`]: (https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textdocumentpositionparams)
[`Location`]: (https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#location)
25 changes: 24 additions & 1 deletion src/actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,32 @@ impl ActionHandler {
});
}

pub fn find_impls<O: Output>(&self, id: usize, params: TextDocumentPositionParams, out: O) {
let t = thread::current();
let file_path = parse_file_path!(&params.text_document.uri, "find_impls");
let span = self.convert_pos_to_span(file_path, params.position);
let type_id = self.analysis.id(&span).expect("Analysis: Getting typeid from span");
let analysis = self.analysis.clone();

let handle = thread::spawn(move || {
let result = analysis.find_impls(type_id).map(|spans| {
spans.into_iter().map(|x| ls_util::rls_to_location(&x)).collect()
});
t.unpark();
result
});
thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT));

let result = handle.join();
trace!("find_impls: {:?}", result);
match result {
Ok(Ok(r)) => out.success(id, ResponseData::Locations(r)),
_ => out.failure_message(id, ErrorCode::InternalError, "Find Implementations failed to complete successfully"),
}
}

pub fn on_open<O: Output>(&self, open: DidOpenTextDocumentParams, _out: O) {
trace!("on_open: {:?}", open.text_document.uri);

let file_path = parse_file_path!(&open.text_document.uri, "on_open");

self.vfs.set_file(&file_path, &open.text_document.text);
Expand Down
7 changes: 7 additions & 0 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ pub fn server_failure(id: jsonrpc::Id, error: jsonrpc::Error) -> jsonrpc::Failur
#[allow(non_upper_case_globals)]
pub const REQUEST__Deglob: &'static str = "rustWorkspace/deglob";

#[cfg(test)]
#[allow(non_upper_case_globals)]
pub const REQUEST__FindImpls: &'static str = "rustDocument/implementations";


#[derive(Debug, Serialize)]
pub struct Ack;

Expand Down Expand Up @@ -290,6 +295,7 @@ messages! {
"textDocument/codeAction" => CodeAction(CodeActionParams);
"workspace/executeCommand" => ExecuteCommand(ExecuteCommandParams);
"rustWorkspace/deglob" => Deglob(Location);
"rustDocument/implementations" => FindImpls(TextDocumentPositionParams);
}
notifications {
"initialized" => Initialized;
Expand Down Expand Up @@ -518,6 +524,7 @@ impl<O: Output> LsService<O> {
Deglob(params) => { action: deglob };
ExecuteCommand(params) => { action: execute_command };
CodeAction(params) => { action: code_action };
FindImpls(params) => { action: find_impls };
}
notifications {
Initialized => {{ self.handler.inited().initialized(self.output.clone()) }};
Expand Down
66 changes: 66 additions & 0 deletions src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,3 +581,69 @@ fn test_parse_error_on_malformed_input() {

assert!(failure.error.code == jsonrpc_core::ErrorCode::ParseError);
}

#[test]
fn test_find_impls() {
let (mut cache, _tc) = init_env("find_impls");

let source_file_path = Path::new("src").join("main.rs");

let root_path = cache.abs_path(Path::new("."));
let url = Url::from_file_path(cache.abs_path(&source_file_path))
.expect("couldn't convert file path to URL");

// This test contains code for testing implementations of `Eq`. However, `rust-analysis` is not
// installed on Travis making rls-analysis fail why retrieving the typeid. Installing
// `rust-analysis` is also not an option, because this makes other test timeout.
// e.g., https://travis-ci.org/rust-lang-nursery/rls/jobs/265339002

let messages = vec![
ServerMessage::initialize(0,root_path.as_os_str().to_str().map(|x| x.to_owned())),
ServerMessage::request(1, Method::FindImpls(TextDocumentPositionParams {
text_document: TextDocumentIdentifier::new(url.clone()),
position: cache.mk_ls_position(src(&source_file_path, 13, "Bar"))
})),
ServerMessage::request(2, Method::FindImpls(TextDocumentPositionParams {
text_document: TextDocumentIdentifier::new(url.clone()),
position: cache.mk_ls_position(src(&source_file_path, 16, "Super"))
})),
// Does not work on Travis
// ServerMessage::request(3, Method::FindImpls(TextDocumentPositionParams {
// text_document: TextDocumentIdentifier::new(url),
// position: cache.mk_ls_position(src(&source_file_path, 20, "Eq"))
// })),
];

let (mut server, results) = mock_server(messages);
// Initialise and build.
assert_eq!(ls_server::LsService::handle_message(&mut server),
ls_server::ServerStateChange::Continue);
expect_messages(results.clone(),
&[ExpectedMessage::new(Some(0)).expect_contains("capabilities"),
ExpectedMessage::new(None).expect_contains("diagnosticsBegin"),
ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]);

assert_eq!(ls_server::LsService::handle_message(&mut server),
ls_server::ServerStateChange::Continue);
// TODO structural checking of result, rather than looking for a string - src(&source_file_path, 12, "world")
expect_messages(results.clone(), &[
ExpectedMessage::new(Some(1))
.expect_contains(r#""range":{"start":{"line":18,"character":15},"end":{"line":18,"character":18}}"#)
.expect_contains(r#""range":{"start":{"line":19,"character":12},"end":{"line":19,"character":15}}"#)
]);
assert_eq!(ls_server::LsService::handle_message(&mut server),
ls_server::ServerStateChange::Continue);
expect_messages(results.clone(), &[
ExpectedMessage::new(Some(2))
.expect_contains(r#""range":{"start":{"line":18,"character":15},"end":{"line":18,"character":18}}"#)
.expect_contains(r#""range":{"start":{"line":22,"character":15},"end":{"line":22,"character":18}}"#)
]);
// Does not work on Travis
// assert_eq!(ls_server::LsService::handle_message(&mut server),
// ls_server::ServerStateChange::Continue);
// expect_messages(results.clone(), &[
// // TODO assert that only one position is returned
// ExpectedMessage::new(Some(3))
// .expect_contains(r#""range":{"start":{"line":19,"character":12},"end":{"line":19,"character":15}}"#)
// ]);
}
4 changes: 4 additions & 0 deletions test_data/find_impls/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions test_data/find_impls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "find_impls"
version = "0.1.0"
authors = ["Jonas Bushart <[email protected]>"]

[dependencies]
23 changes: 23 additions & 0 deletions test_data/find_impls/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]

#[derive(PartialEq)]
struct Bar;
struct Foo;

trait Super{}
trait Sub: Super {}

impl Super for Bar {}
impl Eq for Bar {}

impl Sub for Foo {}
impl Super for Foo {}