Skip to content

Commit 08de1b4

Browse files
Implement RawAttr::filter
1 parent 03c177a commit 08de1b4

File tree

5 files changed

+76
-3
lines changed

5 files changed

+76
-3
lines changed

crates/hir_def/src/attr.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,67 @@ impl RawAttrs {
122122
}
123123

124124
/// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
125-
pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs {
126-
// FIXME actually implement this
127-
Attrs(self)
125+
pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
126+
let has_cfg_attrs = self.iter().any(|attr| {
127+
attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr])
128+
});
129+
if !has_cfg_attrs {
130+
return Attrs(self);
131+
}
132+
133+
let crate_graph = db.crate_graph();
134+
let new_attrs = self
135+
.iter()
136+
.filter_map(|attr| {
137+
let attr = attr.clone();
138+
let is_cfg_attr =
139+
attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]);
140+
if !is_cfg_attr {
141+
return Some(attr);
142+
}
143+
144+
let subtree = match &attr.input {
145+
Some(AttrInput::TokenTree(it)) => it,
146+
_ => return Some(attr),
147+
};
148+
149+
// Input subtree is: `(cfg, attr)`
150+
// Split it up into a `cfg` and an `attr` subtree.
151+
// FIXME: There should be a common API for this.
152+
let mut saw_comma = false;
153+
let (mut cfg, attr): (Vec<_>, Vec<_>) =
154+
subtree.clone().token_trees.into_iter().partition(|tree| {
155+
if saw_comma {
156+
return false;
157+
}
158+
159+
match tree {
160+
tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
161+
saw_comma = true;
162+
}
163+
_ => {}
164+
}
165+
166+
true
167+
});
168+
cfg.pop(); // `,` ends up in here
169+
170+
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg };
171+
let cfg = CfgExpr::parse(&cfg);
172+
173+
let cfg_options = &crate_graph[krate].cfg_options;
174+
if cfg_options.check(&cfg) == Some(false) {
175+
None
176+
} else {
177+
let attr = Subtree { delimiter: None, token_trees: attr };
178+
let attr = ast::Attr::parse(&attr.to_string()).ok()?;
179+
let hygiene = Hygiene::new_unhygienic(); // FIXME
180+
Attr::from_src(attr, &hygiene)
181+
}
182+
})
183+
.collect();
184+
185+
Attrs(RawAttrs { entries: Some(new_attrs) })
128186
}
129187
}
130188

crates/hir_expand/src/name.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub mod known {
153153
// Special names
154154
macro_rules,
155155
doc,
156+
cfg_attr,
156157
// Components of known path (value or mod name)
157158
std,
158159
core,

crates/parser/src/grammar.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ pub(crate) mod fragments {
133133

134134
m.complete(p, MACRO_STMTS);
135135
}
136+
137+
pub(crate) fn attr(p: &mut Parser) {
138+
attributes::outer_attrs(p)
139+
}
136140
}
137141

138142
pub(crate) fn reparser(

crates/parser/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ pub enum FragmentKind {
9999
// FIXME: use separate fragment kinds for macro inputs and outputs?
100100
Items,
101101
Statements,
102+
103+
Attr,
102104
}
103105

104106
pub fn parse_fragment(
@@ -118,6 +120,7 @@ pub fn parse_fragment(
118120
FragmentKind::Statement => grammar::fragments::stmt,
119121
FragmentKind::Items => grammar::fragments::macro_items,
120122
FragmentKind::Statements => grammar::fragments::macro_stmts,
123+
FragmentKind::Attr => grammar::fragments::attr,
121124
};
122125
parse_from_tokens(token_source, tree_sink, parser)
123126
}

crates/syntax/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,13 @@ impl ast::Type {
205205
}
206206
}
207207

208+
impl ast::Attr {
209+
/// Returns `text`, parsed as an attribute, but only if it has no errors.
210+
pub fn parse(text: &str) -> Result<Self, ()> {
211+
parsing::parse_text_fragment(text, parser::FragmentKind::Attr)
212+
}
213+
}
214+
208215
/// Matches a `SyntaxNode` against an `ast` type.
209216
///
210217
/// # Example:

0 commit comments

Comments
 (0)