aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs1
-rw-r--r--crates/ra_proc_macro_srv/Cargo.toml1
-rw-r--r--crates/ra_proc_macro_srv/src/tests/utils.rs3
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs5
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs85
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs11
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs123
-rw-r--r--crates/rust-analyzer/src/to_proto.rs44
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs10
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">// =&gt; "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">// =&gt; "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">// =&gt; "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">// =&gt; "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">// =&gt; "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">// =&gt; "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">// =&gt; "{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"
22difference = "2.0.0" 22difference = "2.0.0"
23# used as proc macro test target 23# used as proc macro test target
24serde_derive = "1.0.106" 24serde_derive = "1.0.106"
25ra_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
3use crate::dylib; 3use crate::dylib;
4use crate::ProcMacroSrv; 4use crate::ProcMacroSrv;
5pub use difference::Changeset as __Changeset;
6use ra_proc_macro::ListMacrosTask; 5use ra_proc_macro::ListMacrosTask;
7use std::str::FromStr; 6use std::str::FromStr;
8use test_utils::assert_eq_text; 7use 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
3use ra_cfg::CfgExpr;
3use ra_ide::{FileId, RunnableKind, TestId}; 4use ra_ide::{FileId, RunnableKind, TestId};
4use ra_project_model::{self, ProjectWorkspace, TargetKind}; 5use ra_project_model::{self, ProjectWorkspace, TargetKind};
5 6
6use crate::{world::WorldSnapshot, Result}; 7use crate::{world::WorldSnapshot, Result};
7use 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
149fn 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)]
169mod 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")]
127pub 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")]
126pub struct Runnable { 135pub 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};
20use ra_cfg::CfgExpr;
21use ra_ide::{ 20use ra_ide::{
22 FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, 21 FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit,
23 TextEdit,
24}; 22};
25use ra_prof::profile; 23use ra_prof::profile;
26use ra_project_model::TargetKind; 24use ra_project_model::TargetKind;
27use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize}; 25use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize};
28use rustc_hash::FxHashMap; 26use rustc_hash::FxHashMap;
29use serde::{Deserialize, Serialize}; 27use serde::{Deserialize, Serialize};
30use serde_json::to_value; 28use 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
962fn 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
1001fn 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
1020pub fn handle_inlay_hints( 960pub 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)]
1158mod 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};
3use ra_ide::{ 3use 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};
9use ra_syntax::{SyntaxKind, TextRange, TextSize}; 9use ra_syntax::{SyntaxKind, TextRange, TextSize};
10use ra_vfs::LineEndings; 10use ra_vfs::LineEndings;
11use rustc_hash::FxHashMap;
11 12
12use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; 13use crate::{
14 cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result,
15};
13 16
14pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { 17pub(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
634pub(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": {