Skip to content

Commit f137b3a

Browse files
bors[bot]matklad
andauthored
Merge #4709
4709: Minor r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 61e8f39 + 31f2826 commit f137b3a

File tree

3 files changed

+125
-124
lines changed

3 files changed

+125
-124
lines changed

crates/rust-analyzer/src/cargo_target_spec.rs

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! See `CargoTargetSpec`
22
3+
use ra_cfg::CfgExpr;
34
use ra_ide::{FileId, RunnableKind, TestId};
45
use ra_project_model::{self, ProjectWorkspace, TargetKind};
56

67
use crate::{world::WorldSnapshot, Result};
7-
use ra_syntax::SmolStr;
88

99
/// Abstract representation of Cargo target.
1010
///
@@ -21,7 +21,7 @@ impl CargoTargetSpec {
2121
pub(crate) fn runnable_args(
2222
spec: Option<CargoTargetSpec>,
2323
kind: &RunnableKind,
24-
features_needed: &Vec<SmolStr>,
24+
cfgs: &[CfgExpr],
2525
) -> Result<(Vec<String>, Vec<String>)> {
2626
let mut args = Vec::new();
2727
let mut extra_args = Vec::new();
@@ -76,10 +76,14 @@ impl CargoTargetSpec {
7676
}
7777
}
7878

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 {
8084
args.push("--features".to_string());
81-
args.push(feature.to_string());
82-
});
85+
args.push(feature);
86+
}
8387

8488
Ok((args, extra_args))
8589
}
@@ -140,3 +144,74 @@ impl CargoTargetSpec {
140144
}
141145
}
142146
}
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+
}

crates/rust-analyzer/src/main_loop/handlers.rs

Lines changed: 4 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@ use lsp_types::{
1717
SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult,
1818
SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit,
1919
};
20-
use ra_cfg::CfgExpr;
2120
use ra_ide::{
22-
FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope,
23-
TextEdit,
21+
FileId, FilePosition, FileRange, Query, RangeInfo, RunnableKind, SearchScope, TextEdit,
2422
};
2523
use ra_prof::profile;
2624
use ra_project_model::TargetKind;
27-
use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize};
25+
use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize};
2826
use rustc_hash::FxHashMap;
2927
use serde::{Deserialize, Serialize};
3028
use serde_json::to_value;
@@ -416,7 +414,7 @@ pub fn handle_runnables(
416414
}
417415
}
418416
}
419-
res.push(to_lsp_runnable(&world, file_id, runnable)?);
417+
res.push(to_proto::runnable(&world, file_id, runnable)?);
420418
}
421419

422420
// Add `cargo check` and `cargo test` for the whole package
@@ -784,7 +782,7 @@ pub fn handle_code_lens(
784782
}
785783
};
786784

787-
let mut r = to_lsp_runnable(&world, file_id, runnable)?;
785+
let mut r = to_proto::runnable(&world, file_id, runnable)?;
788786
if world.config.lens.run {
789787
let lens = CodeLens {
790788
range: r.range,
@@ -959,65 +957,6 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia
959957
Ok(DiagnosticTask::SetNative(file_id, diagnostics))
960958
}
961959

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-
986-
Ok(lsp_ext::Runnable {
987-
range: to_proto::range(&line_index, runnable.range),
988-
label,
989-
kind: lsp_ext::RunnableKind::Cargo,
990-
args,
991-
extra_args,
992-
env: {
993-
let mut m = FxHashMap::default();
994-
m.insert("RUST_BACKTRACE".to_string(), "short".to_string());
995-
m
996-
},
997-
cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()),
998-
})
999-
}
1000-
1001-
/// Fill minimal features needed
1002-
fn collect_minimal_features_needed(cfg_expr: &CfgExpr, features: &mut Vec<SmolStr>) {
1003-
match cfg_expr {
1004-
CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()),
1005-
CfgExpr::All(preds) => {
1006-
preds.iter().for_each(|cfg| collect_minimal_features_needed(cfg, features));
1007-
}
1008-
CfgExpr::Any(preds) => {
1009-
for cfg in preds {
1010-
let len_features = features.len();
1011-
collect_minimal_features_needed(cfg, features);
1012-
if len_features != features.len() {
1013-
break;
1014-
}
1015-
}
1016-
}
1017-
_ => {}
1018-
}
1019-
}
1020-
1021960
pub fn handle_inlay_hints(
1022961
world: WorldSnapshot,
1023962
params: InlayHintsParams,
@@ -1154,54 +1093,3 @@ pub fn handle_semantic_tokens_range(
11541093
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
11551094
Ok(Some(semantic_tokens.into()))
11561095
}
1157-
1158-
#[cfg(test)]
1159-
mod tests {
1160-
use super::*;
1161-
1162-
use mbe::{ast_to_token_tree, TokenMap};
1163-
use ra_cfg::parse_cfg;
1164-
use ra_syntax::{
1165-
ast::{self, AstNode},
1166-
SmolStr,
1167-
};
1168-
1169-
fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) {
1170-
let source_file = ast::SourceFile::parse(input).ok().unwrap();
1171-
let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1172-
ast_to_token_tree(&tt).unwrap()
1173-
}
1174-
1175-
#[test]
1176-
fn test_cfg_expr_minimal_features_needed() {
1177-
let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#);
1178-
let cfg_expr = parse_cfg(&subtree);
1179-
let mut min_features = vec![];
1180-
collect_minimal_features_needed(&cfg_expr, &mut min_features);
1181-
1182-
assert_eq!(min_features, vec![SmolStr::new("baz")]);
1183-
1184-
let (subtree, _) =
1185-
get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#);
1186-
let cfg_expr = parse_cfg(&subtree);
1187-
1188-
let mut min_features = vec![];
1189-
collect_minimal_features_needed(&cfg_expr, &mut min_features);
1190-
assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]);
1191-
1192-
let (subtree, _) =
1193-
get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#);
1194-
let cfg_expr = parse_cfg(&subtree);
1195-
1196-
let mut min_features = vec![];
1197-
collect_minimal_features_needed(&cfg_expr, &mut min_features);
1198-
assert_eq!(min_features, vec![SmolStr::new("baz")]);
1199-
1200-
let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#);
1201-
let cfg_expr = parse_cfg(&subtree);
1202-
1203-
let mut min_features = vec![];
1204-
collect_minimal_features_needed(&cfg_expr, &mut min_features);
1205-
assert!(min_features.is_empty());
1206-
}
1207-
}

crates/rust-analyzer/src/to_proto.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ use ra_db::{FileId, FileRange};
33
use ra_ide::{
44
Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind,
55
FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel,
6-
InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity,
7-
SourceChange, SourceFileEdit, TextEdit,
6+
InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Runnable,
7+
RunnableKind, Severity, SourceChange, SourceFileEdit, TextEdit,
88
};
99
use ra_syntax::{SyntaxKind, TextRange, TextSize};
1010
use ra_vfs::LineEndings;
11+
use rustc_hash::FxHashMap;
1112

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+
};
1316

1417
pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
1518
let line_col = line_index.line_col(offset);
@@ -627,3 +630,38 @@ pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_e
627630
};
628631
Ok(res)
629632
}
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+
}

0 commit comments

Comments
 (0)