From c6143742bd4e625d391ac3ea860be7578ab9f53f Mon Sep 17 00:00:00 2001 From: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> Date: Thu, 21 May 2020 10:48:42 +0200 Subject: add support of feature flag for runnables #4464 Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> --- crates/ra_cfg/src/cfg_expr.rs | 68 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) (limited to 'crates/ra_cfg') diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs index 39d71851c..a4b201e0e 100644 --- a/crates/ra_cfg/src/cfg_expr.rs +++ b/crates/ra_cfg/src/cfg_expr.rs @@ -33,6 +33,36 @@ impl CfgExpr { CfgExpr::Not(pred) => pred.fold(query).map(|s| !s), } } + + /// Return minimal features needed + pub fn minimal_features_needed(&self) -> Option> { + let mut features = vec![]; + self.collect_minimal_features_needed(&mut features); + if features.is_empty() { + None + } else { + Some(features) + } + } + + fn collect_minimal_features_needed(&self, features: &mut Vec) { + match self { + CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()), + CfgExpr::All(preds) => { + preds.iter().for_each(|cfg| cfg.collect_minimal_features_needed(features)); + } + CfgExpr::Any(preds) => { + for cfg in preds { + let len_features = features.len(); + cfg.collect_minimal_features_needed(features); + if len_features != features.len() { + break; + } + } + } + _ => {} + } + } } pub fn parse_cfg(tt: &Subtree) -> CfgExpr { @@ -88,13 +118,17 @@ fn next_cfg_expr(it: &mut SliceIter) -> Option { mod tests { use super::*; - use mbe::ast_to_token_tree; + use mbe::{ast_to_token_tree, TokenMap}; use ra_syntax::ast::{self, AstNode}; - fn assert_parse_result(input: &str, expected: CfgExpr) { + fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { let source_file = ast::SourceFile::parse(input).ok().unwrap(); let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let (tt, _) = ast_to_token_tree(&tt).unwrap(); + ast_to_token_tree(&tt).unwrap() + } + + fn assert_parse_result(input: &str, expected: CfgExpr) { + let (tt, _) = get_token_tree_generated(input); assert_eq!(parse_cfg(&tt), expected); } @@ -129,4 +163,32 @@ mod tests { ]), ); } + + #[test] + fn test_cfg_expr_minimal_features_needed() { + let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); + let cfg_expr = parse_cfg(&subtree); + + assert_eq!(cfg_expr.minimal_features_needed().unwrap(), vec![SmolStr::new("baz")]); + + let (subtree, _) = + get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); + let cfg_expr = parse_cfg(&subtree); + + assert_eq!( + cfg_expr.minimal_features_needed().unwrap(), + vec![SmolStr::new("baz"), SmolStr::new("foo")] + ); + + let (subtree, _) = + get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); + let cfg_expr = parse_cfg(&subtree); + + assert_eq!(cfg_expr.minimal_features_needed().unwrap(), vec![SmolStr::new("baz")]); + + let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); + let cfg_expr = parse_cfg(&subtree); + + assert!(cfg_expr.minimal_features_needed().is_none()); + } } -- cgit v1.2.3