From 08de1b4fa57ca78ad13026950b3eb024b7d2abf3 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 18 Dec 2020 18:58:42 +0100 Subject: Implement `RawAttr::filter` --- crates/hir_def/src/attr.rs | 64 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) (limited to 'crates/hir_def/src') diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 9cd0b72aa..b8d9c2682 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -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) }) } } -- cgit v1.2.3