mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 04:23:25 +00:00
Implement RawAttr::filter
This commit is contained in:
parent
03c177af89
commit
08de1b4fa5
5 changed files with 76 additions and 3 deletions
|
@ -122,9 +122,67 @@ impl RawAttrs {
|
|||
}
|
||||
|
||||
/// 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) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ pub mod known {
|
|||
// Special names
|
||||
macro_rules,
|
||||
doc,
|
||||
cfg_attr,
|
||||
// Components of known path (value or mod name)
|
||||
std,
|
||||
core,
|
||||
|
|
|
@ -133,6 +133,10 @@ pub(crate) mod fragments {
|
|||
|
||||
m.complete(p, MACRO_STMTS);
|
||||
}
|
||||
|
||||
pub(crate) fn attr(p: &mut Parser) {
|
||||
attributes::outer_attrs(p)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reparser(
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -205,6 +205,13 @@ impl ast::Type {
|
|||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
|
Loading…
Reference in a new issue