mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
Add cfg_attr and cleanup code
This commit is contained in:
parent
f45b080965
commit
79f2651262
8 changed files with 234 additions and 199 deletions
|
@ -2,8 +2,12 @@
|
|||
//!
|
||||
//! See: <https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation>
|
||||
|
||||
use std::{fmt, slice::Iter as SliceIter};
|
||||
use std::{fmt, iter::Peekable, slice::Iter as SliceIter};
|
||||
|
||||
use syntax::{
|
||||
ast::{self, Meta},
|
||||
NodeOrToken,
|
||||
};
|
||||
use tt::SmolStr;
|
||||
|
||||
/// A simple configuration value passed in from the outside.
|
||||
|
@ -47,6 +51,12 @@ impl CfgExpr {
|
|||
pub fn parse<S>(tt: &tt::Subtree<S>) -> CfgExpr {
|
||||
next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
|
||||
}
|
||||
/// Parses a `cfg` attribute from the meta
|
||||
pub fn parse_from_attr_meta(meta: Meta) -> Option<CfgExpr> {
|
||||
let tt = meta.token_tree()?;
|
||||
let mut iter = tt.token_trees_and_tokens().skip(1).peekable();
|
||||
next_cfg_expr_from_syntax(&mut iter)
|
||||
}
|
||||
/// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
|
||||
pub fn fold(&self, query: &dyn Fn(&CfgAtom) -> bool) -> Option<bool> {
|
||||
match self {
|
||||
|
@ -62,8 +72,71 @@ impl CfgExpr {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn next_cfg_expr_from_syntax<I>(iter: &mut Peekable<I>) -> Option<CfgExpr>
|
||||
where
|
||||
I: Iterator<Item = NodeOrToken<ast::TokenTree, syntax::SyntaxToken>>,
|
||||
{
|
||||
let name = match iter.next() {
|
||||
None => return None,
|
||||
Some(NodeOrToken::Token(element)) => match element.kind() {
|
||||
syntax::T![ident] => SmolStr::new(element.text()),
|
||||
_ => return Some(CfgExpr::Invalid),
|
||||
},
|
||||
Some(_) => return Some(CfgExpr::Invalid),
|
||||
};
|
||||
let result = match name.as_str() {
|
||||
"all" | "any" | "not" => {
|
||||
let mut preds = Vec::new();
|
||||
let Some(NodeOrToken::Node(tree)) = iter.next() else {
|
||||
return Some(CfgExpr::Invalid);
|
||||
};
|
||||
let mut tree_iter = tree.token_trees_and_tokens().skip(1).peekable();
|
||||
while tree_iter
|
||||
.peek()
|
||||
.filter(
|
||||
|element| matches!(element, NodeOrToken::Token(token) if (token.kind() != syntax::T![')'])),
|
||||
)
|
||||
.is_some()
|
||||
{
|
||||
let pred = next_cfg_expr_from_syntax(&mut tree_iter);
|
||||
if let Some(pred) = pred {
|
||||
preds.push(pred);
|
||||
}
|
||||
}
|
||||
let group = match name.as_str() {
|
||||
"all" => CfgExpr::All(preds),
|
||||
"any" => CfgExpr::Any(preds),
|
||||
"not" => CfgExpr::Not(Box::new(preds.pop().unwrap_or(CfgExpr::Invalid))),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Some(group)
|
||||
}
|
||||
_ => match iter.peek() {
|
||||
Some(NodeOrToken::Token(element)) if (element.kind() == syntax::T![=]) => {
|
||||
iter.next();
|
||||
match iter.next() {
|
||||
Some(NodeOrToken::Token(value_token))
|
||||
if (value_token.kind() == syntax::SyntaxKind::STRING) =>
|
||||
{
|
||||
let value = value_token.text();
|
||||
let value = SmolStr::new(value.trim_matches('"'));
|
||||
Some(CfgExpr::Atom(CfgAtom::KeyValue { key: name, value }))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => Some(CfgExpr::Atom(CfgAtom::Flag(name))),
|
||||
},
|
||||
};
|
||||
if let Some(NodeOrToken::Token(element)) = iter.peek() {
|
||||
if element.kind() == syntax::T![,] {
|
||||
iter.next();
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr> {
|
||||
fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr> {
|
||||
let name = match it.next() {
|
||||
None => return None,
|
||||
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue