use std::{collections::HashMap, path::PathBuf, time::Instant};
use lsp_types::{
- CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions,
- GotoDefinitionParams, HoverParams, PartialResultParams, Position, Range, TextDocumentItem,
- TextDocumentPositionParams, WorkDoneProgressParams,
-};
-use rust_analyzer::req::{
- CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument,
- Formatting, GotoDefinition, HoverRequest, OnEnter, Runnables, RunnablesParams,
+ notification::DidOpenTextDocument,
+ request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest},
+ CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams,
+ DocumentFormattingParams, FormattingOptions, GotoDefinitionParams, HoverParams,
+ PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams,
+ WorkDoneProgressParams,
};
+use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams};
use serde_json::json;
use tempfile::TempDir;
use test_utils::skip_slow_tests;
let project_start = Instant::now();
let server = Project::with_fixture(
r#"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = "foo"
version = "0.0.0"
-//- src/lib.rs
+//- /src/lib.rs
use std::collections::Spam;
"#,
)
eprintln!("completion took {:?}", completion_start.elapsed());
}
-#[test]
-fn test_runnables_no_project() {
- if skip_slow_tests() {
- return;
- }
-
- let server = project(
- r"
-//- lib.rs
-#[test]
-fn foo() {
-}
-",
- );
- server.wait_until_workspace_is_loaded();
- server.request::<Runnables>(
- RunnablesParams { text_document: server.doc_id("lib.rs"), position: None },
- json!([
- {
- "args": [ "test" ],
- "extraArgs": [ "foo", "--nocapture" ],
- "bin": "cargo",
- "env": { "RUST_BACKTRACE": "short" },
- "cwd": null,
- "label": "test foo",
- "range": {
- "end": { "character": 1, "line": 2 },
- "start": { "character": 0, "line": 0 }
- }
- },
- {
- "args": ["check", "--workspace"],
- "extraArgs": [],
- "bin": "cargo",
- "env": {},
- "cwd": null,
- "label": "cargo check --workspace",
- "range": {
- "end": { "character": 0, "line": 0 },
- "start": { "character": 0, "line": 0 }
- }
- }
- ]),
- );
-}
-
#[test]
fn test_runnables_project() {
if skip_slow_tests() {
}
let code = r#"
-//- foo/Cargo.toml
+//- /foo/Cargo.toml
[package]
name = "foo"
version = "0.0.0"
-//- foo/src/lib.rs
+//- /foo/src/lib.rs
pub fn foo() {}
-//- foo/tests/spam.rs
+//- /foo/tests/spam.rs
#[test]
fn test_eggs() {}
-//- bar/Cargo.toml
+//- /bar/Cargo.toml
[package]
name = "bar"
version = "0.0.0"
-//- bar/src/main.rs
+//- /bar/src/main.rs
fn main() {}
"#;
server.request::<Runnables>(
RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None },
json!([
- {
- "args": [ "test", "--package", "foo", "--test", "spam" ],
- "extraArgs": [ "test_eggs", "--exact", "--nocapture" ],
- "bin": "cargo",
- "env": { "RUST_BACKTRACE": "short" },
- "label": "test test_eggs",
- "range": {
- "end": { "character": 17, "line": 1 },
- "start": { "character": 0, "line": 0 }
- },
- "cwd": server.path().join("foo")
+ {
+ "args": {
+ "cargoArgs": ["test", "--package", "foo", "--test", "spam"],
+ "executableArgs": ["test_eggs", "--exact", "--nocapture"],
+ "workspaceRoot": server.path().join("foo")
},
- {
- "args": [ "check", "--package", "foo", "--test", "spam" ],
- "extraArgs": [],
- "bin": "cargo",
- "env": {},
- "label": "cargo check -p foo",
- "range": {
- "end": { "character": 0, "line": 0 },
+ "kind": "cargo",
+ "label": "test test_eggs",
+ "location": {
+ "targetRange": {
+ "end": { "character": 17, "line": 1 },
"start": { "character": 0, "line": 0 }
},
- "cwd": server.path().join("foo")
- },
- {
- "args": [ "test", "--package", "foo", "--test", "spam" ],
- "extraArgs": [],
- "bin": "cargo",
- "env": {},
- "label": "cargo test -p foo",
- "range": {
- "end": { "character": 0, "line": 0 },
- "start": { "character": 0, "line": 0 }
+ "targetSelectionRange": {
+ "end": { "character": 12, "line": 1 },
+ "start": { "character": 3, "line": 1 }
},
- "cwd": server.path().join("foo")
+ "targetUri": "file:///[..]/tests/spam.rs"
}
+ },
+ {
+ "args": {
+ "cargoArgs": ["check", "--package", "foo"],
+ "executableArgs": [],
+ "workspaceRoot": server.path().join("foo")
+ },
+ "kind": "cargo",
+ "label": "cargo check -p foo"
+ },
+ {
+ "args": {
+ "cargoArgs": ["test", "--package", "foo"],
+ "executableArgs": [],
+ "workspaceRoot": server.path().join("foo")
+ },
+ "kind": "cargo",
+ "label": "cargo test -p foo"
+ }
]),
);
}
let server = project(
r#"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = "foo"
version = "0.0.0"
-//- src/lib.rs
+//- /src/lib.rs
mod bar;
fn main() {
let server = project(
r#"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = "foo"
version = "0.0.0"
edition = "2018"
-//- src/lib.rs
+//- /src/lib.rs
mod bar;
async fn test() {
let server = project(
r#"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = "foo"
version = "0.0.0"
-//- src/lib.rs
+//- /src/lib.rs
mod bar;
fn main() {}
partial_result_params: PartialResultParams::default(),
work_done_progress_params: WorkDoneProgressParams::default(),
},
- json!([
- {
- "command": {
- "arguments": [
+ json!([{
+ "edit": {
+ "documentChanges": [
{
- "cursorPosition": null,
- "label": "create module",
- "workspaceEdit": {
- "documentChanges": [
- {
- "kind": "create",
- "uri": "file:///[..]/src/bar.rs"
- }
- ]
- }
+ "kind": "create",
+ "uri": "file:///[..]/src/bar.rs"
}
- ],
- "command": "rust-analyzer.applySourceChange",
- "title": "create module"
+ ]
},
- "title": "create module"
- }
- ]),
+ "kind": "quickfix",
+ "title": "Create module"
+ }]),
);
server.request::<CodeActionRequest>(
"root_module": path.join("src/lib.rs"),
"deps": [],
"edition": "2015",
- "atom_cfgs": [],
- "key_value_cfgs": {}
+ "cfg": [ "cfg_atom_1", "feature=cfg_1"],
} ]
});
let code = format!(
r#"
-//- rust-project.json
+//- /rust-project.json
{PROJECT}
-//- src/lib.rs
+//- /src/lib.rs
mod bar;
fn main() {{}}
partial_result_params: PartialResultParams::default(),
work_done_progress_params: WorkDoneProgressParams::default(),
},
- json!([
- {
- "command": {
- "arguments": [
+ json!([{
+ "edit": {
+ "documentChanges": [
{
- "cursorPosition": null,
- "label": "create module",
- "workspaceEdit": {
- "documentChanges": [
- {
- "kind": "create",
- "uri": "file:///[..]/src/bar.rs"
- }
- ]
- }
+ "kind": "create",
+ "uri": "file://[..]/src/bar.rs"
}
- ],
- "command": "rust-analyzer.applySourceChange",
- "title": "create module"
+ ]
},
- "title": "create module"
- }
- ]),
+ "kind": "quickfix",
+ "title": "Create module"
+ }]),
);
server.request::<CodeActionRequest>(
}
let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
- let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
+ let libs: String = (0..10).map(|i| format!("//- /src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
let server = Project::with_fixture(&format!(
r#"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = "foo"
version = "0.0.0"
-//- src/lib.rs
+//- /src/lib.rs
{}
{}
text_document: server.doc_id("src/m0.rs"),
position: Position { line: 0, character: 5 },
},
- json!({
- "cursorPosition": {
- "position": { "character": 4, "line": 1 },
- "textDocument": { "uri": "file:///[..]src/m0.rs" }
- },
- "label": "on enter",
- "workspaceEdit": {
- "documentChanges": [
- {
- "edits": [
- {
- "newText": "\n/// ",
- "range": {
- "end": { "character": 5, "line": 0 },
- "start": { "character": 5, "line": 0 }
- }
- }
- ],
- "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null }
- }
- ]
- }
- }),
+ json!([{
+ "insertTextFormat": 2,
+ "newText": "\n/// $0",
+ "range": {
+ "end": { "character": 5, "line": 0 },
+ "start": { "character": 5, "line": 0 }
+ }
+ }]),
);
let elapsed = start.elapsed();
assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed);
let server = Project::with_fixture(
&"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = \"foo\"
version = \"0.0.0\"
-//- src/main.rs
+//- /src/main.rs
/// Some Docs\r\nfn main() {}
",
)
text_document: server.doc_id("src/main.rs"),
position: Position { line: 0, character: 8 },
},
- json!({
- "cursorPosition": {
- "position": { "line": 1, "character": 4 },
- "textDocument": { "uri": "file:///[..]src/main.rs" }
- },
- "label": "on enter",
- "workspaceEdit": {
- "documentChanges": [
- {
- "edits": [
- {
- "newText": "\r\n/// ",
- "range": {
- "end": { "line": 0, "character": 8 },
- "start": { "line": 0, "character": 8 }
- }
- }
- ],
- "textDocument": { "uri": "file:///[..]src/main.rs", "version": null }
- }
- ]
- }
- }),
+ json!([{
+ "insertTextFormat": 2,
+ "newText": "\r\n/// $0",
+ "range": {
+ "end": { "line": 0, "character": 8 },
+ "start": { "line": 0, "character": 8 }
+ }
+ }]),
);
}
#[test]
-fn resolve_include_concat_env() {
+fn out_dirs_check() {
if skip_slow_tests() {
return;
}
let server = Project::with_fixture(
r###"
-//- Cargo.toml
+//- /Cargo.toml
[package]
name = "foo"
version = "0.0.0"
-//- build.rs
+//- /build.rs
use std::{env, fs, path::Path};
fn main() {
r#"pub fn message() -> &'static str { "Hello, World!" }"#,
)
.unwrap();
+ println!("cargo:rustc-cfg=atom_cfg");
+ println!("cargo:rustc-cfg=featlike=\"set\"");
println!("cargo:rerun-if-changed=build.rs");
}
-//- src/main.rs
+//- /src/main.rs
+#[rustc_builtin_macro] macro_rules! include {}
+#[rustc_builtin_macro] macro_rules! concat {}
+#[rustc_builtin_macro] macro_rules! env {}
+
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
-fn main() { message(); }
+#[cfg(atom_cfg)]
+struct A;
+#[cfg(bad_atom_cfg)]
+struct A;
+#[cfg(featlike = "set")]
+struct B;
+#[cfg(featlike = "not_set")]
+struct B;
+
+fn main() {
+ let va = A;
+ let vb = B;
+ let should_be_str = message();
+}
"###,
)
.with_config(|config| {
})
.server();
server.wait_until_workspace_is_loaded();
- let res = server.send_request::<GotoDefinition>(GotoDefinitionParams {
+ let res = server.send_request::<HoverRequest>(HoverParams {
text_document_position_params: TextDocumentPositionParams::new(
server.doc_id("src/main.rs"),
- Position::new(2, 15),
+ Position::new(18, 10),
),
work_done_progress_params: Default::default(),
- partial_result_params: Default::default(),
});
- assert!(format!("{}", res).contains("hello.rs"));
+ assert!(res.to_string().contains("&str"));
+ server.request::<GotoTypeDefinition>(
+ GotoDefinitionParams {
+ text_document_position_params: TextDocumentPositionParams::new(
+ server.doc_id("src/main.rs"),
+ Position::new(16, 9),
+ ),
+ work_done_progress_params: Default::default(),
+ partial_result_params: Default::default(),
+ },
+ json!([{
+ "originSelectionRange": {
+ "end": { "character": 10, "line": 16 },
+ "start": { "character": 8, "line": 16 }
+ },
+ "targetRange": {
+ "end": { "character": 9, "line": 7 },
+ "start": { "character": 0, "line": 6 }
+ },
+ "targetSelectionRange": {
+ "end": { "character": 8, "line": 7 },
+ "start": { "character": 7, "line": 7 }
+ },
+ "targetUri": "file:///[..]src/main.rs"
+ }]),
+ );
+ server.request::<GotoTypeDefinition>(
+ GotoDefinitionParams {
+ text_document_position_params: TextDocumentPositionParams::new(
+ server.doc_id("src/main.rs"),
+ Position::new(17, 9),
+ ),
+ work_done_progress_params: Default::default(),
+ partial_result_params: Default::default(),
+ },
+ json!([{
+ "originSelectionRange": {
+ "end": { "character": 10, "line": 17 },
+ "start": { "character": 8, "line": 17 }
+ },
+ "targetRange": {
+ "end": { "character": 9, "line": 11 },
+ "start": { "character": 0, "line":10 }
+ },
+ "targetSelectionRange": {
+ "end": { "character": 8, "line": 11 },
+ "start": { "character": 7, "line": 11 }
+ },
+ "targetUri": "file:///[..]src/main.rs"
+ }]),
+ );
}
#[test]
}
let server = Project::with_fixture(
r###"
-//- foo/Cargo.toml
+//- /foo/Cargo.toml
[package]
name = "foo"
version = "0.0.0"
[dependencies]
bar = {path = "../bar"}
-//- foo/src/main.rs
+//- /foo/src/main.rs
use bar::Bar;
trait Bar {
fn bar();
Foo::bar();
}
-//- bar/Cargo.toml
+//- /bar/Cargo.toml
[package]
name = "bar"
version = "0.0.0"
[lib]
proc-macro = true
-//- bar/src/lib.rs
+//- /bar/src/lib.rs
extern crate proc_macro;
use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
macro_rules! t {
});
let value = res.get("contents").unwrap().get("value").unwrap().to_string();
- assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#)
+ assert_eq!(value, r#""```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#)
}