diff options
-rw-r--r-- | crates/ra_cfg/src/cfg_expr.rs | 21 | ||||
-rw-r--r-- | crates/ra_cfg/src/lib.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_def/src/attr.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 7 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 56 |
6 files changed, 44 insertions, 67 deletions
diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs index 85b100c6a..f48928aee 100644 --- a/crates/ra_cfg/src/cfg_expr.rs +++ b/crates/ra_cfg/src/cfg_expr.rs | |||
@@ -5,7 +5,6 @@ | |||
5 | use std::slice::Iter as SliceIter; | 5 | use std::slice::Iter as SliceIter; |
6 | 6 | ||
7 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
8 | use tt::{Leaf, Subtree, TokenTree}; | ||
9 | 8 | ||
10 | #[derive(Debug, Clone, PartialEq, Eq)] | 9 | #[derive(Debug, Clone, PartialEq, Eq)] |
11 | pub enum CfgExpr { | 10 | pub enum CfgExpr { |
@@ -18,6 +17,9 @@ pub enum CfgExpr { | |||
18 | } | 17 | } |
19 | 18 | ||
20 | impl CfgExpr { | 19 | impl CfgExpr { |
20 | pub fn parse(tt: &tt::Subtree) -> CfgExpr { | ||
21 | next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) | ||
22 | } | ||
21 | /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. | 23 | /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. |
22 | pub fn fold(&self, query: &dyn Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> { | 24 | pub fn fold(&self, query: &dyn Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> { |
23 | match self { | 25 | match self { |
@@ -35,22 +37,18 @@ impl CfgExpr { | |||
35 | } | 37 | } |
36 | } | 38 | } |
37 | 39 | ||
38 | pub fn parse_cfg(tt: &Subtree) -> CfgExpr { | ||
39 | next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) | ||
40 | } | ||
41 | |||
42 | fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | 40 | fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { |
43 | let name = match it.next() { | 41 | let name = match it.next() { |
44 | None => return None, | 42 | None => return None, |
45 | Some(TokenTree::Leaf(Leaf::Ident(ident))) => ident.text.clone(), | 43 | Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(), |
46 | Some(_) => return Some(CfgExpr::Invalid), | 44 | Some(_) => return Some(CfgExpr::Invalid), |
47 | }; | 45 | }; |
48 | 46 | ||
49 | // Peek | 47 | // Peek |
50 | let ret = match it.as_slice().first() { | 48 | let ret = match it.as_slice().first() { |
51 | Some(TokenTree::Leaf(Leaf::Punct(punct))) if punct.char == '=' => { | 49 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '=' => { |
52 | match it.as_slice().get(1) { | 50 | match it.as_slice().get(1) { |
53 | Some(TokenTree::Leaf(Leaf::Literal(literal))) => { | 51 | Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { |
54 | it.next(); | 52 | it.next(); |
55 | it.next(); | 53 | it.next(); |
56 | // FIXME: escape? raw string? | 54 | // FIXME: escape? raw string? |
@@ -61,7 +59,7 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | |||
61 | _ => return Some(CfgExpr::Invalid), | 59 | _ => return Some(CfgExpr::Invalid), |
62 | } | 60 | } |
63 | } | 61 | } |
64 | Some(TokenTree::Subtree(subtree)) => { | 62 | Some(tt::TokenTree::Subtree(subtree)) => { |
65 | it.next(); | 63 | it.next(); |
66 | let mut sub_it = subtree.token_trees.iter(); | 64 | let mut sub_it = subtree.token_trees.iter(); |
67 | let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect(); | 65 | let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect(); |
@@ -76,7 +74,7 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | |||
76 | }; | 74 | }; |
77 | 75 | ||
78 | // Eat comma separator | 76 | // Eat comma separator |
79 | if let Some(TokenTree::Leaf(Leaf::Punct(punct))) = it.as_slice().first() { | 77 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = it.as_slice().first() { |
80 | if punct.char == ',' { | 78 | if punct.char == ',' { |
81 | it.next(); | 79 | it.next(); |
82 | } | 80 | } |
@@ -99,7 +97,8 @@ mod tests { | |||
99 | 97 | ||
100 | fn assert_parse_result(input: &str, expected: CfgExpr) { | 98 | fn assert_parse_result(input: &str, expected: CfgExpr) { |
101 | let (tt, _) = get_token_tree_generated(input); | 99 | let (tt, _) = get_token_tree_generated(input); |
102 | assert_eq!(parse_cfg(&tt), expected); | 100 | let cfg = CfgExpr::parse(&tt); |
101 | assert_eq!(cfg, expected); | ||
103 | } | 102 | } |
104 | 103 | ||
105 | #[test] | 104 | #[test] |
diff --git a/crates/ra_cfg/src/lib.rs b/crates/ra_cfg/src/lib.rs index f9c73ece1..cd5a0a7b6 100644 --- a/crates/ra_cfg/src/lib.rs +++ b/crates/ra_cfg/src/lib.rs | |||
@@ -5,7 +5,7 @@ mod cfg_expr; | |||
5 | use ra_syntax::SmolStr; | 5 | use ra_syntax::SmolStr; |
6 | use rustc_hash::FxHashSet; | 6 | use rustc_hash::FxHashSet; |
7 | 7 | ||
8 | pub use cfg_expr::{parse_cfg, CfgExpr}; | 8 | pub use cfg_expr::CfgExpr; |
9 | 9 | ||
10 | /// Configuration options used for conditional compilition on items with `cfg` attributes. | 10 | /// Configuration options used for conditional compilition on items with `cfg` attributes. |
11 | /// We have two kind of options in different namespaces: atomic options like `unix`, and | 11 | /// We have two kind of options in different namespaces: atomic options like `unix`, and |
@@ -31,18 +31,10 @@ impl CfgOptions { | |||
31 | }) | 31 | }) |
32 | } | 32 | } |
33 | 33 | ||
34 | pub fn is_cfg_enabled(&self, attr: &tt::Subtree) -> Option<bool> { | ||
35 | self.check(&parse_cfg(attr)) | ||
36 | } | ||
37 | |||
38 | pub fn insert_atom(&mut self, key: SmolStr) { | 34 | pub fn insert_atom(&mut self, key: SmolStr) { |
39 | self.atoms.insert(key); | 35 | self.atoms.insert(key); |
40 | } | 36 | } |
41 | 37 | ||
42 | pub fn remove_atom(&mut self, name: &str) { | ||
43 | self.atoms.remove(name); | ||
44 | } | ||
45 | |||
46 | pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { | 38 | pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { |
47 | self.key_values.insert((key, value)); | 39 | self.key_values.insert((key, value)); |
48 | } | 40 | } |
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index e228e2145..70ccd4305 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -5,7 +5,7 @@ use std::{ops, sync::Arc}; | |||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; | 6 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; |
7 | use mbe::ast_to_token_tree; | 7 | use mbe::ast_to_token_tree; |
8 | use ra_cfg::CfgOptions; | 8 | use ra_cfg::{CfgExpr, CfgOptions}; |
9 | use ra_syntax::{ | 9 | use ra_syntax::{ |
10 | ast::{self, AstNode, AttrsOwner}, | 10 | ast::{self, AstNode, AttrsOwner}, |
11 | SmolStr, | 11 | SmolStr, |
@@ -125,9 +125,12 @@ impl Attrs { | |||
125 | AttrQuery { attrs: self, key } | 125 | AttrQuery { attrs: self, key } |
126 | } | 126 | } |
127 | 127 | ||
128 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { | 128 | pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ { |
129 | // FIXME: handle cfg_attr :-) | 129 | // FIXME: handle cfg_attr :-) |
130 | self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false)) | 130 | self.by_key("cfg").tt_values().map(CfgExpr::parse) |
131 | } | ||
132 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { | ||
133 | self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false)) | ||
131 | } | 134 | } |
132 | } | 135 | } |
133 | 136 | ||
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 0994beec5..95a35a28d 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -168,8 +168,7 @@ fn runnable_fn( | |||
168 | }; | 168 | }; |
169 | 169 | ||
170 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); | 170 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); |
171 | let cfg_exprs = | 171 | let cfg_exprs = attrs.cfg().collect(); |
172 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | ||
173 | 172 | ||
174 | let nav = if let RunnableKind::DocTest { .. } = kind { | 173 | let nav = if let RunnableKind::DocTest { .. } = kind { |
175 | NavigationTarget::from_doc_commented( | 174 | NavigationTarget::from_doc_commented( |
@@ -242,9 +241,7 @@ fn runnable_mod( | |||
242 | .join("::"); | 241 | .join("::"); |
243 | 242 | ||
244 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module)); | 243 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module)); |
245 | let cfg_exprs = | 244 | let cfg_exprs = attrs.cfg().collect(); |
246 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | ||
247 | |||
248 | let nav = module_def.to_nav(sema.db); | 245 | let nav = module_def.to_nav(sema.db); |
249 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) | 246 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) |
250 | } | 247 | } |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 6da4d7928..8053712ff 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -15,6 +15,7 @@ use paths::{AbsPath, AbsPathBuf}; | |||
15 | use ra_cfg::CfgOptions; | 15 | use ra_cfg::CfgOptions; |
16 | use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId}; | 16 | use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId}; |
17 | use rustc_hash::{FxHashMap, FxHashSet}; | 17 | use rustc_hash::{FxHashMap, FxHashSet}; |
18 | use stdx::split_delim; | ||
18 | 19 | ||
19 | pub use crate::{ | 20 | pub use crate::{ |
20 | cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, | 21 | cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, |
@@ -529,11 +530,10 @@ fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { | |||
529 | match rustc_cfgs { | 530 | match rustc_cfgs { |
530 | Ok(rustc_cfgs) => { | 531 | Ok(rustc_cfgs) => { |
531 | for line in rustc_cfgs.lines() { | 532 | for line in rustc_cfgs.lines() { |
532 | match line.find('=') { | 533 | match split_delim(line, '=') { |
533 | None => cfg_options.insert_atom(line.into()), | 534 | None => cfg_options.insert_atom(line.into()), |
534 | Some(pos) => { | 535 | Some((key, value)) => { |
535 | let key = &line[..pos]; | 536 | let value = value.trim_matches('"'); |
536 | let value = line[pos + 1..].trim_matches('"'); | ||
537 | cfg_options.insert_key_value(key.into(), value.into()); | 537 | cfg_options.insert_key_value(key.into(), value.into()); |
538 | } | 538 | } |
539 | } | 539 | } |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 318399624..03c41263a 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -177,49 +177,35 @@ fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) { | |||
177 | mod tests { | 177 | mod tests { |
178 | use super::*; | 178 | use super::*; |
179 | 179 | ||
180 | use mbe::{ast_to_token_tree, TokenMap}; | 180 | use mbe::ast_to_token_tree; |
181 | use ra_cfg::parse_cfg; | 181 | use ra_cfg::CfgExpr; |
182 | use ra_syntax::{ | 182 | use ra_syntax::{ |
183 | ast::{self, AstNode}, | 183 | ast::{self, AstNode}, |
184 | SmolStr, | 184 | SmolStr, |
185 | }; | 185 | }; |
186 | 186 | ||
187 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | 187 | fn check(cfg: &str, expected_features: &[&str]) { |
188 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | 188 | let cfg_expr = { |
189 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | 189 | let source_file = ast::SourceFile::parse(cfg).ok().unwrap(); |
190 | ast_to_token_tree(&tt).unwrap() | 190 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); |
191 | } | 191 | let (tt, _) = ast_to_token_tree(&tt).unwrap(); |
192 | 192 | CfgExpr::parse(&tt) | |
193 | #[test] | 193 | }; |
194 | fn test_cfg_expr_minimal_features_needed() { | ||
195 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
196 | let cfg_expr = parse_cfg(&subtree); | ||
197 | let mut min_features = vec![]; | ||
198 | required_features(&cfg_expr, &mut min_features); | ||
199 | |||
200 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
201 | |||
202 | let (subtree, _) = | ||
203 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
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"), SmolStr::new("foo")]); | ||
209 | 194 | ||
210 | let (subtree, _) = | 195 | let mut features = vec![]; |
211 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | 196 | required_features(&cfg_expr, &mut features); |
212 | let cfg_expr = parse_cfg(&subtree); | ||
213 | 197 | ||
214 | let mut min_features = vec![]; | 198 | let expected_features = |
215 | required_features(&cfg_expr, &mut min_features); | 199 | expected_features.iter().map(|&it| SmolStr::new(it)).collect::<Vec<_>>(); |
216 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
217 | 200 | ||
218 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | 201 | assert_eq!(features, expected_features); |
219 | let cfg_expr = parse_cfg(&subtree); | 202 | } |
220 | 203 | ||
221 | let mut min_features = vec![]; | 204 | #[test] |
222 | required_features(&cfg_expr, &mut min_features); | 205 | fn test_cfg_expr_minimal_features_needed() { |
223 | assert!(min_features.is_empty()); | 206 | check(r#"#![cfg(feature = "baz")]"#, &["baz"]); |
207 | check(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#, &["baz", "foo"]); | ||
208 | check(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#, &["baz"]); | ||
209 | check(r#"#![cfg(foo)]"#, &[]); | ||
224 | } | 210 | } |
225 | } | 211 | } |