diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-10-05 15:25:59 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-10-05 15:25:59 +0100 |
commit | ae6305b90c80eb919cfde985cba66975b6222ed2 (patch) | |
tree | de601daf3714c4bda937e7cad05d048b69d16e71 /crates/ra_hir | |
parent | dbf869b4d2dac09df17609edf6e67c1611b71dc5 (diff) | |
parent | c6303d9fee98232ac83a77f943c39d65c9c6b6db (diff) |
Merge #1928
1928: Support `#[cfg(..)]` r=matklad a=oxalica
This PR implement `#[cfg(..)]` conditional compilation. It read default cfg options from `rustc --print cfg` with also hard-coded `test` and `debug_assertion` enabled.
Front-end settings are **not** included in this PR.
There is also a known issue that inner control attributes are totally ignored. I think it is **not** a part of `cfg` and create a separated issue for it. #1949
Fixes #1920
Related: #1073
Co-authored-by: uHOOCCOOHu <[email protected]>
Co-authored-by: oxalica <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/attr.rs | 80 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 34 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 53 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 54 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 70 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 45 |
9 files changed, 323 insertions, 38 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index d9bed4dda..cc117f84d 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -15,6 +15,7 @@ once_cell = "1.0.1" | |||
15 | 15 | ||
16 | ra_syntax = { path = "../ra_syntax" } | 16 | ra_syntax = { path = "../ra_syntax" } |
17 | ra_arena = { path = "../ra_arena" } | 17 | ra_arena = { path = "../ra_arena" } |
18 | ra_cfg = { path = "../ra_cfg" } | ||
18 | ra_db = { path = "../ra_db" } | 19 | ra_db = { path = "../ra_db" } |
19 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | 20 | mbe = { path = "../ra_mbe", package = "ra_mbe" } |
20 | tt = { path = "../ra_tt", package = "ra_tt" } | 21 | tt = { path = "../ra_tt", package = "ra_tt" } |
diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs new file mode 100644 index 000000000..f67e80bfd --- /dev/null +++ b/crates/ra_hir/src/attr.rs | |||
@@ -0,0 +1,80 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use mbe::ast_to_token_tree; | ||
6 | use ra_cfg::CfgOptions; | ||
7 | use ra_syntax::{ | ||
8 | ast::{self, AstNode, AttrsOwner}, | ||
9 | SmolStr, | ||
10 | }; | ||
11 | use tt::Subtree; | ||
12 | |||
13 | use crate::{db::AstDatabase, path::Path, HirFileId, Source}; | ||
14 | |||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
16 | pub(crate) struct Attr { | ||
17 | pub(crate) path: Path, | ||
18 | pub(crate) input: Option<AttrInput>, | ||
19 | } | ||
20 | |||
21 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
22 | pub enum AttrInput { | ||
23 | Literal(SmolStr), | ||
24 | TokenTree(Subtree), | ||
25 | } | ||
26 | |||
27 | impl Attr { | ||
28 | pub(crate) fn from_src( | ||
29 | Source { file_id, ast }: Source<ast::Attr>, | ||
30 | db: &impl AstDatabase, | ||
31 | ) -> Option<Attr> { | ||
32 | let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?; | ||
33 | let input = match ast.input() { | ||
34 | None => None, | ||
35 | Some(ast::AttrInput::Literal(lit)) => { | ||
36 | // FIXME: escape? raw string? | ||
37 | let value = lit.syntax().first_token()?.text().trim_matches('"').into(); | ||
38 | Some(AttrInput::Literal(value)) | ||
39 | } | ||
40 | Some(ast::AttrInput::TokenTree(tt)) => { | ||
41 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) | ||
42 | } | ||
43 | }; | ||
44 | |||
45 | Some(Attr { path, input }) | ||
46 | } | ||
47 | |||
48 | pub(crate) fn from_attrs_owner( | ||
49 | file_id: HirFileId, | ||
50 | owner: &dyn AttrsOwner, | ||
51 | db: &impl AstDatabase, | ||
52 | ) -> Option<Arc<[Attr]>> { | ||
53 | let mut attrs = owner.attrs().peekable(); | ||
54 | if attrs.peek().is_none() { | ||
55 | // Avoid heap allocation | ||
56 | return None; | ||
57 | } | ||
58 | Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect()) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn is_simple_atom(&self, name: &str) -> bool { | ||
62 | // FIXME: Avoid cloning | ||
63 | self.path.as_ident().map_or(false, |s| s.to_string() == name) | ||
64 | } | ||
65 | |||
66 | pub(crate) fn as_cfg(&self) -> Option<&Subtree> { | ||
67 | if self.is_simple_atom("cfg") { | ||
68 | match &self.input { | ||
69 | Some(AttrInput::TokenTree(subtree)) => Some(subtree), | ||
70 | _ => None, | ||
71 | } | ||
72 | } else { | ||
73 | None | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> { | ||
78 | cfg_options.is_cfg_enabled(self.as_cfg()?) | ||
79 | } | ||
80 | } | ||
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 8cf74ddc7..55dfc393b 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -4,12 +4,14 @@ use rustc_hash::FxHashMap; | |||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 6 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
7 | use ra_cfg::CfgOptions; | ||
7 | use ra_syntax::{ | 8 | use ra_syntax::{ |
8 | ast::{self, AstNode}, | 9 | ast::{self, AstNode}, |
9 | AstPtr, | 10 | AstPtr, |
10 | }; | 11 | }; |
11 | 12 | ||
12 | use crate::{ | 13 | use crate::{ |
14 | attr::Attr, | ||
13 | code_model::{Module, ModuleSource}, | 15 | code_model::{Module, ModuleSource}, |
14 | db::{AstDatabase, DefDatabase, HirDatabase}, | 16 | db::{AstDatabase, DefDatabase, HirDatabase}, |
15 | generics::HasGenericParams, | 17 | generics::HasGenericParams, |
@@ -176,6 +178,7 @@ pub struct ModuleImplBlocks { | |||
176 | impl ModuleImplBlocks { | 178 | impl ModuleImplBlocks { |
177 | fn collect( | 179 | fn collect( |
178 | db: &(impl DefDatabase + AstDatabase), | 180 | db: &(impl DefDatabase + AstDatabase), |
181 | cfg_options: &CfgOptions, | ||
179 | module: Module, | 182 | module: Module, |
180 | source_map: &mut ImplSourceMap, | 183 | source_map: &mut ImplSourceMap, |
181 | ) -> Self { | 184 | ) -> Self { |
@@ -188,11 +191,11 @@ impl ModuleImplBlocks { | |||
188 | let src = m.module.definition_source(db); | 191 | let src = m.module.definition_source(db); |
189 | match &src.ast { | 192 | match &src.ast { |
190 | ModuleSource::SourceFile(node) => { | 193 | ModuleSource::SourceFile(node) => { |
191 | m.collect_from_item_owner(db, source_map, node, src.file_id) | 194 | m.collect_from_item_owner(db, cfg_options, source_map, node, src.file_id) |
192 | } | 195 | } |
193 | ModuleSource::Module(node) => { | 196 | ModuleSource::Module(node) => { |
194 | let item_list = node.item_list().expect("inline module should have item list"); | 197 | let item_list = node.item_list().expect("inline module should have item list"); |
195 | m.collect_from_item_owner(db, source_map, &item_list, src.file_id) | 198 | m.collect_from_item_owner(db, cfg_options, source_map, &item_list, src.file_id) |
196 | } | 199 | } |
197 | }; | 200 | }; |
198 | m | 201 | m |
@@ -201,6 +204,7 @@ impl ModuleImplBlocks { | |||
201 | fn collect_from_item_owner( | 204 | fn collect_from_item_owner( |
202 | &mut self, | 205 | &mut self, |
203 | db: &(impl DefDatabase + AstDatabase), | 206 | db: &(impl DefDatabase + AstDatabase), |
207 | cfg_options: &CfgOptions, | ||
204 | source_map: &mut ImplSourceMap, | 208 | source_map: &mut ImplSourceMap, |
205 | owner: &dyn ast::ModuleItemOwner, | 209 | owner: &dyn ast::ModuleItemOwner, |
206 | file_id: HirFileId, | 210 | file_id: HirFileId, |
@@ -208,6 +212,13 @@ impl ModuleImplBlocks { | |||
208 | for item in owner.items_with_macros() { | 212 | for item in owner.items_with_macros() { |
209 | match item { | 213 | match item { |
210 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { | 214 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { |
215 | let attrs = Attr::from_attrs_owner(file_id, &impl_block_ast, db); | ||
216 | if attrs.map_or(false, |attrs| { | ||
217 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
218 | }) { | ||
219 | continue; | ||
220 | } | ||
221 | |||
211 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); | 222 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); |
212 | let id = self.impls.alloc(impl_block); | 223 | let id = self.impls.alloc(impl_block); |
213 | for &impl_item in &self.impls[id].items { | 224 | for &impl_item in &self.impls[id].items { |
@@ -218,6 +229,13 @@ impl ModuleImplBlocks { | |||
218 | } | 229 | } |
219 | ast::ItemOrMacro::Item(_) => (), | 230 | ast::ItemOrMacro::Item(_) => (), |
220 | ast::ItemOrMacro::Macro(macro_call) => { | 231 | ast::ItemOrMacro::Macro(macro_call) => { |
232 | let attrs = Attr::from_attrs_owner(file_id, ¯o_call, db); | ||
233 | if attrs.map_or(false, |attrs| { | ||
234 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
235 | }) { | ||
236 | continue; | ||
237 | } | ||
238 | |||
221 | //FIXME: we should really cut down on the boilerplate required to process a macro | 239 | //FIXME: we should really cut down on the boilerplate required to process a macro |
222 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); | 240 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); |
223 | if let Some(path) = macro_call | 241 | if let Some(path) = macro_call |
@@ -231,7 +249,13 @@ impl ModuleImplBlocks { | |||
231 | if let Some(item_list) = | 249 | if let Some(item_list) = |
232 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) | 250 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) |
233 | { | 251 | { |
234 | self.collect_from_item_owner(db, source_map, &item_list, file_id) | 252 | self.collect_from_item_owner( |
253 | db, | ||
254 | cfg_options, | ||
255 | source_map, | ||
256 | &item_list, | ||
257 | file_id, | ||
258 | ) | ||
235 | } | 259 | } |
236 | } | 260 | } |
237 | } | 261 | } |
@@ -246,8 +270,10 @@ pub(crate) fn impls_in_module_with_source_map_query( | |||
246 | module: Module, | 270 | module: Module, |
247 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | 271 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { |
248 | let mut source_map = ImplSourceMap::default(); | 272 | let mut source_map = ImplSourceMap::default(); |
273 | let crate_graph = db.crate_graph(); | ||
274 | let cfg_options = crate_graph.cfg_options(module.krate.crate_id()); | ||
249 | 275 | ||
250 | let result = ModuleImplBlocks::collect(db, module, &mut source_map); | 276 | let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); |
251 | (Arc::new(result), Arc::new(source_map)) | 277 | (Arc::new(result), Arc::new(source_map)) |
252 | } | 278 | } |
253 | 279 | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 00031deba..4340e9d34 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -44,6 +44,7 @@ mod traits; | |||
44 | mod type_alias; | 44 | mod type_alias; |
45 | mod type_ref; | 45 | mod type_ref; |
46 | mod ty; | 46 | mod ty; |
47 | mod attr; | ||
47 | mod impl_block; | 48 | mod impl_block; |
48 | mod expr; | 49 | mod expr; |
49 | mod lang_item; | 50 | mod lang_item; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 50feb98fb..f750986b8 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | use std::{panic, sync::Arc}; | 3 | use std::{panic, sync::Arc}; |
4 | 4 | ||
5 | use parking_lot::Mutex; | 5 | use parking_lot::Mutex; |
6 | use ra_cfg::CfgOptions; | ||
6 | use ra_db::{ | 7 | use ra_db::{ |
7 | salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, | 8 | salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, |
8 | SourceRootId, | 9 | SourceRootId, |
@@ -74,13 +75,13 @@ impl MockDatabase { | |||
74 | pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { | 75 | pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { |
75 | let mut ids = FxHashMap::default(); | 76 | let mut ids = FxHashMap::default(); |
76 | let mut crate_graph = CrateGraph::default(); | 77 | let mut crate_graph = CrateGraph::default(); |
77 | for (crate_name, (crate_root, edition, _)) in graph.0.iter() { | 78 | for (crate_name, (crate_root, edition, cfg_options, _)) in graph.0.iter() { |
78 | let crate_root = self.file_id_of(&crate_root); | 79 | let crate_root = self.file_id_of(&crate_root); |
79 | let crate_id = crate_graph.add_crate_root(crate_root, *edition); | 80 | let crate_id = crate_graph.add_crate_root(crate_root, *edition, cfg_options.clone()); |
80 | Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone()); | 81 | Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone()); |
81 | ids.insert(crate_name, crate_id); | 82 | ids.insert(crate_name, crate_id); |
82 | } | 83 | } |
83 | for (crate_name, (_, _, deps)) in graph.0.iter() { | 84 | for (crate_name, (_, _, _, deps)) in graph.0.iter() { |
84 | let from = ids[crate_name]; | 85 | let from = ids[crate_name]; |
85 | for dep in deps { | 86 | for dep in deps { |
86 | let to = ids[dep]; | 87 | let to = ids[dep]; |
@@ -184,7 +185,7 @@ impl MockDatabase { | |||
184 | 185 | ||
185 | if is_crate_root { | 186 | if is_crate_root { |
186 | let mut crate_graph = CrateGraph::default(); | 187 | let mut crate_graph = CrateGraph::default(); |
187 | crate_graph.add_crate_root(file_id, Edition::Edition2018); | 188 | crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); |
188 | self.set_crate_graph(Arc::new(crate_graph)); | 189 | self.set_crate_graph(Arc::new(crate_graph)); |
189 | } | 190 | } |
190 | file_id | 191 | file_id |
@@ -268,19 +269,27 @@ impl MockDatabase { | |||
268 | } | 269 | } |
269 | 270 | ||
270 | #[derive(Default)] | 271 | #[derive(Default)] |
271 | pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, Vec<String>))>); | 272 | pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, CfgOptions, Vec<String>))>); |
272 | 273 | ||
273 | #[macro_export] | 274 | #[macro_export] |
274 | macro_rules! crate_graph { | 275 | macro_rules! crate_graph { |
275 | ($($crate_name:literal: ($crate_path:literal, $($edition:literal,)? [$($dep:literal),*]),)*) => {{ | 276 | ($( |
277 | $crate_name:literal: ( | ||
278 | $crate_path:literal, | ||
279 | $($edition:literal,)? | ||
280 | [$($dep:literal),*] | ||
281 | $(,$cfg:expr)? | ||
282 | ), | ||
283 | )*) => {{ | ||
276 | let mut res = $crate::mock::CrateGraphFixture::default(); | 284 | let mut res = $crate::mock::CrateGraphFixture::default(); |
277 | $( | 285 | $( |
278 | #[allow(unused_mut, unused_assignments)] | 286 | #[allow(unused_mut, unused_assignments)] |
279 | let mut edition = ra_db::Edition::Edition2018; | 287 | let mut edition = ra_db::Edition::Edition2018; |
280 | $(edition = ra_db::Edition::from_string($edition);)? | 288 | $(edition = ra_db::Edition::from_string($edition);)? |
289 | let cfg_options = { ::ra_cfg::CfgOptions::default() $(; $cfg)? }; | ||
281 | res.0.push(( | 290 | res.0.push(( |
282 | $crate_name.to_string(), | 291 | $crate_name.to_string(), |
283 | ($crate_path.to_string(), edition, vec![$($dep.to_string()),*]) | 292 | ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*]) |
284 | )); | 293 | )); |
285 | )* | 294 | )* |
286 | res | 295 | res |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index a568fdabd..cef2dc9d2 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_cfg::CfgOptions; | ||
3 | use ra_db::FileId; | 4 | use ra_db::FileId; |
4 | use ra_syntax::{ast, SmolStr}; | 5 | use ra_syntax::{ast, SmolStr}; |
5 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
@@ -35,6 +36,9 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
35 | } | 36 | } |
36 | } | 37 | } |
37 | 38 | ||
39 | let crate_graph = db.crate_graph(); | ||
40 | let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id()); | ||
41 | |||
38 | let mut collector = DefCollector { | 42 | let mut collector = DefCollector { |
39 | db, | 43 | db, |
40 | def_map, | 44 | def_map, |
@@ -42,6 +46,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
42 | unresolved_imports: Vec::new(), | 46 | unresolved_imports: Vec::new(), |
43 | unexpanded_macros: Vec::new(), | 47 | unexpanded_macros: Vec::new(), |
44 | macro_stack_monitor: MacroStackMonitor::default(), | 48 | macro_stack_monitor: MacroStackMonitor::default(), |
49 | cfg_options, | ||
45 | }; | 50 | }; |
46 | collector.collect(); | 51 | collector.collect(); |
47 | collector.finish() | 52 | collector.finish() |
@@ -76,8 +81,8 @@ impl MacroStackMonitor { | |||
76 | } | 81 | } |
77 | 82 | ||
78 | /// Walks the tree of module recursively | 83 | /// Walks the tree of module recursively |
79 | struct DefCollector<DB> { | 84 | struct DefCollector<'a, DB> { |
80 | db: DB, | 85 | db: &'a DB, |
81 | def_map: CrateDefMap, | 86 | def_map: CrateDefMap, |
82 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, | 87 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, |
83 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, | 88 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, |
@@ -86,9 +91,11 @@ struct DefCollector<DB> { | |||
86 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | 91 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly |
87 | /// To prevent stack overflow, we add a deep counter here for prevent that. | 92 | /// To prevent stack overflow, we add a deep counter here for prevent that. |
88 | macro_stack_monitor: MacroStackMonitor, | 93 | macro_stack_monitor: MacroStackMonitor, |
94 | |||
95 | cfg_options: &'a CfgOptions, | ||
89 | } | 96 | } |
90 | 97 | ||
91 | impl<'a, DB> DefCollector<&'a DB> | 98 | impl<DB> DefCollector<'_, DB> |
92 | where | 99 | where |
93 | DB: DefDatabase, | 100 | DB: DefDatabase, |
94 | { | 101 | { |
@@ -506,7 +513,7 @@ struct ModCollector<'a, D> { | |||
506 | parent_module: Option<ParentModule<'a>>, | 513 | parent_module: Option<ParentModule<'a>>, |
507 | } | 514 | } |
508 | 515 | ||
509 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | 516 | impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> |
510 | where | 517 | where |
511 | DB: DefDatabase, | 518 | DB: DefDatabase, |
512 | { | 519 | { |
@@ -523,24 +530,27 @@ where | |||
523 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | 530 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting |
524 | // any other items. | 531 | // any other items. |
525 | for item in items { | 532 | for item in items { |
526 | if let raw::RawItem::Import(import_id) = *item { | 533 | if self.is_cfg_enabled(&item.attrs) { |
527 | let import = self.raw_items[import_id].clone(); | 534 | if let raw::RawItemKind::Import(import_id) = item.kind { |
528 | if import.is_extern_crate && import.is_macro_use { | 535 | let import = self.raw_items[import_id].clone(); |
529 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | 536 | if import.is_extern_crate && import.is_macro_use { |
537 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | ||
538 | } | ||
530 | } | 539 | } |
531 | } | 540 | } |
532 | } | 541 | } |
533 | 542 | ||
534 | for item in items { | 543 | for item in items { |
535 | match *item { | 544 | if self.is_cfg_enabled(&item.attrs) { |
536 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 545 | match item.kind { |
537 | raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( | 546 | raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]), |
538 | self.module_id, | 547 | raw::RawItemKind::Import(import_id) => self |
539 | import_id, | 548 | .def_collector |
540 | self.raw_items[import_id].clone(), | 549 | .unresolved_imports |
541 | )), | 550 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), |
542 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), | 551 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), |
543 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 552 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
553 | } | ||
544 | } | 554 | } |
545 | } | 555 | } |
546 | } | 556 | } |
@@ -703,6 +713,14 @@ where | |||
703 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); | 713 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
704 | } | 714 | } |
705 | } | 715 | } |
716 | |||
717 | fn is_cfg_enabled(&self, attrs: &raw::Attrs) -> bool { | ||
718 | attrs.as_ref().map_or(true, |attrs| { | ||
719 | attrs | ||
720 | .iter() | ||
721 | .all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false)) | ||
722 | }) | ||
723 | } | ||
706 | } | 724 | } |
707 | 725 | ||
708 | fn is_macro_rules(path: &Path) -> bool { | 726 | fn is_macro_rules(path: &Path) -> bool { |
@@ -730,6 +748,7 @@ mod tests { | |||
730 | unresolved_imports: Vec::new(), | 748 | unresolved_imports: Vec::new(), |
731 | unexpanded_macros: Vec::new(), | 749 | unexpanded_macros: Vec::new(), |
732 | macro_stack_monitor: monitor, | 750 | macro_stack_monitor: monitor, |
751 | cfg_options: &CfgOptions::default(), | ||
733 | }; | 752 | }; |
734 | collector.collect(); | 753 | collector.collect(); |
735 | collector.finish() | 754 | collector.finish() |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 606bd1a95..623b343c4 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -10,6 +10,7 @@ use ra_syntax::{ | |||
10 | use test_utils::tested_by; | 10 | use test_utils::tested_by; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | attr::Attr, | ||
13 | db::{AstDatabase, DefDatabase}, | 14 | db::{AstDatabase, DefDatabase}, |
14 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, | 15 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, |
15 | }; | 16 | }; |
@@ -119,8 +120,17 @@ impl Index<Macro> for RawItems { | |||
119 | } | 120 | } |
120 | } | 121 | } |
121 | 122 | ||
123 | // Avoid heap allocation on items without attributes. | ||
124 | pub(super) type Attrs = Option<Arc<[Attr]>>; | ||
125 | |||
126 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
127 | pub(super) struct RawItem { | ||
128 | pub(super) attrs: Attrs, | ||
129 | pub(super) kind: RawItemKind, | ||
130 | } | ||
131 | |||
122 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 132 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
123 | pub(super) enum RawItem { | 133 | pub(super) enum RawItemKind { |
124 | Module(Module), | 134 | Module(Module), |
125 | Import(ImportId), | 135 | Import(ImportId), |
126 | Def(Def), | 136 | Def(Def), |
@@ -215,6 +225,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
215 | } | 225 | } |
216 | 226 | ||
217 | fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { | 227 | fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { |
228 | let attrs = self.parse_attrs(&item); | ||
218 | let (kind, name) = match item { | 229 | let (kind, name) = match item { |
219 | ast::ModuleItem::Module(module) => { | 230 | ast::ModuleItem::Module(module) => { |
220 | self.add_module(current_module, module); | 231 | self.add_module(current_module, module); |
@@ -263,7 +274,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
263 | if let Some(name) = name { | 274 | if let Some(name) = name { |
264 | let name = name.as_name(); | 275 | let name = name.as_name(); |
265 | let def = self.raw_items.defs.alloc(DefData { name, kind }); | 276 | let def = self.raw_items.defs.alloc(DefData { name, kind }); |
266 | self.push_item(current_module, RawItem::Def(def)) | 277 | self.push_item(current_module, attrs, RawItemKind::Def(def)); |
267 | } | 278 | } |
268 | } | 279 | } |
269 | 280 | ||
@@ -272,8 +283,10 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
272 | Some(it) => it.as_name(), | 283 | Some(it) => it.as_name(), |
273 | None => return, | 284 | None => return, |
274 | }; | 285 | }; |
286 | let attrs = self.parse_attrs(&module); | ||
275 | 287 | ||
276 | let ast_id = self.source_ast_id_map.ast_id(&module); | 288 | let ast_id = self.source_ast_id_map.ast_id(&module); |
289 | // FIXME: cfg_attr | ||
277 | let is_macro_use = module.has_atom_attr("macro_use"); | 290 | let is_macro_use = module.has_atom_attr("macro_use"); |
278 | if module.has_semi() { | 291 | if module.has_semi() { |
279 | let attr_path = extract_mod_path_attribute(&module); | 292 | let attr_path = extract_mod_path_attribute(&module); |
@@ -283,7 +296,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
283 | attr_path, | 296 | attr_path, |
284 | is_macro_use, | 297 | is_macro_use, |
285 | }); | 298 | }); |
286 | self.push_item(current_module, RawItem::Module(item)); | 299 | self.push_item(current_module, attrs, RawItemKind::Module(item)); |
287 | return; | 300 | return; |
288 | } | 301 | } |
289 | 302 | ||
@@ -297,14 +310,16 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
297 | is_macro_use, | 310 | is_macro_use, |
298 | }); | 311 | }); |
299 | self.process_module(Some(item), item_list); | 312 | self.process_module(Some(item), item_list); |
300 | self.push_item(current_module, RawItem::Module(item)); | 313 | self.push_item(current_module, attrs, RawItemKind::Module(item)); |
301 | return; | 314 | return; |
302 | } | 315 | } |
303 | tested_by!(name_res_works_for_broken_modules); | 316 | tested_by!(name_res_works_for_broken_modules); |
304 | } | 317 | } |
305 | 318 | ||
306 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { | 319 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { |
320 | // FIXME: cfg_attr | ||
307 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 321 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
322 | let attrs = self.parse_attrs(&use_item); | ||
308 | 323 | ||
309 | Path::expand_use_item( | 324 | Path::expand_use_item( |
310 | Source { ast: use_item, file_id: self.file_id }, | 325 | Source { ast: use_item, file_id: self.file_id }, |
@@ -318,7 +333,12 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
318 | is_extern_crate: false, | 333 | is_extern_crate: false, |
319 | is_macro_use: false, | 334 | is_macro_use: false, |
320 | }; | 335 | }; |
321 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 336 | self.push_import( |
337 | current_module, | ||
338 | attrs.clone(), | ||
339 | import_data, | ||
340 | Either::A(AstPtr::new(use_tree)), | ||
341 | ); | ||
322 | }, | 342 | }, |
323 | ) | 343 | ) |
324 | } | 344 | } |
@@ -331,6 +351,8 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
331 | if let Some(name_ref) = extern_crate.name_ref() { | 351 | if let Some(name_ref) = extern_crate.name_ref() { |
332 | let path = Path::from_name_ref(&name_ref); | 352 | let path = Path::from_name_ref(&name_ref); |
333 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 353 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
354 | let attrs = self.parse_attrs(&extern_crate); | ||
355 | // FIXME: cfg_attr | ||
334 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | 356 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); |
335 | let import_data = ImportData { | 357 | let import_data = ImportData { |
336 | path, | 358 | path, |
@@ -340,11 +362,17 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
340 | is_extern_crate: true, | 362 | is_extern_crate: true, |
341 | is_macro_use, | 363 | is_macro_use, |
342 | }; | 364 | }; |
343 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); | 365 | self.push_import( |
366 | current_module, | ||
367 | attrs, | ||
368 | import_data, | ||
369 | Either::B(AstPtr::new(&extern_crate)), | ||
370 | ); | ||
344 | } | 371 | } |
345 | } | 372 | } |
346 | 373 | ||
347 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { | 374 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { |
375 | let attrs = self.parse_attrs(&m); | ||
348 | let path = match m | 376 | let path = match m |
349 | .path() | 377 | .path() |
350 | .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) | 378 | .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) |
@@ -355,24 +383,26 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
355 | 383 | ||
356 | let name = m.name().map(|it| it.as_name()); | 384 | let name = m.name().map(|it| it.as_name()); |
357 | let ast_id = self.source_ast_id_map.ast_id(&m); | 385 | let ast_id = self.source_ast_id_map.ast_id(&m); |
386 | // FIXME: cfg_attr | ||
358 | let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); | 387 | let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); |
359 | 388 | ||
360 | let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); | 389 | let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); |
361 | self.push_item(current_module, RawItem::Macro(m)); | 390 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
362 | } | 391 | } |
363 | 392 | ||
364 | fn push_import( | 393 | fn push_import( |
365 | &mut self, | 394 | &mut self, |
366 | current_module: Option<Module>, | 395 | current_module: Option<Module>, |
396 | attrs: Attrs, | ||
367 | data: ImportData, | 397 | data: ImportData, |
368 | source: ImportSourcePtr, | 398 | source: ImportSourcePtr, |
369 | ) { | 399 | ) { |
370 | let import = self.raw_items.imports.alloc(data); | 400 | let import = self.raw_items.imports.alloc(data); |
371 | self.source_map.insert(import, source); | 401 | self.source_map.insert(import, source); |
372 | self.push_item(current_module, RawItem::Import(import)) | 402 | self.push_item(current_module, attrs, RawItemKind::Import(import)) |
373 | } | 403 | } |
374 | 404 | ||
375 | fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { | 405 | fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) { |
376 | match current_module { | 406 | match current_module { |
377 | Some(module) => match &mut self.raw_items.modules[module] { | 407 | Some(module) => match &mut self.raw_items.modules[module] { |
378 | ModuleData::Definition { items, .. } => items, | 408 | ModuleData::Definition { items, .. } => items, |
@@ -380,7 +410,11 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> { | |||
380 | }, | 410 | }, |
381 | None => &mut self.raw_items.items, | 411 | None => &mut self.raw_items.items, |
382 | } | 412 | } |
383 | .push(item) | 413 | .push(RawItem { attrs, kind }) |
414 | } | ||
415 | |||
416 | fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { | ||
417 | Attr::from_attrs_owner(self.file_id, item, self.db) | ||
384 | } | 418 | } |
385 | } | 419 | } |
386 | 420 | ||
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index bc4b47b70..34dd79574 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -7,6 +7,7 @@ mod mod_resolution; | |||
7 | use std::sync::Arc; | 7 | use std::sync::Arc; |
8 | 8 | ||
9 | use insta::assert_snapshot; | 9 | use insta::assert_snapshot; |
10 | use ra_cfg::CfgOptions; | ||
10 | use ra_db::SourceDatabase; | 11 | use ra_db::SourceDatabase; |
11 | use test_utils::covers; | 12 | use test_utils::covers; |
12 | 13 | ||
@@ -507,3 +508,72 @@ fn values_dont_shadow_extern_crates() { | |||
507 | ⋮foo: v | 508 | ⋮foo: v |
508 | "###); | 509 | "###); |
509 | } | 510 | } |
511 | |||
512 | #[test] | ||
513 | fn cfg_not_test() { | ||
514 | let map = def_map_with_crate_graph( | ||
515 | r#" | ||
516 | //- /main.rs | ||
517 | use {Foo, Bar, Baz}; | ||
518 | //- /lib.rs | ||
519 | #[prelude_import] | ||
520 | pub use self::prelude::*; | ||
521 | mod prelude { | ||
522 | #[cfg(test)] | ||
523 | pub struct Foo; | ||
524 | #[cfg(not(test))] | ||
525 | pub struct Bar; | ||
526 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | ||
527 | pub struct Baz; | ||
528 | } | ||
529 | "#, | ||
530 | crate_graph! { | ||
531 | "main": ("/main.rs", ["std"]), | ||
532 | "std": ("/lib.rs", []), | ||
533 | }, | ||
534 | ); | ||
535 | |||
536 | assert_snapshot!(map, @r###" | ||
537 | ⋮crate | ||
538 | ⋮Bar: t v | ||
539 | ⋮Baz: _ | ||
540 | ⋮Foo: _ | ||
541 | "###); | ||
542 | } | ||
543 | |||
544 | #[test] | ||
545 | fn cfg_test() { | ||
546 | let map = def_map_with_crate_graph( | ||
547 | r#" | ||
548 | //- /main.rs | ||
549 | use {Foo, Bar, Baz}; | ||
550 | //- /lib.rs | ||
551 | #[prelude_import] | ||
552 | pub use self::prelude::*; | ||
553 | mod prelude { | ||
554 | #[cfg(test)] | ||
555 | pub struct Foo; | ||
556 | #[cfg(not(test))] | ||
557 | pub struct Bar; | ||
558 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | ||
559 | pub struct Baz; | ||
560 | } | ||
561 | "#, | ||
562 | crate_graph! { | ||
563 | "main": ("/main.rs", ["std"]), | ||
564 | "std": ("/lib.rs", [], CfgOptions::default() | ||
565 | .atom("test".into()) | ||
566 | .key_value("feature".into(), "foo".into()) | ||
567 | .key_value("feature".into(), "bar".into()) | ||
568 | .key_value("opt".into(), "42".into()) | ||
569 | ), | ||
570 | }, | ||
571 | ); | ||
572 | |||
573 | assert_snapshot!(map, @r###" | ||
574 | ⋮crate | ||
575 | ⋮Bar: _ | ||
576 | ⋮Baz: t v | ||
577 | ⋮Foo: t v | ||
578 | "###); | ||
579 | } | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 66f63ca24..25dad81eb 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3,6 +3,7 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use insta::assert_snapshot; | 4 | use insta::assert_snapshot; |
5 | 5 | ||
6 | use ra_cfg::CfgOptions; | ||
6 | use ra_db::{salsa::Database, FilePosition, SourceDatabase}; | 7 | use ra_db::{salsa::Database, FilePosition, SourceDatabase}; |
7 | use ra_syntax::{ | 8 | use ra_syntax::{ |
8 | algo, | 9 | algo, |
@@ -24,6 +25,50 @@ mod never_type; | |||
24 | mod coercion; | 25 | mod coercion; |
25 | 26 | ||
26 | #[test] | 27 | #[test] |
28 | fn cfg_impl_block() { | ||
29 | let (mut db, pos) = MockDatabase::with_position( | ||
30 | r#" | ||
31 | //- /main.rs | ||
32 | use foo::S as T; | ||
33 | struct S; | ||
34 | |||
35 | #[cfg(test)] | ||
36 | impl S { | ||
37 | fn foo1(&self) -> i32 { 0 } | ||
38 | } | ||
39 | |||
40 | #[cfg(not(test))] | ||
41 | impl S { | ||
42 | fn foo2(&self) -> i32 { 0 } | ||
43 | } | ||
44 | |||
45 | fn test() { | ||
46 | let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); | ||
47 | t<|>; | ||
48 | } | ||
49 | |||
50 | //- /foo.rs | ||
51 | struct S; | ||
52 | |||
53 | #[cfg(not(test))] | ||
54 | impl S { | ||
55 | fn foo3(&self) -> i32 { 0 } | ||
56 | } | ||
57 | |||
58 | #[cfg(test)] | ||
59 | impl S { | ||
60 | fn foo4(&self) -> i32 { 0 } | ||
61 | } | ||
62 | "#, | ||
63 | ); | ||
64 | db.set_crate_graph_from_fixture(crate_graph! { | ||
65 | "main": ("/main.rs", ["foo"], CfgOptions::default().atom("test".into())), | ||
66 | "foo": ("/foo.rs", []), | ||
67 | }); | ||
68 | assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); | ||
69 | } | ||
70 | |||
71 | #[test] | ||
27 | fn infer_await() { | 72 | fn infer_await() { |
28 | let (mut db, pos) = MockDatabase::with_position( | 73 | let (mut db, pos) = MockDatabase::with_position( |
29 | r#" | 74 | r#" |