aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_cfg/src/cfg_expr.rs21
-rw-r--r--crates/ra_cfg/src/lib.rs10
-rw-r--r--crates/ra_hir_def/src/attr.rs9
-rw-r--r--crates/ra_ide/src/runnables.rs7
-rw-r--r--crates/ra_project_model/src/lib.rs8
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs56
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 @@
5use std::slice::Iter as SliceIter; 5use std::slice::Iter as SliceIter;
6 6
7use ra_syntax::SmolStr; 7use ra_syntax::SmolStr;
8use tt::{Leaf, Subtree, TokenTree};
9 8
10#[derive(Debug, Clone, PartialEq, Eq)] 9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum CfgExpr { 10pub enum CfgExpr {
@@ -18,6 +17,9 @@ pub enum CfgExpr {
18} 17}
19 18
20impl CfgExpr { 19impl 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
38pub fn parse_cfg(tt: &Subtree) -> CfgExpr {
39 next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
40}
41
42fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { 40fn 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;
5use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7 7
8pub use cfg_expr::{parse_cfg, CfgExpr}; 8pub 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};
5use either::Either; 5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile}; 6use hir_expand::{hygiene::Hygiene, AstId, InFile};
7use mbe::ast_to_token_tree; 7use mbe::ast_to_token_tree;
8use ra_cfg::CfgOptions; 8use ra_cfg::{CfgExpr, CfgOptions};
9use ra_syntax::{ 9use 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};
15use ra_cfg::CfgOptions; 15use ra_cfg::CfgOptions;
16use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId}; 16use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId};
17use rustc_hash::{FxHashMap, FxHashSet}; 17use rustc_hash::{FxHashMap, FxHashSet};
18use stdx::split_delim;
18 19
19pub use crate::{ 20pub 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>) {
177mod tests { 177mod 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}