diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-13 17:20:16 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-13 17:20:16 +0000 |
commit | be7a31fbd64943f71afe11b0413c99496526dddc (patch) | |
tree | 746e40311f1fc9f351a088ec92434139c5207354 | |
parent | 6ab405f2e9861c34ab9e1ad86af6604523745cef (diff) | |
parent | 1848bd0fa093a9fa00b0de98201abcfd574349f9 (diff) |
Merge #7999
7999: Handle `cfg_attr` gating multiple attributes r=jonas-schievink a=jonas-schievink
Apparently `#[cfg_attr(cfg_expr, attr1, attr2)]` is valid, so let's add support for that.
bors r+
Co-authored-by: Jonas Schievink <[email protected]>
-rw-r--r-- | crates/hir_def/src/attr.rs | 48 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 3 |
2 files changed, 22 insertions, 29 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 97cdbbb9e..7b41b148c 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -9,6 +9,7 @@ use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; | |||
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use la_arena::ArenaMap; | 10 | use la_arena::ArenaMap; |
11 | use mbe::ast_to_token_tree; | 11 | use mbe::ast_to_token_tree; |
12 | use smallvec::{smallvec, SmallVec}; | ||
12 | use syntax::{ | 13 | use syntax::{ |
13 | ast::{self, AstNode, AttrsOwner}, | 14 | ast::{self, AstNode, AttrsOwner}, |
14 | match_ast, AstToken, SmolStr, SyntaxNode, | 15 | match_ast, AstToken, SmolStr, SyntaxNode, |
@@ -134,53 +135,42 @@ impl RawAttrs { | |||
134 | let crate_graph = db.crate_graph(); | 135 | let crate_graph = db.crate_graph(); |
135 | let new_attrs = self | 136 | let new_attrs = self |
136 | .iter() | 137 | .iter() |
137 | .filter_map(|attr| { | 138 | .flat_map(|attr| -> SmallVec<[_; 1]> { |
138 | let attr = attr.clone(); | 139 | let attr = attr.clone(); |
139 | let is_cfg_attr = | 140 | let is_cfg_attr = |
140 | attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]); | 141 | attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]); |
141 | if !is_cfg_attr { | 142 | if !is_cfg_attr { |
142 | return Some(attr); | 143 | return smallvec![attr]; |
143 | } | 144 | } |
144 | 145 | ||
145 | let subtree = match &attr.input { | 146 | let subtree = match &attr.input { |
146 | Some(AttrInput::TokenTree(it)) => it, | 147 | Some(AttrInput::TokenTree(it)) => it, |
147 | _ => return Some(attr), | 148 | _ => return smallvec![attr], |
148 | }; | 149 | }; |
149 | 150 | ||
150 | // Input subtree is: `(cfg, attr)` | 151 | // Input subtree is: `(cfg, $(attr),+)` |
151 | // Split it up into a `cfg` and an `attr` subtree. | 152 | // Split it up into a `cfg` subtree and the `attr` subtrees. |
152 | // FIXME: There should be a common API for this. | 153 | // FIXME: There should be a common API for this. |
153 | let mut saw_comma = false; | 154 | let mut parts = subtree.token_trees.split( |
154 | let (mut cfg, attr): (Vec<_>, Vec<_>) = | 155 | |tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ','), |
155 | subtree.clone().token_trees.into_iter().partition(|tree| { | 156 | ); |
156 | if saw_comma { | 157 | let cfg = parts.next().unwrap(); |
157 | return false; | 158 | let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; |
158 | } | ||
159 | |||
160 | match tree { | ||
161 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
162 | saw_comma = true; | ||
163 | } | ||
164 | _ => {} | ||
165 | } | ||
166 | |||
167 | true | ||
168 | }); | ||
169 | cfg.pop(); // `,` ends up in here | ||
170 | |||
171 | let attr = Subtree { delimiter: None, token_trees: attr }; | ||
172 | let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg }; | ||
173 | let cfg = CfgExpr::parse(&cfg); | 159 | let cfg = CfgExpr::parse(&cfg); |
160 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { | ||
161 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; | ||
162 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | ||
163 | let hygiene = Hygiene::new_unhygienic(); // FIXME | ||
164 | Attr::from_src(attr, &hygiene) | ||
165 | }); | ||
174 | 166 | ||
175 | let cfg_options = &crate_graph[krate].cfg_options; | 167 | let cfg_options = &crate_graph[krate].cfg_options; |
176 | if cfg_options.check(&cfg) == Some(false) { | 168 | if cfg_options.check(&cfg) == Some(false) { |
177 | None | 169 | smallvec![] |
178 | } else { | 170 | } else { |
179 | cov_mark::hit!(cfg_attr_active); | 171 | cov_mark::hit!(cfg_attr_active); |
180 | 172 | ||
181 | let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?; | 173 | attrs.collect() |
182 | let hygiene = Hygiene::new_unhygienic(); // FIXME | ||
183 | Attr::from_src(attr, &hygiene) | ||
184 | } | 174 | } |
185 | }) | 175 | }) |
186 | .collect(); | 176 | .collect(); |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index d5ef8ceb5..1b8e885b0 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -149,6 +149,9 @@ fn inactive_via_cfg_attr() { | |||
149 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | 149 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} |
150 | 150 | ||
151 | #[cfg_attr(never, cfg(no))] fn g() {} | 151 | #[cfg_attr(never, cfg(no))] fn g() {} |
152 | |||
153 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} | ||
154 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
152 | "#, | 155 | "#, |
153 | ); | 156 | ); |
154 | } | 157 | } |