mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +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`.
|
/// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
|
||||||
pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs {
|
pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
|
||||||
// FIXME actually implement this
|
let has_cfg_attrs = self.iter().any(|attr| {
|
||||||
Attrs(self)
|
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
|
// Special names
|
||||||
macro_rules,
|
macro_rules,
|
||||||
doc,
|
doc,
|
||||||
|
cfg_attr,
|
||||||
// Components of known path (value or mod name)
|
// Components of known path (value or mod name)
|
||||||
std,
|
std,
|
||||||
core,
|
core,
|
||||||
|
|
|
@ -133,6 +133,10 @@ pub(crate) mod fragments {
|
||||||
|
|
||||||
m.complete(p, MACRO_STMTS);
|
m.complete(p, MACRO_STMTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn attr(p: &mut Parser) {
|
||||||
|
attributes::outer_attrs(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reparser(
|
pub(crate) fn reparser(
|
||||||
|
|
|
@ -99,6 +99,8 @@ pub enum FragmentKind {
|
||||||
// FIXME: use separate fragment kinds for macro inputs and outputs?
|
// FIXME: use separate fragment kinds for macro inputs and outputs?
|
||||||
Items,
|
Items,
|
||||||
Statements,
|
Statements,
|
||||||
|
|
||||||
|
Attr,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_fragment(
|
pub fn parse_fragment(
|
||||||
|
@ -118,6 +120,7 @@ pub fn parse_fragment(
|
||||||
FragmentKind::Statement => grammar::fragments::stmt,
|
FragmentKind::Statement => grammar::fragments::stmt,
|
||||||
FragmentKind::Items => grammar::fragments::macro_items,
|
FragmentKind::Items => grammar::fragments::macro_items,
|
||||||
FragmentKind::Statements => grammar::fragments::macro_stmts,
|
FragmentKind::Statements => grammar::fragments::macro_stmts,
|
||||||
|
FragmentKind::Attr => grammar::fragments::attr,
|
||||||
};
|
};
|
||||||
parse_from_tokens(token_source, tree_sink, parser)
|
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.
|
/// Matches a `SyntaxNode` against an `ast` type.
|
||||||
///
|
///
|
||||||
/// # Example:
|
/// # Example:
|
||||||
|
|
Loading…
Reference in a new issue