diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/snapshots/highlight_strings.html | 1 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting/tests.rs | 1 | ||||
-rw-r--r-- | crates/ra_proc_macro_srv/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_proc_macro_srv/src/tests/utils.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/tokens.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 85 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_ext.rs | 11 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 123 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 44 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/main.rs | 10 |
10 files changed, 146 insertions, 138 deletions
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 326744361..41cddd0ff 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html | |||
@@ -52,6 +52,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
52 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// => "test"</span> | 52 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// => "test"</span> |
53 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// => "2 1"</span> | 53 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// => "2 1"</span> |
54 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// => "a 3 b"</span> | 54 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// => "a 3 b"</span> |
55 | <span class="macro">println!</span>(<span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span>, <span class="numeric_literal">2</span>); <span class="comment">// => "{2}"</span> | ||
55 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 56 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
56 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); | 57 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); |
57 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); | 58 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); |
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index eb43a23da..7dc229cab 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs | |||
@@ -218,6 +218,7 @@ fn main() { | |||
218 | println!("{argument}", argument = "test"); // => "test" | 218 | println!("{argument}", argument = "test"); // => "test" |
219 | println!("{name} {}", 1, name = 2); // => "2 1" | 219 | println!("{name} {}", 1, name = 2); // => "2 1" |
220 | println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" | 220 | println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" |
221 | println!("{{{}}}", 2); // => "{2}" | ||
221 | println!("Hello {:5}!", "x"); | 222 | println!("Hello {:5}!", "x"); |
222 | println!("Hello {:1$}!", "x", 5); | 223 | println!("Hello {:1$}!", "x", 5); |
223 | println!("Hello {1:0$}!", 5, "x"); | 224 | println!("Hello {1:0$}!", 5, "x"); |
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml index bb3003278..582102945 100644 --- a/crates/ra_proc_macro_srv/Cargo.toml +++ b/crates/ra_proc_macro_srv/Cargo.toml | |||
@@ -22,3 +22,4 @@ cargo_metadata = "0.10.0" | |||
22 | difference = "2.0.0" | 22 | difference = "2.0.0" |
23 | # used as proc macro test target | 23 | # used as proc macro test target |
24 | serde_derive = "1.0.106" | 24 | serde_derive = "1.0.106" |
25 | ra_toolchain = { path = "../ra_toolchain" } | ||
diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs index 84348b5de..8d85f2d8a 100644 --- a/crates/ra_proc_macro_srv/src/tests/utils.rs +++ b/crates/ra_proc_macro_srv/src/tests/utils.rs | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | use crate::dylib; | 3 | use crate::dylib; |
4 | use crate::ProcMacroSrv; | 4 | use crate::ProcMacroSrv; |
5 | pub use difference::Changeset as __Changeset; | ||
6 | use ra_proc_macro::ListMacrosTask; | 5 | use ra_proc_macro::ListMacrosTask; |
7 | use std::str::FromStr; | 6 | use std::str::FromStr; |
8 | use test_utils::assert_eq_text; | 7 | use test_utils::assert_eq_text; |
@@ -13,7 +12,7 @@ mod fixtures { | |||
13 | 12 | ||
14 | // Use current project metadata to get the proc-macro dylib path | 13 | // Use current project metadata to get the proc-macro dylib path |
15 | pub fn dylib_path(crate_name: &str, version: &str) -> std::path::PathBuf { | 14 | pub fn dylib_path(crate_name: &str, version: &str) -> std::path::PathBuf { |
16 | let command = Command::new("cargo") | 15 | let command = Command::new(ra_toolchain::cargo()) |
17 | .args(&["check", "--message-format", "json"]) | 16 | .args(&["check", "--message-format", "json"]) |
18 | .output() | 17 | .output() |
19 | .unwrap() | 18 | .unwrap() |
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 3cd6d99c3..04b0a4480 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -418,14 +418,9 @@ pub trait HasFormatSpecifier: AstToken { | |||
418 | 418 | ||
419 | let mut cloned = chars.clone().take(2); | 419 | let mut cloned = chars.clone().take(2); |
420 | let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); | 420 | let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); |
421 | let second = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); | ||
422 | if first != Some('}') { | 421 | if first != Some('}') { |
423 | continue; | 422 | continue; |
424 | } | 423 | } |
425 | if second == Some('}') { | ||
426 | // Escaped format end specifier, `}}` | ||
427 | continue; | ||
428 | } | ||
429 | skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); | 424 | skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); |
430 | } | 425 | } |
431 | _ => { | 426 | _ => { |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 441fb61df..008518a08 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! See `CargoTargetSpec` | 1 | //! See `CargoTargetSpec` |
2 | 2 | ||
3 | use ra_cfg::CfgExpr; | ||
3 | use ra_ide::{FileId, RunnableKind, TestId}; | 4 | use ra_ide::{FileId, RunnableKind, TestId}; |
4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; | 5 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; |
5 | 6 | ||
6 | use crate::{world::WorldSnapshot, Result}; | 7 | use crate::{world::WorldSnapshot, Result}; |
7 | use ra_syntax::SmolStr; | ||
8 | 8 | ||
9 | /// Abstract representation of Cargo target. | 9 | /// Abstract representation of Cargo target. |
10 | /// | 10 | /// |
@@ -21,7 +21,7 @@ impl CargoTargetSpec { | |||
21 | pub(crate) fn runnable_args( | 21 | pub(crate) fn runnable_args( |
22 | spec: Option<CargoTargetSpec>, | 22 | spec: Option<CargoTargetSpec>, |
23 | kind: &RunnableKind, | 23 | kind: &RunnableKind, |
24 | features_needed: &Vec<SmolStr>, | 24 | cfgs: &[CfgExpr], |
25 | ) -> Result<(Vec<String>, Vec<String>)> { | 25 | ) -> Result<(Vec<String>, Vec<String>)> { |
26 | let mut args = Vec::new(); | 26 | let mut args = Vec::new(); |
27 | let mut extra_args = Vec::new(); | 27 | let mut extra_args = Vec::new(); |
@@ -76,10 +76,14 @@ impl CargoTargetSpec { | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | features_needed.iter().for_each(|feature| { | 79 | let mut features = Vec::new(); |
80 | for cfg in cfgs { | ||
81 | required_features(cfg, &mut features); | ||
82 | } | ||
83 | for feature in features { | ||
80 | args.push("--features".to_string()); | 84 | args.push("--features".to_string()); |
81 | args.push(feature.to_string()); | 85 | args.push(feature); |
82 | }); | 86 | } |
83 | 87 | ||
84 | Ok((args, extra_args)) | 88 | Ok((args, extra_args)) |
85 | } | 89 | } |
@@ -140,3 +144,74 @@ impl CargoTargetSpec { | |||
140 | } | 144 | } |
141 | } | 145 | } |
142 | } | 146 | } |
147 | |||
148 | /// Fill minimal features needed | ||
149 | fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) { | ||
150 | match cfg_expr { | ||
151 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.to_string()), | ||
152 | CfgExpr::All(preds) => { | ||
153 | preds.iter().for_each(|cfg| required_features(cfg, features)); | ||
154 | } | ||
155 | CfgExpr::Any(preds) => { | ||
156 | for cfg in preds { | ||
157 | let len_features = features.len(); | ||
158 | required_features(cfg, features); | ||
159 | if len_features != features.len() { | ||
160 | break; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | _ => {} | ||
165 | } | ||
166 | } | ||
167 | |||
168 | #[cfg(test)] | ||
169 | mod tests { | ||
170 | use super::*; | ||
171 | |||
172 | use mbe::{ast_to_token_tree, TokenMap}; | ||
173 | use ra_cfg::parse_cfg; | ||
174 | use ra_syntax::{ | ||
175 | ast::{self, AstNode}, | ||
176 | SmolStr, | ||
177 | }; | ||
178 | |||
179 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | ||
180 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
181 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
182 | ast_to_token_tree(&tt).unwrap() | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn test_cfg_expr_minimal_features_needed() { | ||
187 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
188 | let cfg_expr = parse_cfg(&subtree); | ||
189 | let mut min_features = vec![]; | ||
190 | required_features(&cfg_expr, &mut min_features); | ||
191 | |||
192 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
193 | |||
194 | let (subtree, _) = | ||
195 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
196 | let cfg_expr = parse_cfg(&subtree); | ||
197 | |||
198 | let mut min_features = vec![]; | ||
199 | required_features(&cfg_expr, &mut min_features); | ||
200 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | ||
201 | |||
202 | let (subtree, _) = | ||
203 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | ||
204 | let cfg_expr = parse_cfg(&subtree); | ||
205 | |||
206 | let mut min_features = vec![]; | ||
207 | required_features(&cfg_expr, &mut min_features); | ||
208 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
209 | |||
210 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | ||
211 | let cfg_expr = parse_cfg(&subtree); | ||
212 | |||
213 | let mut min_features = vec![]; | ||
214 | required_features(&cfg_expr, &mut min_features); | ||
215 | assert!(min_features.is_empty()); | ||
216 | } | ||
217 | } | ||
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index acb1dacb6..173c23b9e 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -121,12 +121,21 @@ pub struct RunnablesParams { | |||
121 | pub position: Option<Position>, | 121 | pub position: Option<Position>, |
122 | } | 122 | } |
123 | 123 | ||
124 | // Must strictly correspond to the executable name | ||
125 | #[derive(Serialize, Deserialize, Debug)] | ||
126 | #[serde(rename_all = "lowercase")] | ||
127 | pub enum RunnableKind { | ||
128 | Cargo, | ||
129 | Rustc, | ||
130 | Rustup, | ||
131 | } | ||
132 | |||
124 | #[derive(Deserialize, Serialize, Debug)] | 133 | #[derive(Deserialize, Serialize, Debug)] |
125 | #[serde(rename_all = "camelCase")] | 134 | #[serde(rename_all = "camelCase")] |
126 | pub struct Runnable { | 135 | pub struct Runnable { |
127 | pub range: Range, | 136 | pub range: Range, |
128 | pub label: String, | 137 | pub label: String, |
129 | pub bin: String, | 138 | pub kind: RunnableKind, |
130 | pub args: Vec<String>, | 139 | pub args: Vec<String>, |
131 | pub extra_args: Vec<String>, | 140 | pub extra_args: Vec<String>, |
132 | pub env: FxHashMap<String, String>, | 141 | pub env: FxHashMap<String, String>, |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 1f910ff82..410c654ab 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -17,14 +17,12 @@ use lsp_types::{ | |||
17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, | 17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, |
18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, | 18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_cfg::CfgExpr; | ||
21 | use ra_ide::{ | 20 | use ra_ide::{ |
22 | FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, | 21 | FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit, |
23 | TextEdit, | ||
24 | }; | 22 | }; |
25 | use ra_prof::profile; | 23 | use ra_prof::profile; |
26 | use ra_project_model::TargetKind; | 24 | use ra_project_model::TargetKind; |
27 | use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize}; | 25 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; |
28 | use rustc_hash::FxHashMap; | 26 | use rustc_hash::FxHashMap; |
29 | use serde::{Deserialize, Serialize}; | 27 | use serde::{Deserialize, Serialize}; |
30 | use serde_json::to_value; | 28 | use serde_json::to_value; |
@@ -416,7 +414,7 @@ pub fn handle_runnables( | |||
416 | } | 414 | } |
417 | } | 415 | } |
418 | } | 416 | } |
419 | res.push(to_lsp_runnable(&world, file_id, runnable)?); | 417 | res.push(to_proto::runnable(&world, file_id, runnable)?); |
420 | } | 418 | } |
421 | 419 | ||
422 | // Add `cargo check` and `cargo test` for the whole package | 420 | // Add `cargo check` and `cargo test` for the whole package |
@@ -426,7 +424,7 @@ pub fn handle_runnables( | |||
426 | res.push(lsp_ext::Runnable { | 424 | res.push(lsp_ext::Runnable { |
427 | range: Default::default(), | 425 | range: Default::default(), |
428 | label: format!("cargo {} -p {}", cmd, spec.package), | 426 | label: format!("cargo {} -p {}", cmd, spec.package), |
429 | bin: "cargo".to_string(), | 427 | kind: lsp_ext::RunnableKind::Cargo, |
430 | args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], | 428 | args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], |
431 | extra_args: Vec::new(), | 429 | extra_args: Vec::new(), |
432 | env: FxHashMap::default(), | 430 | env: FxHashMap::default(), |
@@ -438,7 +436,7 @@ pub fn handle_runnables( | |||
438 | res.push(lsp_ext::Runnable { | 436 | res.push(lsp_ext::Runnable { |
439 | range: Default::default(), | 437 | range: Default::default(), |
440 | label: "cargo check --workspace".to_string(), | 438 | label: "cargo check --workspace".to_string(), |
441 | bin: "cargo".to_string(), | 439 | kind: lsp_ext::RunnableKind::Cargo, |
442 | args: vec!["check".to_string(), "--workspace".to_string()], | 440 | args: vec!["check".to_string(), "--workspace".to_string()], |
443 | extra_args: Vec::new(), | 441 | extra_args: Vec::new(), |
444 | env: FxHashMap::default(), | 442 | env: FxHashMap::default(), |
@@ -784,7 +782,7 @@ pub fn handle_code_lens( | |||
784 | } | 782 | } |
785 | }; | 783 | }; |
786 | 784 | ||
787 | let mut r = to_lsp_runnable(&world, file_id, runnable)?; | 785 | let mut r = to_proto::runnable(&world, file_id, runnable)?; |
788 | if world.config.lens.run { | 786 | if world.config.lens.run { |
789 | let lens = CodeLens { | 787 | let lens = CodeLens { |
790 | range: r.range, | 788 | range: r.range, |
@@ -959,64 +957,6 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia | |||
959 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) | 957 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) |
960 | } | 958 | } |
961 | 959 | ||
962 | fn to_lsp_runnable( | ||
963 | world: &WorldSnapshot, | ||
964 | file_id: FileId, | ||
965 | runnable: Runnable, | ||
966 | ) -> Result<lsp_ext::Runnable> { | ||
967 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
968 | let target = spec.as_ref().map(|s| s.target.clone()); | ||
969 | let mut features_needed = vec![]; | ||
970 | for cfg_expr in &runnable.cfg_exprs { | ||
971 | collect_minimal_features_needed(cfg_expr, &mut features_needed); | ||
972 | } | ||
973 | let (args, extra_args) = | ||
974 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &features_needed)?; | ||
975 | let line_index = world.analysis().file_line_index(file_id)?; | ||
976 | let label = match &runnable.kind { | ||
977 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
978 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
979 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
980 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
981 | RunnableKind::Bin => { | ||
982 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
983 | } | ||
984 | }; | ||
985 | Ok(lsp_ext::Runnable { | ||
986 | range: to_proto::range(&line_index, runnable.range), | ||
987 | label, | ||
988 | bin: "cargo".to_string(), | ||
989 | args, | ||
990 | extra_args, | ||
991 | env: { | ||
992 | let mut m = FxHashMap::default(); | ||
993 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | ||
994 | m | ||
995 | }, | ||
996 | cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), | ||
997 | }) | ||
998 | } | ||
999 | |||
1000 | /// Fill minimal features needed | ||
1001 | fn collect_minimal_features_needed(cfg_expr: &CfgExpr, features: &mut Vec<SmolStr>) { | ||
1002 | match cfg_expr { | ||
1003 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()), | ||
1004 | CfgExpr::All(preds) => { | ||
1005 | preds.iter().for_each(|cfg| collect_minimal_features_needed(cfg, features)); | ||
1006 | } | ||
1007 | CfgExpr::Any(preds) => { | ||
1008 | for cfg in preds { | ||
1009 | let len_features = features.len(); | ||
1010 | collect_minimal_features_needed(cfg, features); | ||
1011 | if len_features != features.len() { | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | } | ||
1016 | _ => {} | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | pub fn handle_inlay_hints( | 960 | pub fn handle_inlay_hints( |
1021 | world: WorldSnapshot, | 961 | world: WorldSnapshot, |
1022 | params: InlayHintsParams, | 962 | params: InlayHintsParams, |
@@ -1153,54 +1093,3 @@ pub fn handle_semantic_tokens_range( | |||
1153 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); | 1093 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); |
1154 | Ok(Some(semantic_tokens.into())) | 1094 | Ok(Some(semantic_tokens.into())) |
1155 | } | 1095 | } |
1156 | |||
1157 | #[cfg(test)] | ||
1158 | mod tests { | ||
1159 | use super::*; | ||
1160 | |||
1161 | use mbe::{ast_to_token_tree, TokenMap}; | ||
1162 | use ra_cfg::parse_cfg; | ||
1163 | use ra_syntax::{ | ||
1164 | ast::{self, AstNode}, | ||
1165 | SmolStr, | ||
1166 | }; | ||
1167 | |||
1168 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | ||
1169 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
1170 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1171 | ast_to_token_tree(&tt).unwrap() | ||
1172 | } | ||
1173 | |||
1174 | #[test] | ||
1175 | fn test_cfg_expr_minimal_features_needed() { | ||
1176 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
1177 | let cfg_expr = parse_cfg(&subtree); | ||
1178 | let mut min_features = vec![]; | ||
1179 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1180 | |||
1181 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
1182 | |||
1183 | let (subtree, _) = | ||
1184 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
1185 | let cfg_expr = parse_cfg(&subtree); | ||
1186 | |||
1187 | let mut min_features = vec![]; | ||
1188 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1189 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | ||
1190 | |||
1191 | let (subtree, _) = | ||
1192 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | ||
1193 | let cfg_expr = parse_cfg(&subtree); | ||
1194 | |||
1195 | let mut min_features = vec![]; | ||
1196 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1197 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
1198 | |||
1199 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | ||
1200 | let cfg_expr = parse_cfg(&subtree); | ||
1201 | |||
1202 | let mut min_features = vec![]; | ||
1203 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1204 | assert!(min_features.is_empty()); | ||
1205 | } | ||
1206 | } | ||
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 2fbbb4e63..66144fe24 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -3,13 +3,16 @@ use ra_db::{FileId, FileRange}; | |||
3 | use ra_ide::{ | 3 | use ra_ide::{ |
4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Runnable, |
7 | SourceChange, SourceFileEdit, TextEdit, | 7 | RunnableKind, Severity, SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
11 | use rustc_hash::FxHashMap; | ||
11 | 12 | ||
12 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; | 13 | use crate::{ |
14 | cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, | ||
15 | }; | ||
13 | 16 | ||
14 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { | 17 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { |
15 | let line_col = line_index.line_col(offset); | 18 | let line_col = line_index.line_col(offset); |
@@ -627,3 +630,38 @@ pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_e | |||
627 | }; | 630 | }; |
628 | Ok(res) | 631 | Ok(res) |
629 | } | 632 | } |
633 | |||
634 | pub(crate) fn runnable( | ||
635 | world: &WorldSnapshot, | ||
636 | file_id: FileId, | ||
637 | runnable: Runnable, | ||
638 | ) -> Result<lsp_ext::Runnable> { | ||
639 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
640 | let target = spec.as_ref().map(|s| s.target.clone()); | ||
641 | let (args, extra_args) = | ||
642 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; | ||
643 | let line_index = world.analysis().file_line_index(file_id)?; | ||
644 | let label = match &runnable.kind { | ||
645 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
646 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
647 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
648 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
649 | RunnableKind::Bin => { | ||
650 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
651 | } | ||
652 | }; | ||
653 | |||
654 | Ok(lsp_ext::Runnable { | ||
655 | range: range(&line_index, runnable.range), | ||
656 | label, | ||
657 | kind: lsp_ext::RunnableKind::Cargo, | ||
658 | args, | ||
659 | extra_args, | ||
660 | env: { | ||
661 | let mut m = FxHashMap::default(); | ||
662 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | ||
663 | m | ||
664 | }, | ||
665 | cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), | ||
666 | }) | ||
667 | } | ||
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 405ddb362..8b473ff74 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -79,7 +79,7 @@ fn foo() { | |||
79 | { | 79 | { |
80 | "args": [ "test" ], | 80 | "args": [ "test" ], |
81 | "extraArgs": [ "foo", "--nocapture" ], | 81 | "extraArgs": [ "foo", "--nocapture" ], |
82 | "bin": "cargo", | 82 | "kind": "cargo", |
83 | "env": { "RUST_BACKTRACE": "short" }, | 83 | "env": { "RUST_BACKTRACE": "short" }, |
84 | "cwd": null, | 84 | "cwd": null, |
85 | "label": "test foo", | 85 | "label": "test foo", |
@@ -91,7 +91,7 @@ fn foo() { | |||
91 | { | 91 | { |
92 | "args": ["check", "--workspace"], | 92 | "args": ["check", "--workspace"], |
93 | "extraArgs": [], | 93 | "extraArgs": [], |
94 | "bin": "cargo", | 94 | "kind": "cargo", |
95 | "env": {}, | 95 | "env": {}, |
96 | "cwd": null, | 96 | "cwd": null, |
97 | "label": "cargo check --workspace", | 97 | "label": "cargo check --workspace", |
@@ -141,7 +141,7 @@ fn main() {} | |||
141 | { | 141 | { |
142 | "args": [ "test", "--package", "foo", "--test", "spam" ], | 142 | "args": [ "test", "--package", "foo", "--test", "spam" ], |
143 | "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], | 143 | "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], |
144 | "bin": "cargo", | 144 | "kind": "cargo", |
145 | "env": { "RUST_BACKTRACE": "short" }, | 145 | "env": { "RUST_BACKTRACE": "short" }, |
146 | "label": "test test_eggs", | 146 | "label": "test test_eggs", |
147 | "range": { | 147 | "range": { |
@@ -153,7 +153,7 @@ fn main() {} | |||
153 | { | 153 | { |
154 | "args": [ "check", "--package", "foo" ], | 154 | "args": [ "check", "--package", "foo" ], |
155 | "extraArgs": [], | 155 | "extraArgs": [], |
156 | "bin": "cargo", | 156 | "kind": "cargo", |
157 | "env": {}, | 157 | "env": {}, |
158 | "label": "cargo check -p foo", | 158 | "label": "cargo check -p foo", |
159 | "range": { | 159 | "range": { |
@@ -165,7 +165,7 @@ fn main() {} | |||
165 | { | 165 | { |
166 | "args": [ "test", "--package", "foo" ], | 166 | "args": [ "test", "--package", "foo" ], |
167 | "extraArgs": [], | 167 | "extraArgs": [], |
168 | "bin": "cargo", | 168 | "kind": "cargo", |
169 | "env": {}, | 169 | "env": {}, |
170 | "label": "cargo test -p foo", | 170 | "label": "cargo test -p foo", |
171 | "range": { | 171 | "range": { |