diff options
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map.rs | 118 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map/collector.rs | 166 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map/raw.rs | 51 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map/tests.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 3 |
5 files changed, 234 insertions, 106 deletions
diff --git a/crates/ra_hir/src/nameres/crate_def_map.rs b/crates/ra_hir/src/nameres/crate_def_map.rs index 483878c78..d7ccb6584 100644 --- a/crates/ra_hir/src/nameres/crate_def_map.rs +++ b/crates/ra_hir/src/nameres/crate_def_map.rs | |||
@@ -48,25 +48,40 @@ mod tests; | |||
48 | 48 | ||
49 | use rustc_hash::FxHashMap; | 49 | use rustc_hash::FxHashMap; |
50 | use test_utils::tested_by; | 50 | use test_utils::tested_by; |
51 | use ra_arena::Arena; | 51 | use ra_arena::{Arena, RawId, impl_arena_id}; |
52 | use ra_db::FileId; | ||
53 | |||
54 | use std::sync::Arc; | ||
52 | 55 | ||
53 | use crate::{ | 56 | use crate::{ |
54 | Name, Module, Path, PathKind, ModuleDef, Crate, | 57 | Name, Module, Path, PathKind, ModuleDef, Crate, Problem, HirFileId, |
55 | PersistentHirDatabase, | 58 | PersistentHirDatabase, |
56 | module_tree::ModuleId, | ||
57 | nameres::{ModuleScope, ResolveMode, ResolvePathResult, PerNs, Edition, ReachedFixedPoint}, | 59 | nameres::{ModuleScope, ResolveMode, ResolvePathResult, PerNs, Edition, ReachedFixedPoint}, |
60 | ids::{SourceItemId, SourceFileItemId}, | ||
58 | }; | 61 | }; |
59 | 62 | ||
60 | #[derive(Default, Debug)] | 63 | pub(crate) use self::raw::RawItems; |
61 | struct ModuleData { | 64 | |
62 | parent: Option<ModuleId>, | 65 | #[derive(Default, Debug, PartialEq, Eq)] |
63 | children: FxHashMap<Name, ModuleId>, | 66 | pub(crate) struct ModuleData { |
64 | scope: ModuleScope, | 67 | pub(crate) parent: Option<ModuleId>, |
68 | pub(crate) children: FxHashMap<Name, ModuleId>, | ||
69 | pub(crate) scope: ModuleScope, | ||
70 | /// None for root | ||
71 | pub(crate) declaration: Option<SourceItemId>, | ||
72 | /// None for inline modules. | ||
73 | /// | ||
74 | /// Note that non-inline modules, by definition, live inside non-macro file. | ||
75 | pub(crate) definition: Option<FileId>, | ||
65 | } | 76 | } |
66 | 77 | ||
78 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
79 | pub(crate) struct ModuleId(RawId); | ||
80 | impl_arena_id!(ModuleId); | ||
81 | |||
67 | /// Contans all top-level defs from a macro-expanded crate | 82 | /// Contans all top-level defs from a macro-expanded crate |
68 | #[derive(Debug)] | 83 | #[derive(Debug, PartialEq, Eq)] |
69 | pub(crate) struct CrateDefMap { | 84 | pub struct CrateDefMap { |
70 | krate: Crate, | 85 | krate: Crate, |
71 | edition: Edition, | 86 | edition: Edition, |
72 | /// The prelude module for this crate. This either comes from an import | 87 | /// The prelude module for this crate. This either comes from an import |
@@ -77,19 +92,85 @@ pub(crate) struct CrateDefMap { | |||
77 | root: ModuleId, | 92 | root: ModuleId, |
78 | modules: Arena<ModuleId, ModuleData>, | 93 | modules: Arena<ModuleId, ModuleData>, |
79 | public_macros: FxHashMap<Name, mbe::MacroRules>, | 94 | public_macros: FxHashMap<Name, mbe::MacroRules>, |
95 | problems: CrateDefMapProblems, | ||
96 | } | ||
97 | |||
98 | #[derive(Default, Debug, PartialEq, Eq)] | ||
99 | pub(crate) struct CrateDefMapProblems { | ||
100 | problems: Vec<(SourceItemId, Problem)>, | ||
101 | } | ||
102 | |||
103 | impl CrateDefMapProblems { | ||
104 | fn add(&mut self, source_item_id: SourceItemId, problem: Problem) { | ||
105 | self.problems.push((source_item_id, problem)) | ||
106 | } | ||
107 | |||
108 | pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a { | ||
109 | self.problems.iter().map(|(s, p)| (s, p)) | ||
110 | } | ||
80 | } | 111 | } |
81 | 112 | ||
82 | impl std::ops::Index<ModuleId> for CrateDefMap { | 113 | impl std::ops::Index<ModuleId> for CrateDefMap { |
83 | type Output = ModuleScope; | 114 | type Output = ModuleData; |
84 | fn index(&self, id: ModuleId) -> &ModuleScope { | 115 | fn index(&self, id: ModuleId) -> &ModuleData { |
85 | &self.modules[id].scope | 116 | &self.modules[id] |
86 | } | 117 | } |
87 | } | 118 | } |
88 | 119 | ||
89 | impl CrateDefMap { | 120 | impl CrateDefMap { |
121 | pub(crate) fn crate_def_map_query( | ||
122 | db: &impl PersistentHirDatabase, | ||
123 | krate: Crate, | ||
124 | ) -> Arc<CrateDefMap> { | ||
125 | let def_map = { | ||
126 | let edition = krate.edition(db); | ||
127 | let mut modules: Arena<ModuleId, ModuleData> = Arena::default(); | ||
128 | let root = modules.alloc(ModuleData::default()); | ||
129 | CrateDefMap { | ||
130 | krate, | ||
131 | edition, | ||
132 | extern_prelude: FxHashMap::default(), | ||
133 | prelude: None, | ||
134 | root, | ||
135 | modules, | ||
136 | public_macros: FxHashMap::default(), | ||
137 | problems: CrateDefMapProblems::default(), | ||
138 | } | ||
139 | }; | ||
140 | let def_map = collector::collect_defs(db, def_map); | ||
141 | Arc::new(def_map) | ||
142 | } | ||
143 | |||
144 | pub(crate) fn root(&self) -> ModuleId { | ||
145 | self.root | ||
146 | } | ||
147 | |||
148 | pub(crate) fn problems(&self) -> &CrateDefMapProblems { | ||
149 | &self.problems | ||
150 | } | ||
151 | |||
152 | pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a { | ||
153 | self.modules.iter().map(|(id, _data)| id) | ||
154 | } | ||
155 | |||
156 | pub(crate) fn find_module_by_source( | ||
157 | &self, | ||
158 | file_id: HirFileId, | ||
159 | decl_id: Option<SourceFileItemId>, | ||
160 | ) -> Option<ModuleId> { | ||
161 | let decl_id = decl_id.map(|it| it.with_file_id(file_id)); | ||
162 | let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { | ||
163 | if decl_id.is_some() { | ||
164 | module_data.declaration == decl_id | ||
165 | } else { | ||
166 | module_data.definition.map(|it| it.into()) == Some(file_id) | ||
167 | } | ||
168 | })?; | ||
169 | Some(module_id) | ||
170 | } | ||
171 | |||
90 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | 172 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change |
91 | // the result. | 173 | // the result. |
92 | #[allow(unused)] | ||
93 | fn resolve_path_fp( | 174 | fn resolve_path_fp( |
94 | &self, | 175 | &self, |
95 | db: &impl PersistentHirDatabase, | 176 | db: &impl PersistentHirDatabase, |
@@ -182,7 +263,7 @@ impl CrateDefMap { | |||
182 | ); | 263 | ); |
183 | } | 264 | } |
184 | 265 | ||
185 | match self[module.module_id].items.get(&segment.name) { | 266 | match self[module.module_id].scope.items.get(&segment.name) { |
186 | Some(res) if !res.def.is_none() => res.def, | 267 | Some(res) if !res.def.is_none() => res.def, |
187 | _ => { | 268 | _ => { |
188 | log::debug!("path segment {:?} not found", segment.name); | 269 | log::debug!("path segment {:?} not found", segment.name); |
@@ -225,7 +306,8 @@ impl CrateDefMap { | |||
225 | } | 306 | } |
226 | 307 | ||
227 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | 308 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { |
228 | let from_crate_root = self[self.root].items.get(name).map_or(PerNs::none(), |it| it.def); | 309 | let from_crate_root = |
310 | self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def); | ||
229 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 311 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
230 | 312 | ||
231 | from_crate_root.or(from_extern_prelude) | 313 | from_crate_root.or(from_extern_prelude) |
@@ -241,7 +323,7 @@ impl CrateDefMap { | |||
241 | // - current module / scope | 323 | // - current module / scope |
242 | // - extern prelude | 324 | // - extern prelude |
243 | // - std prelude | 325 | // - std prelude |
244 | let from_scope = self[module].items.get(name).map_or(PerNs::none(), |it| it.def); | 326 | let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def); |
245 | let from_extern_prelude = | 327 | let from_extern_prelude = |
246 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 328 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
247 | let from_prelude = self.resolve_in_prelude(db, name); | 329 | let from_prelude = self.resolve_in_prelude(db, name); |
@@ -256,7 +338,7 @@ impl CrateDefMap { | |||
256 | fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> { | 338 | fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> { |
257 | if let Some(prelude) = self.prelude { | 339 | if let Some(prelude) = self.prelude { |
258 | let resolution = if prelude.krate == self.krate { | 340 | let resolution = if prelude.krate == self.krate { |
259 | self[prelude.module_id].items.get(name).cloned() | 341 | self[prelude.module_id].scope.items.get(name).cloned() |
260 | } else { | 342 | } else { |
261 | db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned() | 343 | db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned() |
262 | }; | 344 | }; |
diff --git a/crates/ra_hir/src/nameres/crate_def_map/collector.rs b/crates/ra_hir/src/nameres/crate_def_map/collector.rs index cd328b755..2fbfa9e34 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/collector.rs +++ b/crates/ra_hir/src/nameres/crate_def_map/collector.rs | |||
@@ -1,42 +1,25 @@ | |||
1 | use std::sync::Arc; | 1 | use arrayvec::ArrayVec; |
2 | |||
3 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
4 | use ra_arena::Arena; | 3 | use relative_path::RelativePathBuf; |
5 | use test_utils::tested_by; | 4 | use test_utils::tested_by; |
5 | use ra_db::FileId; | ||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, | 8 | Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, |
9 | Crate, PersistentHirDatabase, HirFileId, Name, Path, | 9 | PersistentHirDatabase, HirFileId, Name, Path, Problem, |
10 | KnownName, | 10 | KnownName, |
11 | nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode}, | 11 | nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode}, |
12 | ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, | 12 | ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, |
13 | module_tree::resolve_module_declaration, | ||
14 | }; | 13 | }; |
15 | 14 | ||
16 | use super::{CrateDefMap, ModuleId, ModuleData, raw}; | 15 | use super::{CrateDefMap, ModuleId, ModuleData, raw}; |
17 | 16 | ||
18 | #[allow(unused)] | 17 | pub(super) fn collect_defs( |
19 | pub(crate) fn crate_def_map_query( | ||
20 | db: &impl PersistentHirDatabase, | 18 | db: &impl PersistentHirDatabase, |
21 | krate: Crate, | 19 | mut def_map: CrateDefMap, |
22 | ) -> Arc<CrateDefMap> { | 20 | ) -> CrateDefMap { |
23 | let mut def_map = { | ||
24 | let edition = krate.edition(db); | ||
25 | let mut modules: Arena<ModuleId, ModuleData> = Arena::default(); | ||
26 | let root = modules.alloc(ModuleData::default()); | ||
27 | CrateDefMap { | ||
28 | krate, | ||
29 | edition, | ||
30 | extern_prelude: FxHashMap::default(), | ||
31 | prelude: None, | ||
32 | root, | ||
33 | modules, | ||
34 | public_macros: FxHashMap::default(), | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | // populate external prelude | 21 | // populate external prelude |
39 | for dep in krate.dependencies(db) { | 22 | for dep in def_map.krate.dependencies(db) { |
40 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); | 23 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); |
41 | if let Some(module) = dep.krate.root_module(db) { | 24 | if let Some(module) = dep.krate.root_module(db) { |
42 | def_map.extern_prelude.insert(dep.name.clone(), module.into()); | 25 | def_map.extern_prelude.insert(dep.name.clone(), module.into()); |
@@ -52,7 +35,6 @@ pub(crate) fn crate_def_map_query( | |||
52 | 35 | ||
53 | let mut collector = DefCollector { | 36 | let mut collector = DefCollector { |
54 | db, | 37 | db, |
55 | krate, | ||
56 | def_map, | 38 | def_map, |
57 | glob_imports: FxHashMap::default(), | 39 | glob_imports: FxHashMap::default(), |
58 | unresolved_imports: Vec::new(), | 40 | unresolved_imports: Vec::new(), |
@@ -60,14 +42,12 @@ pub(crate) fn crate_def_map_query( | |||
60 | global_macro_scope: FxHashMap::default(), | 42 | global_macro_scope: FxHashMap::default(), |
61 | }; | 43 | }; |
62 | collector.collect(); | 44 | collector.collect(); |
63 | let def_map = collector.finish(); | 45 | collector.finish() |
64 | Arc::new(def_map) | ||
65 | } | 46 | } |
66 | 47 | ||
67 | /// Walks the tree of module recursively | 48 | /// Walks the tree of module recursively |
68 | struct DefCollector<DB> { | 49 | struct DefCollector<DB> { |
69 | db: DB, | 50 | db: DB, |
70 | krate: Crate, | ||
71 | def_map: CrateDefMap, | 51 | def_map: CrateDefMap, |
72 | glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, raw::ImportId)>>, | 52 | glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, raw::ImportId)>>, |
73 | unresolved_imports: Vec<(ModuleId, raw::ImportId, raw::ImportData)>, | 53 | unresolved_imports: Vec<(ModuleId, raw::ImportId, raw::ImportData)>, |
@@ -75,23 +55,16 @@ struct DefCollector<DB> { | |||
75 | global_macro_scope: FxHashMap<Name, mbe::MacroRules>, | 55 | global_macro_scope: FxHashMap<Name, mbe::MacroRules>, |
76 | } | 56 | } |
77 | 57 | ||
78 | /// Walks a single module, populating defs, imports and macros | ||
79 | struct ModCollector<'a, D> { | ||
80 | def_collector: D, | ||
81 | module_id: ModuleId, | ||
82 | file_id: HirFileId, | ||
83 | raw_items: &'a raw::RawItems, | ||
84 | } | ||
85 | |||
86 | impl<'a, DB> DefCollector<&'a DB> | 58 | impl<'a, DB> DefCollector<&'a DB> |
87 | where | 59 | where |
88 | DB: PersistentHirDatabase, | 60 | DB: PersistentHirDatabase, |
89 | { | 61 | { |
90 | fn collect(&mut self) { | 62 | fn collect(&mut self) { |
91 | let crate_graph = self.db.crate_graph(); | 63 | let crate_graph = self.db.crate_graph(); |
92 | let file_id = crate_graph.crate_root(self.krate.crate_id()); | 64 | let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); |
93 | let raw_items = raw::RawItems::raw_items_query(self.db, file_id); | 65 | let raw_items = self.db.raw_items(file_id); |
94 | let module_id = self.def_map.root; | 66 | let module_id = self.def_map.root; |
67 | self.def_map.modules[module_id].definition = Some(file_id); | ||
95 | ModCollector { | 68 | ModCollector { |
96 | def_collector: &mut *self, | 69 | def_collector: &mut *self, |
97 | module_id, | 70 | module_id, |
@@ -123,10 +96,6 @@ where | |||
123 | } | 96 | } |
124 | } | 97 | } |
125 | 98 | ||
126 | fn alloc_module(&mut self) -> ModuleId { | ||
127 | self.def_map.modules.alloc(ModuleData::default()) | ||
128 | } | ||
129 | |||
130 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 99 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
131 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 100 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
132 | let mut resolved = Vec::new(); | 101 | let mut resolved = Vec::new(); |
@@ -184,7 +153,7 @@ where | |||
184 | if import.is_prelude { | 153 | if import.is_prelude { |
185 | tested_by!(std_prelude); | 154 | tested_by!(std_prelude); |
186 | self.def_map.prelude = Some(m); | 155 | self.def_map.prelude = Some(m); |
187 | } else if m.krate != self.krate { | 156 | } else if m.krate != self.def_map.krate { |
188 | tested_by!(glob_across_crates); | 157 | tested_by!(glob_across_crates); |
189 | // glob import from other crate => we can just import everything once | 158 | // glob import from other crate => we can just import everything once |
190 | let item_map = self.db.item_map(m.krate); | 159 | let item_map = self.db.item_map(m.krate); |
@@ -199,7 +168,7 @@ where | |||
199 | // glob import from same crate => we do an initial | 168 | // glob import from same crate => we do an initial |
200 | // import, and then need to propagate any further | 169 | // import, and then need to propagate any further |
201 | // additions | 170 | // additions |
202 | let scope = &self.def_map[m.module_id]; | 171 | let scope = &self.def_map[m.module_id].scope; |
203 | let items = scope | 172 | let items = scope |
204 | .items | 173 | .items |
205 | .iter() | 174 | .iter() |
@@ -243,11 +212,9 @@ where | |||
243 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | 212 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); |
244 | 213 | ||
245 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 214 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
246 | if let Some(root_module) = self.krate.root_module(self.db) { | 215 | if import.is_extern_crate && module_id == self.def_map.root { |
247 | if import.is_extern_crate && module_id == root_module.module_id { | 216 | if let Some(def) = def.take_types() { |
248 | if let Some(def) = def.take_types() { | 217 | self.def_map.extern_prelude.insert(name.clone(), def); |
249 | self.def_map.extern_prelude.insert(name.clone(), def); | ||
250 | } | ||
251 | } | 218 | } |
252 | } | 219 | } |
253 | let resolution = Resolution { def, import: Some(import_id) }; | 220 | let resolution = Resolution { def, import: Some(import_id) }; |
@@ -324,8 +291,7 @@ where | |||
324 | Some(it) => it, | 291 | Some(it) => it, |
325 | _ => return true, | 292 | _ => return true, |
326 | }; | 293 | }; |
327 | // FIXME: this should be a proper query | 294 | let def_map = self.db.crate_def_map(krate); |
328 | let def_map = crate_def_map_query(self.db, krate); | ||
329 | let rules = def_map.public_macros.get(&path.segments[1].name).cloned(); | 295 | let rules = def_map.public_macros.get(&path.segments[1].name).cloned(); |
330 | resolved.push((*module_id, *call_id, rules, tt.clone())); | 296 | resolved.push((*module_id, *call_id, rules, tt.clone())); |
331 | false | 297 | false |
@@ -367,6 +333,14 @@ where | |||
367 | } | 333 | } |
368 | } | 334 | } |
369 | 335 | ||
336 | /// Walks a single module, populating defs, imports and macros | ||
337 | struct ModCollector<'a, D> { | ||
338 | def_collector: D, | ||
339 | module_id: ModuleId, | ||
340 | file_id: HirFileId, | ||
341 | raw_items: &'a raw::RawItems, | ||
342 | } | ||
343 | |||
370 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | 344 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> |
371 | where | 345 | where |
372 | DB: PersistentHirDatabase, | 346 | DB: PersistentHirDatabase, |
@@ -389,8 +363,12 @@ where | |||
389 | fn collect_module(&mut self, module: &raw::ModuleData) { | 363 | fn collect_module(&mut self, module: &raw::ModuleData) { |
390 | match module { | 364 | match module { |
391 | // inline module, just recurse | 365 | // inline module, just recurse |
392 | raw::ModuleData::Definition { name, items } => { | 366 | raw::ModuleData::Definition { name, items, source_item_id } => { |
393 | let module_id = self.push_child_module(name.clone()); | 367 | let module_id = self.push_child_module( |
368 | name.clone(), | ||
369 | source_item_id.with_file_id(self.file_id), | ||
370 | None, | ||
371 | ); | ||
394 | ModCollector { | 372 | ModCollector { |
395 | def_collector: &mut *self.def_collector, | 373 | def_collector: &mut *self.def_collector, |
396 | module_id, | 374 | module_id, |
@@ -400,13 +378,20 @@ where | |||
400 | .collect(&*items); | 378 | .collect(&*items); |
401 | } | 379 | } |
402 | // out of line module, resovle, parse and recurse | 380 | // out of line module, resovle, parse and recurse |
403 | raw::ModuleData::Declaration { name } => { | 381 | raw::ModuleData::Declaration { name, source_item_id } => { |
404 | let module_id = self.push_child_module(name.clone()); | 382 | let source_item_id = source_item_id.with_file_id(self.file_id); |
405 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); | 383 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); |
406 | if let Some(file_id) = | 384 | let (file_ids, problem) = |
407 | resolve_module_declaration(self.def_collector.db, self.file_id, name, is_root) | 385 | resolve_submodule(self.def_collector.db, self.file_id, name, is_root); |
408 | { | 386 | |
409 | let raw_items = raw::RawItems::raw_items_query(self.def_collector.db, file_id); | 387 | if let Some(problem) = problem { |
388 | self.def_collector.def_map.problems.add(source_item_id, problem) | ||
389 | } | ||
390 | |||
391 | if let Some(&file_id) = file_ids.first() { | ||
392 | let module_id = | ||
393 | self.push_child_module(name.clone(), source_item_id, Some(file_id)); | ||
394 | let raw_items = self.def_collector.db.raw_items(file_id); | ||
410 | ModCollector { | 395 | ModCollector { |
411 | def_collector: &mut *self.def_collector, | 396 | def_collector: &mut *self.def_collector, |
412 | module_id, | 397 | module_id, |
@@ -419,15 +404,23 @@ where | |||
419 | } | 404 | } |
420 | } | 405 | } |
421 | 406 | ||
422 | fn push_child_module(&mut self, name: Name) -> ModuleId { | 407 | fn push_child_module( |
423 | let res = self.def_collector.alloc_module(); | 408 | &mut self, |
424 | self.def_collector.def_map.modules[res].parent = Some(self.module_id); | 409 | name: Name, |
425 | self.def_collector.def_map.modules[self.module_id].children.insert(name, res); | 410 | declaration: SourceItemId, |
411 | definition: Option<FileId>, | ||
412 | ) -> ModuleId { | ||
413 | let modules = &mut self.def_collector.def_map.modules; | ||
414 | let res = modules.alloc(ModuleData::default()); | ||
415 | modules[res].parent = Some(self.module_id); | ||
416 | modules[res].declaration = Some(declaration); | ||
417 | modules[res].definition = definition; | ||
418 | modules[self.module_id].children.insert(name, res); | ||
426 | res | 419 | res |
427 | } | 420 | } |
428 | 421 | ||
429 | fn define_def(&mut self, def: &raw::DefData) { | 422 | fn define_def(&mut self, def: &raw::DefData) { |
430 | let module = Module { krate: self.def_collector.krate, module_id: self.module_id }; | 423 | let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }; |
431 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into()); | 424 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into()); |
432 | macro_rules! id { | 425 | macro_rules! id { |
433 | () => { | 426 | () => { |
@@ -462,7 +455,7 @@ where | |||
462 | 455 | ||
463 | let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; | 456 | let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; |
464 | let macro_call_id = MacroCallLoc { | 457 | let macro_call_id = MacroCallLoc { |
465 | module: Module { krate: self.def_collector.krate, module_id: self.module_id }, | 458 | module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }, |
466 | source_item_id, | 459 | source_item_id, |
467 | } | 460 | } |
468 | .id(self.def_collector.db); | 461 | .id(self.def_collector.db); |
@@ -491,3 +484,44 @@ where | |||
491 | fn is_macro_rules(path: &Path) -> bool { | 484 | fn is_macro_rules(path: &Path) -> bool { |
492 | path.as_ident().and_then(Name::as_known_name) == Some(KnownName::MacroRules) | 485 | path.as_ident().and_then(Name::as_known_name) == Some(KnownName::MacroRules) |
493 | } | 486 | } |
487 | |||
488 | fn resolve_submodule( | ||
489 | db: &impl PersistentHirDatabase, | ||
490 | file_id: HirFileId, | ||
491 | name: &Name, | ||
492 | is_root: bool, | ||
493 | ) -> (Vec<FileId>, Option<Problem>) { | ||
494 | // FIXME: handle submodules of inline modules properly | ||
495 | let file_id = file_id.original_file(db); | ||
496 | let source_root_id = db.file_source_root(file_id); | ||
497 | let path = db.file_relative_path(file_id); | ||
498 | let root = RelativePathBuf::default(); | ||
499 | let dir_path = path.parent().unwrap_or(&root); | ||
500 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
501 | let is_dir_owner = is_root || mod_name == "mod"; | ||
502 | |||
503 | let file_mod = dir_path.join(format!("{}.rs", name)); | ||
504 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | ||
505 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); | ||
506 | let mut candidates = ArrayVec::<[_; 2]>::new(); | ||
507 | if is_dir_owner { | ||
508 | candidates.push(file_mod.clone()); | ||
509 | candidates.push(dir_mod); | ||
510 | } else { | ||
511 | candidates.push(file_dir_mod.clone()); | ||
512 | }; | ||
513 | let sr = db.source_root(source_root_id); | ||
514 | let points_to = candidates | ||
515 | .into_iter() | ||
516 | .filter_map(|path| sr.files.get(&path)) | ||
517 | .map(|&it| it) | ||
518 | .collect::<Vec<_>>(); | ||
519 | let problem = if points_to.is_empty() { | ||
520 | Some(Problem::UnresolvedModule { | ||
521 | candidate: if is_dir_owner { file_mod } else { file_dir_mod }, | ||
522 | }) | ||
523 | } else { | ||
524 | None | ||
525 | }; | ||
526 | (points_to, problem) | ||
527 | } | ||
diff --git a/crates/ra_hir/src/nameres/crate_def_map/raw.rs b/crates/ra_hir/src/nameres/crate_def_map/raw.rs index fe832b8da..f064f722c 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/raw.rs +++ b/crates/ra_hir/src/nameres/crate_def_map/raw.rs | |||
@@ -3,6 +3,7 @@ use std::{ | |||
3 | ops::Index, | 3 | ops::Index, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use test_utils::tested_by; | ||
6 | use ra_db::FileId; | 7 | use ra_db::FileId; |
7 | use ra_arena::{Arena, impl_arena_id, RawId}; | 8 | use ra_arena::{Arena, impl_arena_id, RawId}; |
8 | use ra_syntax::{ | 9 | use ra_syntax::{ |
@@ -15,8 +16,8 @@ use crate::{ | |||
15 | ids::{SourceFileItemId, SourceFileItems}, | 16 | ids::{SourceFileItemId, SourceFileItems}, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | #[derive(Default, PartialEq, Eq)] | 19 | #[derive(Debug, Default, PartialEq, Eq)] |
19 | pub(crate) struct RawItems { | 20 | pub struct RawItems { |
20 | modules: Arena<Module, ModuleData>, | 21 | modules: Arena<Module, ModuleData>, |
21 | imports: Arena<ImportId, ImportData>, | 22 | imports: Arena<ImportId, ImportData>, |
22 | defs: Arena<Def, DefData>, | 23 | defs: Arena<Def, DefData>, |
@@ -26,18 +27,21 @@ pub(crate) struct RawItems { | |||
26 | } | 27 | } |
27 | 28 | ||
28 | impl RawItems { | 29 | impl RawItems { |
29 | pub(crate) fn items(&self) -> &[RawItem] { | 30 | pub(crate) fn raw_items_query( |
30 | &self.items | 31 | db: &impl PersistentHirDatabase, |
31 | } | 32 | file_id: FileId, |
32 | 33 | ) -> Arc<RawItems> { | |
33 | pub(crate) fn raw_items_query(db: &impl PersistentHirDatabase, file_id: FileId) -> RawItems { | ||
34 | let mut collector = RawItemsCollector { | 34 | let mut collector = RawItemsCollector { |
35 | raw_items: RawItems::default(), | 35 | raw_items: RawItems::default(), |
36 | source_file_items: db.file_items(file_id.into()), | 36 | source_file_items: db.file_items(file_id.into()), |
37 | }; | 37 | }; |
38 | let source_file = db.parse(file_id); | 38 | let source_file = db.parse(file_id); |
39 | collector.process_module(None, &*source_file); | 39 | collector.process_module(None, &*source_file); |
40 | collector.raw_items | 40 | Arc::new(collector.raw_items) |
41 | } | ||
42 | |||
43 | pub(crate) fn items(&self) -> &[RawItem] { | ||
44 | &self.items | ||
41 | } | 45 | } |
42 | 46 | ||
43 | // We can't use queries during name resolution for fear of cycles, so this | 47 | // We can't use queries during name resolution for fear of cycles, so this |
@@ -81,7 +85,7 @@ impl Index<Macro> for RawItems { | |||
81 | } | 85 | } |
82 | } | 86 | } |
83 | 87 | ||
84 | #[derive(PartialEq, Eq, Clone, Copy)] | 88 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
85 | pub(crate) enum RawItem { | 89 | pub(crate) enum RawItem { |
86 | Module(Module), | 90 | Module(Module), |
87 | Import(ImportId), | 91 | Import(ImportId), |
@@ -89,24 +93,24 @@ pub(crate) enum RawItem { | |||
89 | Macro(Macro), | 93 | Macro(Macro), |
90 | } | 94 | } |
91 | 95 | ||
92 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | 96 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
93 | pub(crate) struct Module(RawId); | 97 | pub(crate) struct Module(RawId); |
94 | impl_arena_id!(Module); | 98 | impl_arena_id!(Module); |
95 | 99 | ||
96 | #[derive(PartialEq, Eq)] | 100 | #[derive(Debug, PartialEq, Eq)] |
97 | pub(crate) enum ModuleData { | 101 | pub(crate) enum ModuleData { |
98 | Declaration { name: Name }, | 102 | Declaration { name: Name, source_item_id: SourceFileItemId }, |
99 | Definition { name: Name, items: Vec<RawItem> }, | 103 | Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, |
100 | } | 104 | } |
101 | 105 | ||
102 | pub(crate) use crate::nameres::lower::ImportId; | 106 | pub(crate) use crate::nameres::lower::ImportId; |
103 | pub(super) use crate::nameres::lower::ImportData; | 107 | pub(super) use crate::nameres::lower::ImportData; |
104 | 108 | ||
105 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | 109 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
106 | pub(crate) struct Def(RawId); | 110 | pub(crate) struct Def(RawId); |
107 | impl_arena_id!(Def); | 111 | impl_arena_id!(Def); |
108 | 112 | ||
109 | #[derive(PartialEq, Eq)] | 113 | #[derive(Debug, PartialEq, Eq)] |
110 | pub(crate) struct DefData { | 114 | pub(crate) struct DefData { |
111 | pub(crate) source_item_id: SourceFileItemId, | 115 | pub(crate) source_item_id: SourceFileItemId, |
112 | pub(crate) name: Name, | 116 | pub(crate) name: Name, |
@@ -124,11 +128,11 @@ pub(crate) enum DefKind { | |||
124 | TypeAlias, | 128 | TypeAlias, |
125 | } | 129 | } |
126 | 130 | ||
127 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | 131 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
128 | pub(crate) struct Macro(RawId); | 132 | pub(crate) struct Macro(RawId); |
129 | impl_arena_id!(Macro); | 133 | impl_arena_id!(Macro); |
130 | 134 | ||
131 | #[derive(PartialEq, Eq)] | 135 | #[derive(Debug, PartialEq, Eq)] |
132 | pub(crate) struct MacroData { | 136 | pub(crate) struct MacroData { |
133 | pub(crate) source_item_id: SourceFileItemId, | 137 | pub(crate) source_item_id: SourceFileItemId, |
134 | pub(crate) path: Path, | 138 | pub(crate) path: Path, |
@@ -191,18 +195,25 @@ impl RawItemsCollector { | |||
191 | Some(it) => it.as_name(), | 195 | Some(it) => it.as_name(), |
192 | None => return, | 196 | None => return, |
193 | }; | 197 | }; |
198 | let source_item_id = self.source_file_items.id_of_unchecked(module.syntax()); | ||
194 | if module.has_semi() { | 199 | if module.has_semi() { |
195 | let item = self.raw_items.modules.alloc(ModuleData::Declaration { name }); | 200 | let item = |
201 | self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id }); | ||
196 | self.push_item(current_module, RawItem::Module(item)); | 202 | self.push_item(current_module, RawItem::Module(item)); |
197 | return; | 203 | return; |
198 | } | 204 | } |
199 | 205 | ||
200 | if let Some(item_list) = module.item_list() { | 206 | if let Some(item_list) = module.item_list() { |
201 | let item = | 207 | let item = self.raw_items.modules.alloc(ModuleData::Definition { |
202 | self.raw_items.modules.alloc(ModuleData::Definition { name, items: Vec::new() }); | 208 | name, |
209 | source_item_id, | ||
210 | items: Vec::new(), | ||
211 | }); | ||
203 | self.process_module(Some(item), item_list); | 212 | self.process_module(Some(item), item_list); |
204 | self.push_item(current_module, RawItem::Module(item)); | 213 | self.push_item(current_module, RawItem::Module(item)); |
214 | return; | ||
205 | } | 215 | } |
216 | tested_by!(name_res_works_for_broken_modules); | ||
206 | } | 217 | } |
207 | 218 | ||
208 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) { | 219 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) { |
diff --git a/crates/ra_hir/src/nameres/crate_def_map/tests.rs b/crates/ra_hir/src/nameres/crate_def_map/tests.rs index a56dbaf90..742a19e5c 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/tests.rs +++ b/crates/ra_hir/src/nameres/crate_def_map/tests.rs | |||
@@ -15,7 +15,7 @@ fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc | |||
15 | } | 15 | } |
16 | let crate_id = db.crate_graph().iter().next().unwrap(); | 16 | let crate_id = db.crate_graph().iter().next().unwrap(); |
17 | let krate = Crate { crate_id }; | 17 | let krate = Crate { crate_id }; |
18 | collector::crate_def_map_query(&db, krate) | 18 | db.crate_def_map(krate) |
19 | } | 19 | } |
20 | 20 | ||
21 | fn render_crate_def_map(map: &CrateDefMap) -> String { | 21 | fn render_crate_def_map(map: &CrateDefMap) -> String { |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 9b151bb0c..961e442a9 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -7,7 +7,7 @@ use crate::{ | |||
7 | ItemMap, | 7 | ItemMap, |
8 | PersistentHirDatabase, | 8 | PersistentHirDatabase, |
9 | mock::MockDatabase, | 9 | mock::MockDatabase, |
10 | module_tree::ModuleId, | 10 | nameres::crate_def_map::ModuleId, |
11 | }; | 11 | }; |
12 | use super::Resolution; | 12 | use super::Resolution; |
13 | 13 | ||
@@ -359,6 +359,7 @@ fn std_prelude() { | |||
359 | let main_id = db.file_id_of("/main.rs"); | 359 | let main_id = db.file_id_of("/main.rs"); |
360 | 360 | ||
361 | let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); | 361 | let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); |
362 | eprintln!("module = {:?}", module); | ||
362 | let krate = module.krate(&db).unwrap(); | 363 | let krate = module.krate(&db).unwrap(); |
363 | let item_map = db.item_map(krate); | 364 | let item_map = db.item_map(krate); |
364 | 365 | ||