Implement RawAttr::filter

This commit is contained in:
Jonas Schievink 2020-12-18 18:58:42 +01:00
parent 03c177af89
commit 08de1b4fa5
5 changed files with 76 additions and 3 deletions

View File

@ -122,9 +122,67 @@ pub(crate) fn merge(&self, other: Self) -> Self {
}
/// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs {
// FIXME actually implement this
Attrs(self)
pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
let has_cfg_attrs = self.iter().any(|attr| {
attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr])
});
if !has_cfg_attrs {
return Attrs(self);
}
let crate_graph = db.crate_graph();
let new_attrs = self
.iter()
.filter_map(|attr| {
let attr = attr.clone();
let is_cfg_attr =
attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]);
if !is_cfg_attr {
return Some(attr);
}
let subtree = match &attr.input {
Some(AttrInput::TokenTree(it)) => it,
_ => return Some(attr),
};
// Input subtree is: `(cfg, attr)`
// Split it up into a `cfg` and an `attr` subtree.
// FIXME: There should be a common API for this.
let mut saw_comma = false;
let (mut cfg, attr): (Vec<_>, Vec<_>) =
subtree.clone().token_trees.into_iter().partition(|tree| {
if saw_comma {
return false;
}
match tree {
tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
saw_comma = true;
}
_ => {}
}
true
});
cfg.pop(); // `,` ends up in here
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg };
let cfg = CfgExpr::parse(&cfg);
let cfg_options = &crate_graph[krate].cfg_options;
if cfg_options.check(&cfg) == Some(false) {
None
} else {
let attr = Subtree { delimiter: None, token_trees: attr };
let attr = ast::Attr::parse(&attr.to_string()).ok()?;
let hygiene = Hygiene::new_unhygienic(); // FIXME
Attr::from_src(attr, &hygiene)
}
})
.collect();
Attrs(RawAttrs { entries: Some(new_attrs) })
}
}

View File

@ -153,6 +153,7 @@ macro_rules! known_names {
// Special names
macro_rules,
doc,
cfg_attr,
// Components of known path (value or mod name)
std,
core,

View File

@ -133,6 +133,10 @@ pub(crate) fn macro_stmts(p: &mut Parser) {
m.complete(p, MACRO_STMTS);
}
pub(crate) fn attr(p: &mut Parser) {
attributes::outer_attrs(p)
}
}
pub(crate) fn reparser(

View File

@ -99,6 +99,8 @@ pub enum FragmentKind {
// FIXME: use separate fragment kinds for macro inputs and outputs?
Items,
Statements,
Attr,
}
pub fn parse_fragment(
@ -118,6 +120,7 @@ pub fn parse_fragment(
FragmentKind::Statement => grammar::fragments::stmt,
FragmentKind::Items => grammar::fragments::macro_items,
FragmentKind::Statements => grammar::fragments::macro_stmts,
FragmentKind::Attr => grammar::fragments::attr,
};
parse_from_tokens(token_source, tree_sink, parser)
}

View File

@ -205,6 +205,13 @@ pub fn parse(text: &str) -> Result<Self, ()> {
}
}
impl ast::Attr {
/// Returns `text`, parsed as an attribute, but only if it has no errors.
pub fn parse(text: &str) -> Result<Self, ()> {
parsing::parse_text_fragment(text, parser::FragmentKind::Attr)
}
}
/// Matches a `SyntaxNode` against an `ast` type.
///
/// # Example: