aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/attr.rs64
-rw-r--r--crates/hir_expand/src/name.rs1
-rw-r--r--crates/parser/src/grammar.rs4
-rw-r--r--crates/parser/src/lib.rs3
-rw-r--r--crates/syntax/src/lib.rs7
5 files changed, 76 insertions, 3 deletions
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 {
122 } 122 }
123 123
124 /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. 124 /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
125 pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs { 125 pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
126 // FIXME actually implement this 126 let has_cfg_attrs = self.iter().any(|attr| {
127 Attrs(self) 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) })
128 } 186 }
129} 187}
130 188
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 7fb4caea3..77eeee3fe 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -153,6 +153,7 @@ pub mod known {
153 // Special names 153 // Special names
154 macro_rules, 154 macro_rules,
155 doc, 155 doc,
156 cfg_attr,
156 // Components of known path (value or mod name) 157 // Components of known path (value or mod name)
157 std, 158 std,
158 core, 159 core,
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 23039eba4..1a078f6b4 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -133,6 +133,10 @@ pub(crate) mod fragments {
133 133
134 m.complete(p, MACRO_STMTS); 134 m.complete(p, MACRO_STMTS);
135 } 135 }
136
137 pub(crate) fn attr(p: &mut Parser) {
138 attributes::outer_attrs(p)
139 }
136} 140}
137 141
138pub(crate) fn reparser( 142pub(crate) fn reparser(
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 41e62116f..ab8e4c70e 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -99,6 +99,8 @@ pub enum FragmentKind {
99 // FIXME: use separate fragment kinds for macro inputs and outputs? 99 // FIXME: use separate fragment kinds for macro inputs and outputs?
100 Items, 100 Items,
101 Statements, 101 Statements,
102
103 Attr,
102} 104}
103 105
104pub fn parse_fragment( 106pub fn parse_fragment(
@@ -118,6 +120,7 @@ pub fn parse_fragment(
118 FragmentKind::Statement => grammar::fragments::stmt, 120 FragmentKind::Statement => grammar::fragments::stmt,
119 FragmentKind::Items => grammar::fragments::macro_items, 121 FragmentKind::Items => grammar::fragments::macro_items,
120 FragmentKind::Statements => grammar::fragments::macro_stmts, 122 FragmentKind::Statements => grammar::fragments::macro_stmts,
123 FragmentKind::Attr => grammar::fragments::attr,
121 }; 124 };
122 parse_from_tokens(token_source, tree_sink, parser) 125 parse_from_tokens(token_source, tree_sink, parser)
123} 126}
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index e753b11bb..4d272f367 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -205,6 +205,13 @@ impl ast::Type {
205 } 205 }
206} 206}
207 207
208impl 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
208/// Matches a `SyntaxNode` against an `ast` type. 215/// Matches a `SyntaxNode` against an `ast` type.
209/// 216///
210/// # Example: 217/// # Example: