diff options
-rw-r--r-- | crates/hir_def/src/attr.rs | 64 | ||||
-rw-r--r-- | crates/hir_expand/src/name.rs | 1 | ||||
-rw-r--r-- | crates/parser/src/grammar.rs | 4 | ||||
-rw-r--r-- | crates/parser/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/syntax/src/lib.rs | 7 |
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 | ||
138 | pub(crate) fn reparser( | 142 | pub(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 | ||
104 | pub fn parse_fragment( | 106 | pub 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 | ||
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 | |||
208 | /// Matches a `SyntaxNode` against an `ast` type. | 215 | /// Matches a `SyntaxNode` against an `ast` type. |
209 | /// | 216 | /// |
210 | /// # Example: | 217 | /// # Example: |