aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authoruHOOCCOOHu <[email protected]>2019-09-29 23:52:15 +0100
committeruHOOCCOOHu <[email protected]>2019-10-02 19:28:02 +0100
commitb1ed887d813bf5775a16624694939fdf836f97b1 (patch)
treeb69daa2ca7d29a3362e9608ad0596de18caffa18 /crates
parentffe179a73663b111e4b3ee8a3f525fb3e461c78e (diff)
Introduce ra_cfg to parse and evaluate CfgExpr
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_cfg/Cargo.toml14
-rw-r--r--crates/ra_cfg/src/cfg_expr.rs128
-rw-r--r--crates/ra_cfg/src/lib.rs43
-rw-r--r--crates/ra_db/Cargo.toml1
-rw-r--r--crates/ra_db/src/input.rs9
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/attr.rs58
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/nameres/collector.rs52
-rw-r--r--crates/ra_hir/src/nameres/raw.rs21
10 files changed, 301 insertions, 27 deletions
diff --git a/crates/ra_cfg/Cargo.toml b/crates/ra_cfg/Cargo.toml
new file mode 100644
index 000000000..b28affc3a
--- /dev/null
+++ b/crates/ra_cfg/Cargo.toml
@@ -0,0 +1,14 @@
1[package]
2edition = "2018"
3name = "ra_cfg"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6
7[dependencies]
8rustc-hash = "1.0.1"
9
10ra_syntax = { path = "../ra_syntax" }
11tt = { path = "../ra_tt", package = "ra_tt" }
12
13[dev-dependencies]
14mbe = { path = "../ra_mbe", package = "ra_mbe" }
diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs
new file mode 100644
index 000000000..efeadf462
--- /dev/null
+++ b/crates/ra_cfg/src/cfg_expr.rs
@@ -0,0 +1,128 @@
1use std::slice::Iter as SliceIter;
2
3use ra_syntax::SmolStr;
4use tt::{Leaf, Subtree, TokenTree};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum CfgExpr {
8 Invalid,
9 Atom(SmolStr),
10 KeyValue { key: SmolStr, value: SmolStr },
11 All(Vec<CfgExpr>),
12 Any(Vec<CfgExpr>),
13 Not(Box<CfgExpr>),
14}
15
16impl CfgExpr {
17 /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
18 pub fn fold(&self, query: &impl Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> {
19 match self {
20 CfgExpr::Invalid => None,
21 CfgExpr::Atom(name) => Some(query(name, None)),
22 CfgExpr::KeyValue { key, value } => Some(query(key, Some(value))),
23 CfgExpr::All(preds) => {
24 preds.iter().try_fold(true, |s, pred| Some(s && pred.fold(query)?))
25 }
26 CfgExpr::Any(preds) => {
27 preds.iter().try_fold(false, |s, pred| Some(s || pred.fold(query)?))
28 }
29 CfgExpr::Not(pred) => pred.fold(query).map(|s| !s),
30 }
31 }
32}
33
34pub fn parse_cfg(tt: &Subtree) -> CfgExpr {
35 next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
36}
37
38fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> {
39 let name = match it.next() {
40 None => return None,
41 Some(TokenTree::Leaf(Leaf::Ident(ident))) => ident.text.clone(),
42 Some(_) => return Some(CfgExpr::Invalid),
43 };
44
45 // Peek
46 let ret = match it.as_slice().first() {
47 Some(TokenTree::Leaf(Leaf::Punct(punct))) if punct.char == '=' => {
48 match it.as_slice().get(1) {
49 Some(TokenTree::Leaf(Leaf::Literal(literal))) => {
50 it.next();
51 it.next();
52 // FIXME: escape? raw string?
53 let value =
54 SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"'));
55 CfgExpr::KeyValue { key: name, value }
56 }
57 _ => return Some(CfgExpr::Invalid),
58 }
59 }
60 Some(TokenTree::Subtree(subtree)) => {
61 it.next();
62 let mut sub_it = subtree.token_trees.iter();
63 let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect();
64 match name.as_str() {
65 "all" => CfgExpr::All(subs),
66 "any" => CfgExpr::Any(subs),
67 "not" => CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))),
68 _ => CfgExpr::Invalid,
69 }
70 }
71 _ => CfgExpr::Atom(name),
72 };
73
74 // Eat comma separator
75 if let Some(TokenTree::Leaf(Leaf::Punct(punct))) = it.as_slice().first() {
76 if punct.char == ',' {
77 it.next();
78 }
79 }
80 Some(ret)
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 use mbe::ast_to_token_tree;
88 use ra_syntax::ast::{self, AstNode};
89
90 fn assert_parse_result(input: &str, expected: CfgExpr) {
91 let source_file = ast::SourceFile::parse(input).ok().unwrap();
92 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
93 let (tt, _) = ast_to_token_tree(&tt).unwrap();
94 assert_eq!(parse_cfg(&tt), expected);
95 }
96
97 #[test]
98 fn test_cfg_expr_parser() {
99 assert_parse_result("#![cfg(foo)]", CfgExpr::Atom("foo".into()));
100 assert_parse_result("#![cfg(foo,)]", CfgExpr::Atom("foo".into()));
101 assert_parse_result(
102 "#![cfg(not(foo))]",
103 CfgExpr::Not(Box::new(CfgExpr::Atom("foo".into()))),
104 );
105 assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid);
106
107 // Only take the first
108 assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgExpr::Atom("foo".into()));
109
110 assert_parse_result(
111 r#"#![cfg(all(foo, bar = "baz"))]"#,
112 CfgExpr::All(vec![
113 CfgExpr::Atom("foo".into()),
114 CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() },
115 ]),
116 );
117
118 assert_parse_result(
119 r#"#![cfg(any(not(), all(), , bar = "baz",))]"#,
120 CfgExpr::Any(vec![
121 CfgExpr::Not(Box::new(CfgExpr::Invalid)),
122 CfgExpr::All(vec![]),
123 CfgExpr::Invalid,
124 CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() },
125 ]),
126 );
127 }
128}
diff --git a/crates/ra_cfg/src/lib.rs b/crates/ra_cfg/src/lib.rs
new file mode 100644
index 000000000..fa5822d8a
--- /dev/null
+++ b/crates/ra_cfg/src/lib.rs
@@ -0,0 +1,43 @@
1//! ra_cfg defines conditional compiling options, `cfg` attibute parser and evaluator
2use ra_syntax::SmolStr;
3use rustc_hash::{FxHashMap, FxHashSet};
4
5mod cfg_expr;
6
7pub use cfg_expr::{parse_cfg, CfgExpr};
8
9#[derive(Debug, Clone, PartialEq, Eq, Default)]
10pub struct CfgOptions {
11 atoms: FxHashSet<SmolStr>,
12 features: FxHashSet<SmolStr>,
13 options: FxHashMap<SmolStr, SmolStr>,
14}
15
16impl CfgOptions {
17 pub fn check(&self, cfg: &CfgExpr) -> Option<bool> {
18 cfg.fold(&|key, value| match value {
19 None => self.atoms.contains(key),
20 Some(value) if key == "feature" => self.features.contains(value),
21 Some(value) => self.options.get(key).map_or(false, |v| v == value),
22 })
23 }
24
25 pub fn is_cfg_enabled(&self, attr: &tt::Subtree) -> Option<bool> {
26 self.check(&parse_cfg(attr))
27 }
28
29 pub fn atom(mut self, name: SmolStr) -> CfgOptions {
30 self.atoms.insert(name);
31 self
32 }
33
34 pub fn feature(mut self, name: SmolStr) -> CfgOptions {
35 self.features.insert(name);
36 self
37 }
38
39 pub fn option(mut self, key: SmolStr, value: SmolStr) -> CfgOptions {
40 self.options.insert(key, value);
41 self
42 }
43}
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index 2fac07bc5..c141f1a88 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -10,4 +10,5 @@ relative-path = "0.4.0"
10rustc-hash = "1.0" 10rustc-hash = "1.0"
11 11
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_cfg = { path = "../ra_cfg" }
13ra_prof = { path = "../ra_prof" } 14ra_prof = { path = "../ra_prof" }
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 52f892891..5fd6edd78 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -9,6 +9,7 @@
9use relative_path::{RelativePath, RelativePathBuf}; 9use relative_path::{RelativePath, RelativePathBuf};
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
12use ra_cfg::CfgOptions;
12use ra_syntax::SmolStr; 13use ra_syntax::SmolStr;
13use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
14 15
@@ -109,11 +110,13 @@ struct CrateData {
109 file_id: FileId, 110 file_id: FileId,
110 edition: Edition, 111 edition: Edition,
111 dependencies: Vec<Dependency>, 112 dependencies: Vec<Dependency>,
113 cfg_options: CfgOptions,
112} 114}
113 115
114impl CrateData { 116impl CrateData {
115 fn new(file_id: FileId, edition: Edition) -> CrateData { 117 fn new(file_id: FileId, edition: Edition) -> CrateData {
116 CrateData { file_id, edition, dependencies: Vec::new() } 118 // FIXME: cfg options
119 CrateData { file_id, edition, dependencies: Vec::new(), cfg_options: CfgOptions::default() }
117 } 120 }
118 121
119 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 122 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
@@ -141,6 +144,10 @@ impl CrateGraph {
141 crate_id 144 crate_id
142 } 145 }
143 146
147 pub fn cfg_options(&self, crate_id: CrateId) -> &CfgOptions {
148 &self.arena[&crate_id].cfg_options
149 }
150
144 pub fn add_dep( 151 pub fn add_dep(
145 &mut self, 152 &mut self,
146 from: CrateId, 153 from: CrateId,
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
16ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
17ra_arena = { path = "../ra_arena" } 17ra_arena = { path = "../ra_arena" }
18ra_cfg = { path = "../ra_cfg" }
18ra_db = { path = "../ra_db" } 19ra_db = { path = "../ra_db" }
19mbe = { path = "../ra_mbe", package = "ra_mbe" } 20mbe = { path = "../ra_mbe", package = "ra_mbe" }
20tt = { path = "../ra_tt", package = "ra_tt" } 21tt = { 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..19be6de32
--- /dev/null
+++ b/crates/ra_hir/src/attr.rs
@@ -0,0 +1,58 @@
1use mbe::ast_to_token_tree;
2use ra_syntax::{
3 ast::{self, AstNode},
4 SmolStr,
5};
6use tt::Subtree;
7
8use crate::{db::AstDatabase, path::Path, Source};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub(crate) struct Attr {
12 pub(crate) path: Path,
13 pub(crate) input: Option<AttrInput>,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum AttrInput {
18 Literal(SmolStr),
19 TokenTree(Subtree),
20}
21
22impl Attr {
23 pub(crate) fn from_src(
24 Source { file_id, ast }: Source<ast::Attr>,
25 db: &impl AstDatabase,
26 ) -> Option<Attr> {
27 let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?;
28 let input = match ast.input() {
29 None => None,
30 Some(ast::AttrInput::Literal(lit)) => {
31 // FIXME: escape? raw string?
32 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
33 Some(AttrInput::Literal(value))
34 }
35 Some(ast::AttrInput::TokenTree(tt)) => {
36 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
37 }
38 };
39
40 Some(Attr { path, input })
41 }
42
43 pub(crate) fn is_simple_atom(&self, name: &str) -> bool {
44 // FIXME: Avoid cloning
45 self.path.as_ident().map_or(false, |s| s.to_string() == name)
46 }
47
48 pub(crate) fn as_cfg(&self) -> Option<&Subtree> {
49 if self.is_simple_atom("cfg") {
50 match &self.input {
51 Some(AttrInput::TokenTree(subtree)) => Some(subtree),
52 _ => None,
53 }
54 } else {
55 None
56 }
57 }
58}
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;
44mod type_alias; 44mod type_alias;
45mod type_ref; 45mod type_ref;
46mod ty; 46mod ty;
47mod attr;
47mod impl_block; 48mod impl_block;
48mod expr; 49mod expr;
49mod lang_item; 50mod lang_item;
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 40e56dfe0..f0e790e4c 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,11 +1,13 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_cfg::CfgOptions;
3use ra_db::FileId; 4use ra_db::FileId;
4use ra_syntax::{ast, SmolStr}; 5use ra_syntax::{ast, SmolStr};
5use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
6use test_utils::tested_by; 7use test_utils::tested_by;
7 8
8use crate::{ 9use crate::{
10 attr::Attr,
9 db::DefDatabase, 11 db::DefDatabase,
10 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 12 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
11 name::MACRO_RULES, 13 name::MACRO_RULES,
@@ -35,6 +37,9 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
35 } 37 }
36 } 38 }
37 39
40 let crate_graph = db.crate_graph();
41 let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
42
38 let mut collector = DefCollector { 43 let mut collector = DefCollector {
39 db, 44 db,
40 def_map, 45 def_map,
@@ -42,6 +47,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
42 unresolved_imports: Vec::new(), 47 unresolved_imports: Vec::new(),
43 unexpanded_macros: Vec::new(), 48 unexpanded_macros: Vec::new(),
44 macro_stack_monitor: MacroStackMonitor::default(), 49 macro_stack_monitor: MacroStackMonitor::default(),
50 cfg_options,
45 }; 51 };
46 collector.collect(); 52 collector.collect();
47 collector.finish() 53 collector.finish()
@@ -76,8 +82,8 @@ impl MacroStackMonitor {
76} 82}
77 83
78/// Walks the tree of module recursively 84/// Walks the tree of module recursively
79struct DefCollector<DB> { 85struct DefCollector<'a, DB> {
80 db: DB, 86 db: &'a DB,
81 def_map: CrateDefMap, 87 def_map: CrateDefMap,
82 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 88 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
83 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 89 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
@@ -86,9 +92,11 @@ struct DefCollector<DB> {
86 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 92 /// 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. 93 /// To prevent stack overflow, we add a deep counter here for prevent that.
88 macro_stack_monitor: MacroStackMonitor, 94 macro_stack_monitor: MacroStackMonitor,
95
96 cfg_options: &'a CfgOptions,
89} 97}
90 98
91impl<'a, DB> DefCollector<&'a DB> 99impl<DB> DefCollector<'_, DB>
92where 100where
93 DB: DefDatabase, 101 DB: DefDatabase,
94{ 102{
@@ -506,7 +514,7 @@ struct ModCollector<'a, D> {
506 parent_module: Option<ParentModule<'a>>, 514 parent_module: Option<ParentModule<'a>>,
507} 515}
508 516
509impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> 517impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
510where 518where
511 DB: DefDatabase, 519 DB: DefDatabase,
512{ 520{
@@ -523,23 +531,27 @@ where
523 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 531 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
524 // any other items. 532 // any other items.
525 for item in items { 533 for item in items {
526 if let raw::RawItemKind::Import(import_id) = item.kind { 534 if self.is_cfg_enabled(&item.attrs) {
527 let import = self.raw_items[import_id].clone(); 535 if let raw::RawItemKind::Import(import_id) = item.kind {
528 if import.is_extern_crate && import.is_macro_use { 536 let import = self.raw_items[import_id].clone();
529 self.def_collector.import_macros_from_extern_crate(self.module_id, &import); 537 if import.is_extern_crate && import.is_macro_use {
538 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
539 }
530 } 540 }
531 } 541 }
532 } 542 }
533 543
534 for item in items { 544 for item in items {
535 match item.kind { 545 if self.is_cfg_enabled(&item.attrs) {
536 raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]), 546 match item.kind {
537 raw::RawItemKind::Import(import_id) => self 547 raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]),
538 .def_collector 548 raw::RawItemKind::Import(import_id) => self
539 .unresolved_imports 549 .def_collector
540 .push((self.module_id, import_id, self.raw_items[import_id].clone())), 550 .unresolved_imports
541 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), 551 .push((self.module_id, import_id, self.raw_items[import_id].clone())),
542 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 552 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]),
553 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
554 }
543 } 555 }
544 } 556 }
545 } 557 }
@@ -702,6 +714,13 @@ where
702 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 714 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
703 } 715 }
704 } 716 }
717
718 fn is_cfg_enabled(&self, attrs: &[Attr]) -> bool {
719 attrs
720 .iter()
721 .flat_map(|attr| attr.as_cfg())
722 .all(|cfg| self.def_collector.cfg_options.is_cfg_enabled(cfg).unwrap_or(true))
723 }
705} 724}
706 725
707fn is_macro_rules(path: &Path) -> bool { 726fn is_macro_rules(path: &Path) -> bool {
@@ -729,6 +748,7 @@ mod tests {
729 unresolved_imports: Vec::new(), 748 unresolved_imports: Vec::new(),
730 unexpanded_macros: Vec::new(), 749 unexpanded_macros: Vec::new(),
731 macro_stack_monitor: monitor, 750 macro_stack_monitor: monitor,
751 cfg_options: &CfgOptions::default(),
732 }; 752 };
733 collector.collect(); 753 collector.collect();
734 collector.finish() 754 collector.finish()
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index cacbcb517..ff079bcf1 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -2,7 +2,6 @@
2 2
3use std::{ops::Index, sync::Arc}; 3use std::{ops::Index, sync::Arc};
4 4
5use mbe::ast_to_token_tree;
6use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
7use ra_syntax::{ 6use ra_syntax::{
8 ast::{self, AttrsOwner, NameOwner}, 7 ast::{self, AttrsOwner, NameOwner},
@@ -11,6 +10,7 @@ use ra_syntax::{
11use test_utils::tested_by; 10use test_utils::tested_by;
12 11
13use crate::{ 12use crate::{
13 attr::Attr,
14 db::{AstDatabase, DefDatabase}, 14 db::{AstDatabase, DefDatabase},
15 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, 15 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
16}; 16};
@@ -29,8 +29,6 @@ pub struct RawItems {
29 items: Vec<RawItem>, 29 items: Vec<RawItem>,
30} 30}
31 31
32type Attrs = Arc<[tt::Subtree]>;
33
34#[derive(Debug, Default, PartialEq, Eq)] 32#[derive(Debug, Default, PartialEq, Eq)]
35pub struct ImportSourceMap { 33pub struct ImportSourceMap {
36 map: ArenaMap<ImportId, ImportSourcePtr>, 34 map: ArenaMap<ImportId, ImportSourcePtr>,
@@ -124,7 +122,7 @@ impl Index<Macro> for RawItems {
124 122
125#[derive(Debug, PartialEq, Eq, Clone)] 123#[derive(Debug, PartialEq, Eq, Clone)]
126pub(super) struct RawItem { 124pub(super) struct RawItem {
127 pub(super) attrs: Attrs, 125 pub(super) attrs: Arc<[Attr]>,
128 pub(super) kind: RawItemKind, 126 pub(super) kind: RawItemKind,
129} 127}
130 128
@@ -285,6 +283,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
285 let attrs = self.parse_attrs(&module); 283 let attrs = self.parse_attrs(&module);
286 284
287 let ast_id = self.source_ast_id_map.ast_id(&module); 285 let ast_id = self.source_ast_id_map.ast_id(&module);
286 // FIXME: cfg_attr
288 let is_macro_use = module.has_atom_attr("macro_use"); 287 let is_macro_use = module.has_atom_attr("macro_use");
289 if module.has_semi() { 288 if module.has_semi() {
290 let attr_path = extract_mod_path_attribute(&module); 289 let attr_path = extract_mod_path_attribute(&module);
@@ -315,6 +314,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
315 } 314 }
316 315
317 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { 316 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
317 // FIXME: cfg_attr
318 let is_prelude = use_item.has_atom_attr("prelude_import"); 318 let is_prelude = use_item.has_atom_attr("prelude_import");
319 let attrs = self.parse_attrs(&use_item); 319 let attrs = self.parse_attrs(&use_item);
320 320
@@ -349,6 +349,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
349 let path = Path::from_name_ref(&name_ref); 349 let path = Path::from_name_ref(&name_ref);
350 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 350 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
351 let attrs = self.parse_attrs(&extern_crate); 351 let attrs = self.parse_attrs(&extern_crate);
352 // FIXME: cfg_attr
352 let is_macro_use = extern_crate.has_atom_attr("macro_use"); 353 let is_macro_use = extern_crate.has_atom_attr("macro_use");
353 let import_data = ImportData { 354 let import_data = ImportData {
354 path, 355 path,
@@ -368,6 +369,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
368 } 369 }
369 370
370 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 371 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
372 let attrs = self.parse_attrs(&m);
371 let path = match m 373 let path = match m
372 .path() 374 .path()
373 .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) 375 .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db))
@@ -378,6 +380,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
378 380
379 let name = m.name().map(|it| it.as_name()); 381 let name = m.name().map(|it| it.as_name());
380 let ast_id = self.source_ast_id_map.ast_id(&m); 382 let ast_id = self.source_ast_id_map.ast_id(&m);
383 // FIXME: cfg_attr
381 let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); 384 let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
382 385
383 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); 386 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
@@ -387,7 +390,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
387 fn push_import( 390 fn push_import(
388 &mut self, 391 &mut self,
389 current_module: Option<Module>, 392 current_module: Option<Module>,
390 attrs: Attrs, 393 attrs: Arc<[Attr]>,
391 data: ImportData, 394 data: ImportData,
392 source: ImportSourcePtr, 395 source: ImportSourcePtr,
393 ) { 396 ) {
@@ -396,7 +399,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
396 self.push_item(current_module, attrs, RawItemKind::Import(import)) 399 self.push_item(current_module, attrs, RawItemKind::Import(import))
397 } 400 }
398 401
399 fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) { 402 fn push_item(&mut self, current_module: Option<Module>, attrs: Arc<[Attr]>, kind: RawItemKind) {
400 match current_module { 403 match current_module {
401 Some(module) => match &mut self.raw_items.modules[module] { 404 Some(module) => match &mut self.raw_items.modules[module] {
402 ModuleData::Definition { items, .. } => items, 405 ModuleData::Definition { items, .. } => items,
@@ -407,11 +410,9 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
407 .push(RawItem { attrs, kind }) 410 .push(RawItem { attrs, kind })
408 } 411 }
409 412
410 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { 413 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Arc<[Attr]> {
411 item.attrs() 414 item.attrs()
412 .flat_map(|attr| attr.value()) 415 .flat_map(|ast| Attr::from_src(Source { ast, file_id: self.file_id }, self.db))
413 .flat_map(|tt| ast_to_token_tree(&tt))
414 .map(|(tt, _)| tt)
415 .collect() 416 .collect()
416 } 417 }
417} 418}