diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/attr.rs | 67 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 18 |
2 files changed, 82 insertions, 3 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 9cd0b72aa..1b9c64ee5 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -12,6 +12,7 @@ use syntax::{ | |||
12 | ast::{self, AstNode, AttrsOwner}, | 12 | ast::{self, AstNode, AttrsOwner}, |
13 | match_ast, AstToken, SmolStr, SyntaxNode, | 13 | match_ast, AstToken, SmolStr, SyntaxNode, |
14 | }; | 14 | }; |
15 | use test_utils::mark; | ||
15 | use tt::Subtree; | 16 | use tt::Subtree; |
16 | 17 | ||
17 | use crate::{ | 18 | use crate::{ |
@@ -122,9 +123,69 @@ impl RawAttrs { | |||
122 | } | 123 | } |
123 | 124 | ||
124 | /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. | 125 | /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. |
125 | pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs { | 126 | pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs { |
126 | // FIXME actually implement this | 127 | let has_cfg_attrs = self.iter().any(|attr| { |
127 | Attrs(self) | 128 | attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]) |
129 | }); | ||
130 | if !has_cfg_attrs { | ||
131 | return Attrs(self); | ||
132 | } | ||
133 | |||
134 | let crate_graph = db.crate_graph(); | ||
135 | let new_attrs = self | ||
136 | .iter() | ||
137 | .filter_map(|attr| { | ||
138 | let attr = attr.clone(); | ||
139 | let is_cfg_attr = | ||
140 | attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]); | ||
141 | if !is_cfg_attr { | ||
142 | return Some(attr); | ||
143 | } | ||
144 | |||
145 | let subtree = match &attr.input { | ||
146 | Some(AttrInput::TokenTree(it)) => it, | ||
147 | _ => return Some(attr), | ||
148 | }; | ||
149 | |||
150 | // Input subtree is: `(cfg, attr)` | ||
151 | // Split it up into a `cfg` and an `attr` subtree. | ||
152 | // FIXME: There should be a common API for this. | ||
153 | let mut saw_comma = false; | ||
154 | let (mut cfg, attr): (Vec<_>, Vec<_>) = | ||
155 | subtree.clone().token_trees.into_iter().partition(|tree| { | ||
156 | if saw_comma { | ||
157 | return false; | ||
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); | ||
174 | |||
175 | let cfg_options = &crate_graph[krate].cfg_options; | ||
176 | if cfg_options.check(&cfg) == Some(false) { | ||
177 | None | ||
178 | } else { | ||
179 | mark::hit!(cfg_attr_active); | ||
180 | |||
181 | let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?; | ||
182 | let hygiene = Hygiene::new_unhygienic(); // FIXME | ||
183 | Attr::from_src(attr, &hygiene) | ||
184 | } | ||
185 | }) | ||
186 | .collect(); | ||
187 | |||
188 | Attrs(RawAttrs { entries: Some(new_attrs) }) | ||
128 | } | 189 | } |
129 | } | 190 | } |
130 | 191 | ||
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index 1a7b98831..58d69d3c6 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use base_db::fixture::WithFixture; | 1 | use base_db::fixture::WithFixture; |
2 | use test_utils::mark; | ||
2 | 3 | ||
3 | use crate::test_db::TestDB; | 4 | use crate::test_db::TestDB; |
4 | 5 | ||
@@ -119,3 +120,20 @@ fn inactive_item() { | |||
119 | "#, | 120 | "#, |
120 | ); | 121 | ); |
121 | } | 122 | } |
123 | |||
124 | /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. | ||
125 | #[test] | ||
126 | fn inactive_via_cfg_attr() { | ||
127 | mark::check!(cfg_attr_active); | ||
128 | check_diagnostics( | ||
129 | r#" | ||
130 | //- /lib.rs | ||
131 | #[cfg_attr(not(never), cfg(no))] fn f() {} | ||
132 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
133 | |||
134 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | ||
135 | |||
136 | #[cfg_attr(never, cfg(no))] fn g() {} | ||
137 | "#, | ||
138 | ); | ||
139 | } | ||