aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/attr.rs67
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs18
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};
15use test_utils::mark;
15use tt::Subtree; 16use tt::Subtree;
16 17
17use crate::{ 18use 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 @@
1use base_db::fixture::WithFixture; 1use base_db::fixture::WithFixture;
2use test_utils::mark;
2 3
3use crate::test_db::TestDB; 4use 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]
126fn 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}