diff options
author | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
commit | b21d9337d9200e2cfdc90b386591c72c302dc03e (patch) | |
tree | f81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_hir_def/src/nameres | |
parent | 18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff) | |
parent | ce07a2daa9e53aa86a769f8641b14c2878444fbc (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_hir_def/src/nameres')
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 637 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/path_resolution.rs | 105 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/raw.rs | 105 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests.rs | 53 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/globs.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/incremental.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/macros.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | 4 |
8 files changed, 515 insertions, 438 deletions
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index fd8245113..b9f40d3dd 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -4,14 +4,15 @@ | |||
4 | //! resolves imports and expands macros. | 4 | //! resolves imports and expands macros. |
5 | 5 | ||
6 | use hir_expand::{ | 6 | use hir_expand::{ |
7 | builtin_derive::find_builtin_derive, | ||
7 | builtin_macro::find_builtin_macro, | 8 | builtin_macro::find_builtin_macro, |
8 | name::{self, AsName, Name}, | 9 | name::{name, AsName, Name}, |
9 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, | 10 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
10 | }; | 11 | }; |
11 | use ra_cfg::CfgOptions; | 12 | use ra_cfg::CfgOptions; |
12 | use ra_db::{CrateId, FileId}; | 13 | use ra_db::{CrateId, FileId}; |
13 | use ra_syntax::ast; | 14 | use ra_syntax::ast; |
14 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::FxHashMap; |
15 | use test_utils::tested_by; | 16 | use test_utils::tested_by; |
16 | 17 | ||
17 | use crate::{ | 18 | use crate::{ |
@@ -19,13 +20,12 @@ use crate::{ | |||
19 | db::DefDatabase, | 20 | db::DefDatabase, |
20 | nameres::{ | 21 | nameres::{ |
21 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 22 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
22 | raw, CrateDefMap, ModuleData, Resolution, ResolveMode, | 23 | raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, |
23 | }, | 24 | }, |
24 | path::{Path, PathKind}, | 25 | path::{ModPath, PathKind}, |
25 | per_ns::PerNs, | 26 | per_ns::PerNs, |
26 | AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId, | 27 | AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, |
27 | Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId, | 28 | LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
28 | TraitId, TypeAliasLoc, UnionId, | ||
29 | }; | 29 | }; |
30 | 30 | ||
31 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 31 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { |
@@ -57,68 +57,63 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
57 | def_map, | 57 | def_map, |
58 | glob_imports: FxHashMap::default(), | 58 | glob_imports: FxHashMap::default(), |
59 | unresolved_imports: Vec::new(), | 59 | unresolved_imports: Vec::new(), |
60 | resolved_imports: Vec::new(), | ||
61 | |||
60 | unexpanded_macros: Vec::new(), | 62 | unexpanded_macros: Vec::new(), |
63 | unexpanded_attribute_macros: Vec::new(), | ||
61 | mod_dirs: FxHashMap::default(), | 64 | mod_dirs: FxHashMap::default(), |
62 | macro_stack_monitor: MacroStackMonitor::default(), | ||
63 | poison_macros: FxHashSet::default(), | ||
64 | cfg_options, | 65 | cfg_options, |
65 | }; | 66 | }; |
66 | collector.collect(); | 67 | collector.collect(); |
67 | collector.finish() | 68 | collector.finish() |
68 | } | 69 | } |
69 | 70 | ||
70 | #[derive(Default)] | 71 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
71 | struct MacroStackMonitor { | 72 | enum PartialResolvedImport { |
72 | counts: FxHashMap<MacroDefId, u32>, | 73 | /// None of any namespaces is resolved |
73 | 74 | Unresolved, | |
74 | /// Mainly use for test | 75 | /// One of namespaces is resolved |
75 | validator: Option<Box<dyn Fn(u32) -> bool>>, | 76 | Indeterminate(PerNs), |
77 | /// All namespaces are resolved, OR it is came from other crate | ||
78 | Resolved(PerNs), | ||
76 | } | 79 | } |
77 | 80 | ||
78 | impl MacroStackMonitor { | 81 | impl PartialResolvedImport { |
79 | fn increase(&mut self, macro_def_id: MacroDefId) { | 82 | fn namespaces(&self) -> PerNs { |
80 | *self.counts.entry(macro_def_id).or_default() += 1; | 83 | match self { |
81 | } | 84 | PartialResolvedImport::Unresolved => PerNs::none(), |
82 | 85 | PartialResolvedImport::Indeterminate(ns) => *ns, | |
83 | fn decrease(&mut self, macro_def_id: MacroDefId) { | 86 | PartialResolvedImport::Resolved(ns) => *ns, |
84 | *self.counts.entry(macro_def_id).or_default() -= 1; | 87 | } |
85 | } | 88 | } |
89 | } | ||
86 | 90 | ||
87 | fn is_poison(&self, macro_def_id: MacroDefId) -> bool { | 91 | #[derive(Clone, Debug, Eq, PartialEq)] |
88 | let cur = *self.counts.get(¯o_def_id).unwrap_or(&0); | 92 | struct ImportDirective { |
93 | module_id: LocalModuleId, | ||
94 | import_id: raw::Import, | ||
95 | import: raw::ImportData, | ||
96 | status: PartialResolvedImport, | ||
97 | } | ||
89 | 98 | ||
90 | if let Some(validator) = &self.validator { | 99 | #[derive(Clone, Debug, Eq, PartialEq)] |
91 | validator(cur) | 100 | struct MacroDirective { |
92 | } else { | 101 | module_id: LocalModuleId, |
93 | cur > 100 | 102 | ast_id: AstId<ast::MacroCall>, |
94 | } | 103 | path: ModPath, |
95 | } | 104 | legacy: Option<MacroCallId>, |
96 | } | 105 | } |
97 | 106 | ||
98 | /// Walks the tree of module recursively | 107 | /// Walks the tree of module recursively |
99 | struct DefCollector<'a, DB> { | 108 | struct DefCollector<'a, DB> { |
100 | db: &'a DB, | 109 | db: &'a DB, |
101 | def_map: CrateDefMap, | 110 | def_map: CrateDefMap, |
102 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, | 111 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>, |
103 | unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, | 112 | unresolved_imports: Vec<ImportDirective>, |
104 | unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, | 113 | resolved_imports: Vec<ImportDirective>, |
114 | unexpanded_macros: Vec<MacroDirective>, | ||
115 | unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>, | ||
105 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 116 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
106 | |||
107 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | ||
108 | /// To prevent stack overflow, we add a deep counter here for prevent that. | ||
109 | macro_stack_monitor: MacroStackMonitor, | ||
110 | /// Some macros are not well-behavior, which leads to infinite loop | ||
111 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } | ||
112 | /// We mark it down and skip it in collector | ||
113 | /// | ||
114 | /// FIXME: | ||
115 | /// Right now it only handle a poison macro in a single crate, | ||
116 | /// such that if other crate try to call that macro, | ||
117 | /// the whole process will do again until it became poisoned in that crate. | ||
118 | /// We should handle this macro set globally | ||
119 | /// However, do we want to put it as a global variable? | ||
120 | poison_macros: FxHashSet<MacroDefId>, | ||
121 | |||
122 | cfg_options: &'a CfgOptions, | 117 | cfg_options: &'a CfgOptions, |
123 | } | 118 | } |
124 | 119 | ||
@@ -131,7 +126,7 @@ where | |||
131 | let file_id = crate_graph.crate_root(self.def_map.krate); | 126 | let file_id = crate_graph.crate_root(self.def_map.krate); |
132 | let raw_items = self.db.raw_items(file_id.into()); | 127 | let raw_items = self.db.raw_items(file_id.into()); |
133 | let module_id = self.def_map.root; | 128 | let module_id = self.def_map.root; |
134 | self.def_map.modules[module_id].definition = Some(file_id); | 129 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
135 | ModCollector { | 130 | ModCollector { |
136 | def_collector: &mut *self, | 131 | def_collector: &mut *self, |
137 | module_id, | 132 | module_id, |
@@ -145,9 +140,11 @@ where | |||
145 | let mut i = 0; | 140 | let mut i = 0; |
146 | loop { | 141 | loop { |
147 | self.db.check_canceled(); | 142 | self.db.check_canceled(); |
148 | match (self.resolve_imports(), self.resolve_macros()) { | 143 | self.resolve_imports(); |
149 | (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break, | 144 | |
150 | _ => i += 1, | 145 | match self.resolve_macros() { |
146 | ReachedFixedPoint::Yes => break, | ||
147 | ReachedFixedPoint::No => i += 1, | ||
151 | } | 148 | } |
152 | if i == 1000 { | 149 | if i == 1000 { |
153 | log::error!("name resolution is stuck"); | 150 | log::error!("name resolution is stuck"); |
@@ -155,10 +152,26 @@ where | |||
155 | } | 152 | } |
156 | } | 153 | } |
157 | 154 | ||
155 | // Resolve all indeterminate resolved imports again | ||
156 | // As some of the macros will expand newly import shadowing partial resolved imports | ||
157 | // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports` | ||
158 | // correctly | ||
159 | let partial_resolved = self.resolved_imports.iter().filter_map(|directive| { | ||
160 | if let PartialResolvedImport::Indeterminate(_) = directive.status { | ||
161 | let mut directive = directive.clone(); | ||
162 | directive.status = PartialResolvedImport::Unresolved; | ||
163 | Some(directive) | ||
164 | } else { | ||
165 | None | ||
166 | } | ||
167 | }); | ||
168 | self.unresolved_imports.extend(partial_resolved); | ||
169 | self.resolve_imports(); | ||
170 | |||
158 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 171 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
159 | // show unresolved imports in completion, etc | 172 | // show unresolved imports in completion, etc |
160 | for (module_id, import, import_data) in unresolved_imports { | 173 | for directive in unresolved_imports { |
161 | self.record_resolved_import(module_id, PerNs::none(), import, &import_data) | 174 | self.record_resolved_import(&directive) |
162 | } | 175 | } |
163 | } | 176 | } |
164 | 177 | ||
@@ -201,24 +214,20 @@ where | |||
201 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 214 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
202 | // crate root, even if the parent modules is **not** visible. | 215 | // crate root, even if the parent modules is **not** visible. |
203 | if export { | 216 | if export { |
204 | self.update( | 217 | self.update(self.def_map.root, &[(name, PerNs::macros(macro_))]); |
205 | self.def_map.root, | ||
206 | None, | ||
207 | &[(name, Resolution { def: PerNs::macros(macro_), import: None })], | ||
208 | ); | ||
209 | } | 218 | } |
210 | } | 219 | } |
211 | 220 | ||
212 | /// Define a legacy textual scoped macro in module | 221 | /// Define a legacy textual scoped macro in module |
213 | /// | 222 | /// |
214 | /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module. | 223 | /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module. |
215 | /// It will clone all macros from parent legacy scope, whose definition is prior to | 224 | /// It will clone all macros from parent legacy scope, whose definition is prior to |
216 | /// the definition of current module. | 225 | /// the definition of current module. |
217 | /// And also, `macro_use` on a module will import all legacy macros visable inside to | 226 | /// And also, `macro_use` on a module will import all legacy macros visible inside to |
218 | /// current legacy scope, with possible shadowing. | 227 | /// current legacy scope, with possible shadowing. |
219 | fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) { | 228 | fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) { |
220 | // Always shadowing | 229 | // Always shadowing |
221 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); | 230 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); |
222 | } | 231 | } |
223 | 232 | ||
224 | /// Import macros from `#[macro_use] extern crate`. | 233 | /// Import macros from `#[macro_use] extern crate`. |
@@ -259,31 +268,43 @@ where | |||
259 | } | 268 | } |
260 | } | 269 | } |
261 | 270 | ||
262 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 271 | /// Import resolution |
263 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 272 | /// |
264 | let mut resolved = Vec::new(); | 273 | /// This is a fix point algorithm. We resolve imports until no forward |
265 | imports.retain(|(module_id, import, import_data)| { | 274 | /// progress in resolving imports is made |
266 | let (def, fp) = self.resolve_import(*module_id, import_data); | 275 | fn resolve_imports(&mut self) { |
267 | if fp == ReachedFixedPoint::Yes { | 276 | let mut n_previous_unresolved = self.unresolved_imports.len() + 1; |
268 | resolved.push((*module_id, def, *import, import_data.clone())) | 277 | |
278 | while self.unresolved_imports.len() < n_previous_unresolved { | ||
279 | n_previous_unresolved = self.unresolved_imports.len(); | ||
280 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | ||
281 | for mut directive in imports { | ||
282 | directive.status = self.resolve_import(directive.module_id, &directive.import); | ||
283 | |||
284 | match directive.status { | ||
285 | PartialResolvedImport::Indeterminate(_) => { | ||
286 | self.record_resolved_import(&directive); | ||
287 | // FIXME: For avoid performance regression, | ||
288 | // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved) | ||
289 | self.resolved_imports.push(directive) | ||
290 | } | ||
291 | PartialResolvedImport::Resolved(_) => { | ||
292 | self.record_resolved_import(&directive); | ||
293 | self.resolved_imports.push(directive) | ||
294 | } | ||
295 | PartialResolvedImport::Unresolved => { | ||
296 | self.unresolved_imports.push(directive); | ||
297 | } | ||
298 | } | ||
269 | } | 299 | } |
270 | fp == ReachedFixedPoint::No | ||
271 | }); | ||
272 | self.unresolved_imports = imports; | ||
273 | // Resolves imports, filling-in module scopes | ||
274 | let result = | ||
275 | if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No }; | ||
276 | for (module_id, def, import, import_data) in resolved { | ||
277 | self.record_resolved_import(module_id, def, import, &import_data) | ||
278 | } | 300 | } |
279 | result | ||
280 | } | 301 | } |
281 | 302 | ||
282 | fn resolve_import( | 303 | fn resolve_import( |
283 | &self, | 304 | &self, |
284 | module_id: LocalModuleId, | 305 | module_id: LocalModuleId, |
285 | import: &raw::ImportData, | 306 | import: &raw::ImportData, |
286 | ) -> (PerNs, ReachedFixedPoint) { | 307 | ) -> PartialResolvedImport { |
287 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | 308 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); |
288 | if import.is_extern_crate { | 309 | if import.is_extern_crate { |
289 | let res = self.def_map.resolve_name_in_extern_prelude( | 310 | let res = self.def_map.resolve_name_in_extern_prelude( |
@@ -292,26 +313,45 @@ where | |||
292 | .as_ident() | 313 | .as_ident() |
293 | .expect("extern crate should have been desugared to one-element path"), | 314 | .expect("extern crate should have been desugared to one-element path"), |
294 | ); | 315 | ); |
295 | (res, ReachedFixedPoint::Yes) | 316 | PartialResolvedImport::Resolved(res) |
296 | } else { | 317 | } else { |
297 | let res = self.def_map.resolve_path_fp_with_macro( | 318 | let res = self.def_map.resolve_path_fp_with_macro( |
298 | self.db, | 319 | self.db, |
299 | ResolveMode::Import, | 320 | ResolveMode::Import, |
300 | module_id, | 321 | module_id, |
301 | &import.path, | 322 | &import.path, |
323 | BuiltinShadowMode::Module, | ||
302 | ); | 324 | ); |
303 | 325 | ||
304 | (res.resolved_def, res.reached_fixedpoint) | 326 | let def = res.resolved_def; |
327 | if res.reached_fixedpoint == ReachedFixedPoint::No { | ||
328 | return PartialResolvedImport::Unresolved; | ||
329 | } | ||
330 | |||
331 | if let Some(krate) = res.krate { | ||
332 | if krate != self.def_map.krate { | ||
333 | return PartialResolvedImport::Resolved(def); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | // Check whether all namespace is resolved | ||
338 | if def.take_types().is_some() | ||
339 | && def.take_values().is_some() | ||
340 | && def.take_macros().is_some() | ||
341 | { | ||
342 | PartialResolvedImport::Resolved(def) | ||
343 | } else { | ||
344 | PartialResolvedImport::Indeterminate(def) | ||
345 | } | ||
305 | } | 346 | } |
306 | } | 347 | } |
307 | 348 | ||
308 | fn record_resolved_import( | 349 | fn record_resolved_import(&mut self, directive: &ImportDirective) { |
309 | &mut self, | 350 | let module_id = directive.module_id; |
310 | module_id: LocalModuleId, | 351 | let import_id = directive.import_id; |
311 | def: PerNs, | 352 | let import = &directive.import; |
312 | import_id: LocalImportId, | 353 | let def = directive.status.namespaces(); |
313 | import: &raw::ImportData, | 354 | |
314 | ) { | ||
315 | if import.is_glob { | 355 | if import.is_glob { |
316 | log::debug!("glob import: {:?}", import); | 356 | log::debug!("glob import: {:?}", import); |
317 | match def.take_types() { | 357 | match def.take_types() { |
@@ -326,13 +366,9 @@ where | |||
326 | let scope = &item_map[m.local_id].scope; | 366 | let scope = &item_map[m.local_id].scope; |
327 | 367 | ||
328 | // Module scoped macros is included | 368 | // Module scoped macros is included |
329 | let items = scope | 369 | let items = scope.collect_resolutions(); |
330 | .items | ||
331 | .iter() | ||
332 | .map(|(name, res)| (name.clone(), res.clone())) | ||
333 | .collect::<Vec<_>>(); | ||
334 | 370 | ||
335 | self.update(module_id, Some(import_id), &items); | 371 | self.update(module_id, &items); |
336 | } else { | 372 | } else { |
337 | // glob import from same crate => we do an initial | 373 | // glob import from same crate => we do an initial |
338 | // import, and then need to propagate any further | 374 | // import, and then need to propagate any further |
@@ -340,18 +376,14 @@ where | |||
340 | let scope = &self.def_map[m.local_id].scope; | 376 | let scope = &self.def_map[m.local_id].scope; |
341 | 377 | ||
342 | // Module scoped macros is included | 378 | // Module scoped macros is included |
343 | let items = scope | 379 | let items = scope.collect_resolutions(); |
344 | .items | ||
345 | .iter() | ||
346 | .map(|(name, res)| (name.clone(), res.clone())) | ||
347 | .collect::<Vec<_>>(); | ||
348 | 380 | ||
349 | self.update(module_id, Some(import_id), &items); | 381 | self.update(module_id, &items); |
350 | // record the glob import in case we add further items | 382 | // record the glob import in case we add further items |
351 | self.glob_imports | 383 | let glob = self.glob_imports.entry(m.local_id).or_default(); |
352 | .entry(m.local_id) | 384 | if !glob.iter().any(|it| *it == (module_id, import_id)) { |
353 | .or_default() | 385 | glob.push((module_id, import_id)); |
354 | .push((module_id, import_id)); | 386 | } |
355 | } | 387 | } |
356 | } | 388 | } |
357 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | 389 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { |
@@ -361,17 +393,14 @@ where | |||
361 | let resolutions = enum_data | 393 | let resolutions = enum_data |
362 | .variants | 394 | .variants |
363 | .iter() | 395 | .iter() |
364 | .filter_map(|(local_id, variant_data)| { | 396 | .map(|(local_id, variant_data)| { |
365 | let name = variant_data.name.clone(); | 397 | let name = variant_data.name.clone(); |
366 | let variant = EnumVariantId { parent: e, local_id }; | 398 | let variant = EnumVariantId { parent: e, local_id }; |
367 | let res = Resolution { | 399 | let res = PerNs::both(variant.into(), variant.into()); |
368 | def: PerNs::both(variant.into(), variant.into()), | 400 | (name, res) |
369 | import: Some(import_id), | ||
370 | }; | ||
371 | Some((name, res)) | ||
372 | }) | 401 | }) |
373 | .collect::<Vec<_>>(); | 402 | .collect::<Vec<_>>(); |
374 | self.update(module_id, Some(import_id), &resolutions); | 403 | self.update(module_id, &resolutions); |
375 | } | 404 | } |
376 | Some(d) => { | 405 | Some(d) => { |
377 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | 406 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); |
@@ -383,7 +412,7 @@ where | |||
383 | } else { | 412 | } else { |
384 | match import.path.segments.last() { | 413 | match import.path.segments.last() { |
385 | Some(last_segment) => { | 414 | Some(last_segment) => { |
386 | let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); | 415 | let name = import.alias.clone().unwrap_or_else(|| last_segment.clone()); |
387 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | 416 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); |
388 | 417 | ||
389 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 418 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
@@ -393,62 +422,31 @@ where | |||
393 | } | 422 | } |
394 | } | 423 | } |
395 | 424 | ||
396 | let resolution = Resolution { def, import: Some(import_id) }; | 425 | self.update(module_id, &[(name, def)]); |
397 | self.update(module_id, Some(import_id), &[(name, resolution)]); | ||
398 | } | 426 | } |
399 | None => tested_by!(bogus_paths), | 427 | None => tested_by!(bogus_paths), |
400 | } | 428 | } |
401 | } | 429 | } |
402 | } | 430 | } |
403 | 431 | ||
404 | fn update( | 432 | fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) { |
405 | &mut self, | 433 | self.update_recursive(module_id, resolutions, 0) |
406 | module_id: LocalModuleId, | ||
407 | import: Option<LocalImportId>, | ||
408 | resolutions: &[(Name, Resolution)], | ||
409 | ) { | ||
410 | self.update_recursive(module_id, import, resolutions, 0) | ||
411 | } | 434 | } |
412 | 435 | ||
413 | fn update_recursive( | 436 | fn update_recursive( |
414 | &mut self, | 437 | &mut self, |
415 | module_id: LocalModuleId, | 438 | module_id: LocalModuleId, |
416 | import: Option<LocalImportId>, | 439 | resolutions: &[(Name, PerNs)], |
417 | resolutions: &[(Name, Resolution)], | ||
418 | depth: usize, | 440 | depth: usize, |
419 | ) { | 441 | ) { |
420 | if depth > 100 { | 442 | if depth > 100 { |
421 | // prevent stack overflows (but this shouldn't be possible) | 443 | // prevent stack overflows (but this shouldn't be possible) |
422 | panic!("infinite recursion in glob imports!"); | 444 | panic!("infinite recursion in glob imports!"); |
423 | } | 445 | } |
424 | let module_items = &mut self.def_map.modules[module_id].scope; | 446 | let scope = &mut self.def_map.modules[module_id].scope; |
425 | let mut changed = false; | 447 | let mut changed = false; |
426 | for (name, res) in resolutions { | 448 | for (name, res) in resolutions { |
427 | let existing = module_items.items.entry(name.clone()).or_default(); | 449 | changed |= scope.push_res(name.clone(), *res); |
428 | |||
429 | if existing.def.types.is_none() && res.def.types.is_some() { | ||
430 | existing.def.types = res.def.types; | ||
431 | existing.import = import.or(res.import); | ||
432 | changed = true; | ||
433 | } | ||
434 | if existing.def.values.is_none() && res.def.values.is_some() { | ||
435 | existing.def.values = res.def.values; | ||
436 | existing.import = import.or(res.import); | ||
437 | changed = true; | ||
438 | } | ||
439 | if existing.def.macros.is_none() && res.def.macros.is_some() { | ||
440 | existing.def.macros = res.def.macros; | ||
441 | existing.import = import.or(res.import); | ||
442 | changed = true; | ||
443 | } | ||
444 | |||
445 | if existing.def.is_none() | ||
446 | && res.def.is_none() | ||
447 | && existing.import.is_none() | ||
448 | && res.import.is_some() | ||
449 | { | ||
450 | existing.import = res.import; | ||
451 | } | ||
452 | } | 450 | } |
453 | 451 | ||
454 | if !changed { | 452 | if !changed { |
@@ -461,27 +459,48 @@ where | |||
461 | .flat_map(|v| v.iter()) | 459 | .flat_map(|v| v.iter()) |
462 | .cloned() | 460 | .cloned() |
463 | .collect::<Vec<_>>(); | 461 | .collect::<Vec<_>>(); |
464 | for (glob_importing_module, glob_import) in glob_imports { | 462 | for (glob_importing_module, _glob_import) in glob_imports { |
465 | // We pass the glob import so that the tracked import in those modules is that glob import | 463 | // We pass the glob import so that the tracked import in those modules is that glob import |
466 | self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1); | 464 | self.update_recursive(glob_importing_module, resolutions, depth + 1); |
467 | } | 465 | } |
468 | } | 466 | } |
469 | 467 | ||
470 | fn resolve_macros(&mut self) -> ReachedFixedPoint { | 468 | fn resolve_macros(&mut self) -> ReachedFixedPoint { |
471 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | 469 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); |
470 | let mut attribute_macros = | ||
471 | std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new()); | ||
472 | let mut resolved = Vec::new(); | 472 | let mut resolved = Vec::new(); |
473 | let mut res = ReachedFixedPoint::Yes; | 473 | let mut res = ReachedFixedPoint::Yes; |
474 | macros.retain(|(module_id, ast_id, path)| { | 474 | macros.retain(|directive| { |
475 | if let Some(call_id) = directive.legacy { | ||
476 | res = ReachedFixedPoint::No; | ||
477 | resolved.push((directive.module_id, call_id)); | ||
478 | return false; | ||
479 | } | ||
480 | |||
475 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 481 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
476 | self.db, | 482 | self.db, |
477 | ResolveMode::Other, | 483 | ResolveMode::Other, |
478 | *module_id, | 484 | directive.module_id, |
479 | path, | 485 | &directive.path, |
486 | BuiltinShadowMode::Module, | ||
480 | ); | 487 | ); |
481 | 488 | ||
482 | if let Some(def) = resolved_res.resolved_def.take_macros() { | 489 | if let Some(def) = resolved_res.resolved_def.take_macros() { |
483 | let call_id = def.as_call_id(self.db, *ast_id); | 490 | let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id)); |
484 | resolved.push((*module_id, call_id, def)); | 491 | resolved.push((directive.module_id, call_id)); |
492 | res = ReachedFixedPoint::No; | ||
493 | return false; | ||
494 | } | ||
495 | |||
496 | true | ||
497 | }); | ||
498 | attribute_macros.retain(|(module_id, ast_id, path)| { | ||
499 | let resolved_res = self.resolve_attribute_macro(path); | ||
500 | |||
501 | if let Some(def) = resolved_res { | ||
502 | let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id)); | ||
503 | resolved.push((*module_id, call_id)); | ||
485 | res = ReachedFixedPoint::No; | 504 | res = ReachedFixedPoint::No; |
486 | return false; | 505 | return false; |
487 | } | 506 | } |
@@ -490,44 +509,41 @@ where | |||
490 | }); | 509 | }); |
491 | 510 | ||
492 | self.unexpanded_macros = macros; | 511 | self.unexpanded_macros = macros; |
512 | self.unexpanded_attribute_macros = attribute_macros; | ||
493 | 513 | ||
494 | for (module_id, macro_call_id, macro_def_id) in resolved { | 514 | for (module_id, macro_call_id) in resolved { |
495 | self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); | 515 | self.collect_macro_expansion(module_id, macro_call_id); |
496 | } | 516 | } |
497 | 517 | ||
498 | res | 518 | res |
499 | } | 519 | } |
500 | 520 | ||
501 | fn collect_macro_expansion( | 521 | fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> { |
502 | &mut self, | 522 | // FIXME this is currently super hacky, just enough to support the |
503 | module_id: LocalModuleId, | 523 | // built-in derives |
504 | macro_call_id: MacroCallId, | 524 | if let Some(name) = path.as_ident() { |
505 | macro_def_id: MacroDefId, | 525 | // FIXME this should actually be handled with the normal name |
506 | ) { | 526 | // resolution; the std lib defines built-in stubs for the derives, |
507 | if self.poison_macros.contains(¯o_def_id) { | 527 | // but these are new-style `macro`s, which we don't support yet |
508 | return; | 528 | if let Some(def_id) = find_builtin_derive(name) { |
509 | } | 529 | return Some(def_id); |
510 | |||
511 | self.macro_stack_monitor.increase(macro_def_id); | ||
512 | |||
513 | if !self.macro_stack_monitor.is_poison(macro_def_id) { | ||
514 | let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); | ||
515 | let raw_items = self.db.raw_items(file_id); | ||
516 | let mod_dir = self.mod_dirs[&module_id].clone(); | ||
517 | ModCollector { | ||
518 | def_collector: &mut *self, | ||
519 | file_id, | ||
520 | module_id, | ||
521 | raw_items: &raw_items, | ||
522 | mod_dir, | ||
523 | } | 530 | } |
524 | .collect(raw_items.items()); | ||
525 | } else { | ||
526 | log::error!("Too deep macro expansion: {:?}", macro_call_id); | ||
527 | self.poison_macros.insert(macro_def_id); | ||
528 | } | 531 | } |
532 | None | ||
533 | } | ||
529 | 534 | ||
530 | self.macro_stack_monitor.decrease(macro_def_id); | 535 | fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) { |
536 | let file_id: HirFileId = macro_call_id.as_file(); | ||
537 | let raw_items = self.db.raw_items(file_id); | ||
538 | let mod_dir = self.mod_dirs[&module_id].clone(); | ||
539 | ModCollector { | ||
540 | def_collector: &mut *self, | ||
541 | file_id, | ||
542 | module_id, | ||
543 | raw_items: &raw_items, | ||
544 | mod_dir, | ||
545 | } | ||
546 | .collect(raw_items.items()); | ||
531 | } | 547 | } |
532 | 548 | ||
533 | fn finish(self) -> CrateDefMap { | 549 | fn finish(self) -> CrateDefMap { |
@@ -581,20 +597,31 @@ where | |||
581 | raw::RawItemKind::Module(m) => { | 597 | raw::RawItemKind::Module(m) => { |
582 | self.collect_module(&self.raw_items[m], &item.attrs) | 598 | self.collect_module(&self.raw_items[m], &item.attrs) |
583 | } | 599 | } |
584 | raw::RawItemKind::Import(import_id) => self | 600 | raw::RawItemKind::Import(import_id) => { |
585 | .def_collector | 601 | self.def_collector.unresolved_imports.push(ImportDirective { |
586 | .unresolved_imports | 602 | module_id: self.module_id, |
587 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), | 603 | import_id, |
588 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), | 604 | import: self.raw_items[import_id].clone(), |
605 | status: PartialResolvedImport::Unresolved, | ||
606 | }) | ||
607 | } | ||
608 | raw::RawItemKind::Def(def) => { | ||
609 | self.define_def(&self.raw_items[def], &item.attrs) | ||
610 | } | ||
589 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 611 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
590 | raw::RawItemKind::Impl(imp) => { | 612 | raw::RawItemKind::Impl(imp) => { |
591 | let module = ModuleId { | 613 | let module = ModuleId { |
592 | krate: self.def_collector.def_map.krate, | 614 | krate: self.def_collector.def_map.krate, |
593 | local_id: self.module_id, | 615 | local_id: self.module_id, |
594 | }; | 616 | }; |
595 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | 617 | let container = ContainerId::ModuleId(module); |
596 | let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); | 618 | let ast_id = self.raw_items[imp].ast_id; |
597 | self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) | 619 | let impl_id = |
620 | ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
621 | .intern(self.def_collector.db); | ||
622 | self.def_collector.def_map.modules[self.module_id] | ||
623 | .scope | ||
624 | .define_impl(impl_id) | ||
598 | } | 625 | } |
599 | } | 626 | } |
600 | } | 627 | } |
@@ -667,72 +694,91 @@ where | |||
667 | let modules = &mut self.def_collector.def_map.modules; | 694 | let modules = &mut self.def_collector.def_map.modules; |
668 | let res = modules.alloc(ModuleData::default()); | 695 | let res = modules.alloc(ModuleData::default()); |
669 | modules[res].parent = Some(self.module_id); | 696 | modules[res].parent = Some(self.module_id); |
670 | modules[res].declaration = Some(declaration); | 697 | modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration); |
671 | modules[res].definition = definition; | 698 | for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { |
672 | modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); | 699 | modules[res].scope.define_legacy_macro(name, mac) |
700 | } | ||
673 | modules[self.module_id].children.insert(name.clone(), res); | 701 | modules[self.module_id].children.insert(name.clone(), res); |
674 | let resolution = Resolution { | 702 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; |
675 | def: PerNs::types( | 703 | let def: ModuleDefId = module.into(); |
676 | ModuleId { krate: self.def_collector.def_map.krate, local_id: res }.into(), | 704 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
677 | ), | 705 | self.def_collector.update(self.module_id, &[(name, def.into())]); |
678 | import: None, | ||
679 | }; | ||
680 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); | ||
681 | res | 706 | res |
682 | } | 707 | } |
683 | 708 | ||
684 | fn define_def(&mut self, def: &raw::DefData) { | 709 | fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { |
685 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | 710 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; |
686 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | 711 | // FIXME: check attrs to see if this is an attribute macro invocation; |
712 | // in which case we don't add the invocation, just a single attribute | ||
713 | // macro invocation | ||
687 | 714 | ||
688 | let name = def.name.clone(); | 715 | self.collect_derives(attrs, def); |
689 | let def: PerNs = match def.kind { | ||
690 | raw::DefKind::Function(ast_id) => { | ||
691 | let def = FunctionLoc { | ||
692 | container: ContainerId::ModuleId(module), | ||
693 | ast_id: AstId::new(self.file_id, ast_id), | ||
694 | } | ||
695 | .intern(self.def_collector.db); | ||
696 | 716 | ||
697 | PerNs::values(def.into()) | 717 | let name = def.name.clone(); |
718 | let container = ContainerId::ModuleId(module); | ||
719 | let def: ModuleDefId = match def.kind { | ||
720 | raw::DefKind::Function(ast_id) => FunctionLoc { | ||
721 | container: container.into(), | ||
722 | ast_id: AstId::new(self.file_id, ast_id), | ||
698 | } | 723 | } |
724 | .intern(self.def_collector.db) | ||
725 | .into(), | ||
699 | raw::DefKind::Struct(ast_id) => { | 726 | raw::DefKind::Struct(ast_id) => { |
700 | let id = StructId::from_ast_id(ctx, ast_id).into(); | 727 | StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
701 | PerNs::both(id, id) | 728 | .intern(self.def_collector.db) |
729 | .into() | ||
702 | } | 730 | } |
703 | raw::DefKind::Union(ast_id) => { | 731 | raw::DefKind::Union(ast_id) => { |
704 | let id = UnionId::from_ast_id(ctx, ast_id).into(); | 732 | UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
705 | PerNs::both(id, id) | 733 | .intern(self.def_collector.db) |
734 | .into() | ||
735 | } | ||
736 | raw::DefKind::Enum(ast_id) => { | ||
737 | EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
738 | .intern(self.def_collector.db) | ||
739 | .into() | ||
706 | } | 740 | } |
707 | raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()), | ||
708 | raw::DefKind::Const(ast_id) => { | 741 | raw::DefKind::Const(ast_id) => { |
709 | let def = ConstLoc { | 742 | ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) } |
710 | container: ContainerId::ModuleId(module), | 743 | .intern(self.def_collector.db) |
711 | ast_id: AstId::new(self.file_id, ast_id), | 744 | .into() |
712 | } | ||
713 | .intern(self.def_collector.db); | ||
714 | |||
715 | PerNs::values(def.into()) | ||
716 | } | 745 | } |
717 | raw::DefKind::Static(ast_id) => { | 746 | raw::DefKind::Static(ast_id) => { |
718 | let def = StaticLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } | 747 | StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
719 | .intern(self.def_collector.db); | 748 | .intern(self.def_collector.db) |
720 | 749 | .into() | |
721 | PerNs::values(def.into()) | ||
722 | } | 750 | } |
723 | raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()), | 751 | raw::DefKind::Trait(ast_id) => { |
724 | raw::DefKind::TypeAlias(ast_id) => { | 752 | TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
725 | let def = TypeAliasLoc { | 753 | .intern(self.def_collector.db) |
726 | container: ContainerId::ModuleId(module), | 754 | .into() |
727 | ast_id: AstId::new(self.file_id, ast_id), | ||
728 | } | ||
729 | .intern(self.def_collector.db); | ||
730 | |||
731 | PerNs::types(def.into()) | ||
732 | } | 755 | } |
756 | raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc { | ||
757 | container: container.into(), | ||
758 | ast_id: AstId::new(self.file_id, ast_id), | ||
759 | } | ||
760 | .intern(self.def_collector.db) | ||
761 | .into(), | ||
733 | }; | 762 | }; |
734 | let resolution = Resolution { def, import: None }; | 763 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
735 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) | 764 | self.def_collector.update(self.module_id, &[(name, def.into())]) |
765 | } | ||
766 | |||
767 | fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { | ||
768 | for derive_subtree in attrs.by_key("derive").tt_values() { | ||
769 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | ||
770 | for tt in &derive_subtree.token_trees { | ||
771 | let ident = match &tt { | ||
772 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, | ||
773 | tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok | ||
774 | _ => continue, // anything else would be an error (which we currently ignore) | ||
775 | }; | ||
776 | let path = ModPath::from_tt_ident(ident); | ||
777 | |||
778 | let ast_id = AstId::new(self.file_id, def.kind.ast_id()); | ||
779 | self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path)); | ||
780 | } | ||
781 | } | ||
736 | } | 782 | } |
737 | 783 | ||
738 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 784 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
@@ -758,8 +804,8 @@ where | |||
758 | if is_macro_rules(&mac.path) { | 804 | if is_macro_rules(&mac.path) { |
759 | if let Some(name) = &mac.name { | 805 | if let Some(name) = &mac.name { |
760 | let macro_id = MacroDefId { | 806 | let macro_id = MacroDefId { |
761 | ast_id, | 807 | ast_id: Some(ast_id), |
762 | krate: self.def_collector.def_map.krate, | 808 | krate: Some(self.def_collector.def_map.krate), |
763 | kind: MacroDefKind::Declarative, | 809 | kind: MacroDefKind::Declarative, |
764 | }; | 810 | }; |
765 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); | 811 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); |
@@ -767,14 +813,20 @@ where | |||
767 | return; | 813 | return; |
768 | } | 814 | } |
769 | 815 | ||
770 | // Case 2: try to resolve in legacy scope and expand macro_rules, triggering | 816 | // Case 2: try to resolve in legacy scope and expand macro_rules |
771 | // recursive item collection. | ||
772 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { | 817 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { |
773 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 818 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) |
774 | }) { | 819 | }) { |
775 | let macro_call_id = macro_def.as_call_id(self.def_collector.db, ast_id); | 820 | let macro_call_id = |
821 | macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id)); | ||
822 | |||
823 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
824 | module_id: self.module_id, | ||
825 | path: mac.path.clone(), | ||
826 | ast_id, | ||
827 | legacy: Some(macro_call_id), | ||
828 | }); | ||
776 | 829 | ||
777 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def); | ||
778 | return; | 830 | return; |
779 | } | 831 | } |
780 | 832 | ||
@@ -782,13 +834,19 @@ where | |||
782 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. | 834 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. |
783 | let mut path = mac.path.clone(); | 835 | let mut path = mac.path.clone(); |
784 | if path.is_ident() { | 836 | if path.is_ident() { |
785 | path.kind = PathKind::Self_; | 837 | path.kind = PathKind::Super(0); |
786 | } | 838 | } |
787 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); | 839 | |
840 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
841 | module_id: self.module_id, | ||
842 | path, | ||
843 | ast_id, | ||
844 | legacy: None, | ||
845 | }); | ||
788 | } | 846 | } |
789 | 847 | ||
790 | fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { | 848 | fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { |
791 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); | 849 | let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); |
792 | for (name, macro_) in macros { | 850 | for (name, macro_) in macros { |
793 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); | 851 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
794 | } | 852 | } |
@@ -803,45 +861,35 @@ where | |||
803 | } | 861 | } |
804 | } | 862 | } |
805 | 863 | ||
806 | fn is_macro_rules(path: &Path) -> bool { | 864 | fn is_macro_rules(path: &ModPath) -> bool { |
807 | path.as_ident() == Some(&name::MACRO_RULES) | 865 | path.as_ident() == Some(&name![macro_rules]) |
808 | } | 866 | } |
809 | 867 | ||
810 | #[cfg(test)] | 868 | #[cfg(test)] |
811 | mod tests { | 869 | mod tests { |
870 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
812 | use ra_arena::Arena; | 871 | use ra_arena::Arena; |
813 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 872 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
814 | use rustc_hash::FxHashSet; | ||
815 | |||
816 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
817 | 873 | ||
818 | use super::*; | 874 | use super::*; |
819 | 875 | ||
820 | fn do_collect_defs( | 876 | fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap { |
821 | db: &impl DefDatabase, | ||
822 | def_map: CrateDefMap, | ||
823 | monitor: MacroStackMonitor, | ||
824 | ) -> (CrateDefMap, FxHashSet<MacroDefId>) { | ||
825 | let mut collector = DefCollector { | 877 | let mut collector = DefCollector { |
826 | db, | 878 | db, |
827 | def_map, | 879 | def_map, |
828 | glob_imports: FxHashMap::default(), | 880 | glob_imports: FxHashMap::default(), |
829 | unresolved_imports: Vec::new(), | 881 | unresolved_imports: Vec::new(), |
882 | resolved_imports: Vec::new(), | ||
830 | unexpanded_macros: Vec::new(), | 883 | unexpanded_macros: Vec::new(), |
884 | unexpanded_attribute_macros: Vec::new(), | ||
831 | mod_dirs: FxHashMap::default(), | 885 | mod_dirs: FxHashMap::default(), |
832 | macro_stack_monitor: monitor, | ||
833 | poison_macros: FxHashSet::default(), | ||
834 | cfg_options: &CfgOptions::default(), | 886 | cfg_options: &CfgOptions::default(), |
835 | }; | 887 | }; |
836 | collector.collect(); | 888 | collector.collect(); |
837 | (collector.def_map, collector.poison_macros) | 889 | collector.def_map |
838 | } | 890 | } |
839 | 891 | ||
840 | fn do_limited_resolve( | 892 | fn do_resolve(code: &str) -> CrateDefMap { |
841 | code: &str, | ||
842 | limit: u32, | ||
843 | poison_limit: u32, | ||
844 | ) -> (CrateDefMap, FxHashSet<MacroDefId>) { | ||
845 | let (db, _file_id) = TestDB::with_single_file(&code); | 893 | let (db, _file_id) = TestDB::with_single_file(&code); |
846 | let krate = db.test_crate(); | 894 | let krate = db.test_crate(); |
847 | 895 | ||
@@ -859,59 +907,18 @@ mod tests { | |||
859 | diagnostics: Vec::new(), | 907 | diagnostics: Vec::new(), |
860 | } | 908 | } |
861 | }; | 909 | }; |
862 | 910 | do_collect_defs(&db, def_map) | |
863 | let mut monitor = MacroStackMonitor::default(); | ||
864 | monitor.validator = Some(Box::new(move |count| { | ||
865 | assert!(count < limit); | ||
866 | count >= poison_limit | ||
867 | })); | ||
868 | |||
869 | do_collect_defs(&db, def_map, monitor) | ||
870 | } | 911 | } |
871 | 912 | ||
872 | #[test] | 913 | #[test] |
873 | fn test_macro_expand_limit_width() { | 914 | fn test_macro_expand_will_stop() { |
874 | do_limited_resolve( | 915 | do_resolve( |
875 | r#" | 916 | r#" |
876 | macro_rules! foo { | 917 | macro_rules! foo { |
877 | ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } | 918 | ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } |
878 | } | 919 | } |
879 | foo!(KABOOM); | 920 | foo!(KABOOM); |
880 | "#, | 921 | "#, |
881 | 16, | ||
882 | 1000, | ||
883 | ); | 922 | ); |
884 | } | 923 | } |
885 | |||
886 | #[test] | ||
887 | fn test_macro_expand_poisoned() { | ||
888 | let (_, poison_macros) = do_limited_resolve( | ||
889 | r#" | ||
890 | macro_rules! foo { | ||
891 | ($ty:ty) => { foo!($ty); } | ||
892 | } | ||
893 | foo!(KABOOM); | ||
894 | "#, | ||
895 | 100, | ||
896 | 16, | ||
897 | ); | ||
898 | |||
899 | assert_eq!(poison_macros.len(), 1); | ||
900 | } | ||
901 | |||
902 | #[test] | ||
903 | fn test_macro_expand_normal() { | ||
904 | let (_, poison_macros) = do_limited_resolve( | ||
905 | r#" | ||
906 | macro_rules! foo { | ||
907 | ($ident:ident) => { struct $ident {} } | ||
908 | } | ||
909 | foo!(Bar); | ||
910 | "#, | ||
911 | 16, | ||
912 | 16, | ||
913 | ); | ||
914 | |||
915 | assert_eq!(poison_macros.len(), 0); | ||
916 | } | ||
917 | } | 924 | } |
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs index b72c55bd1..695014c7b 100644 --- a/crates/ra_hir_def/src/nameres/path_resolution.rs +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs | |||
@@ -10,16 +10,18 @@ | |||
10 | //! | 10 | //! |
11 | //! `ReachedFixedPoint` signals about this. | 11 | //! `ReachedFixedPoint` signals about this. |
12 | 12 | ||
13 | use std::iter::successors; | ||
14 | |||
13 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
14 | use ra_db::Edition; | 16 | use ra_db::Edition; |
15 | use test_utils::tested_by; | 17 | use test_utils::tested_by; |
16 | 18 | ||
17 | use crate::{ | 19 | use crate::{ |
18 | db::DefDatabase, | 20 | db::DefDatabase, |
19 | nameres::CrateDefMap, | 21 | nameres::{BuiltinShadowMode, CrateDefMap}, |
20 | path::{Path, PathKind}, | 22 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 23 | per_ns::PerNs, |
22 | AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, | 24 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, |
23 | }; | 25 | }; |
24 | 26 | ||
25 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 27 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
@@ -39,19 +41,21 @@ pub(super) struct ResolvePathResult { | |||
39 | pub(super) resolved_def: PerNs, | 41 | pub(super) resolved_def: PerNs, |
40 | pub(super) segment_index: Option<usize>, | 42 | pub(super) segment_index: Option<usize>, |
41 | pub(super) reached_fixedpoint: ReachedFixedPoint, | 43 | pub(super) reached_fixedpoint: ReachedFixedPoint, |
44 | pub(super) krate: Option<CrateId>, | ||
42 | } | 45 | } |
43 | 46 | ||
44 | impl ResolvePathResult { | 47 | impl ResolvePathResult { |
45 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | 48 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { |
46 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | 49 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None) |
47 | } | 50 | } |
48 | 51 | ||
49 | fn with( | 52 | fn with( |
50 | resolved_def: PerNs, | 53 | resolved_def: PerNs, |
51 | reached_fixedpoint: ReachedFixedPoint, | 54 | reached_fixedpoint: ReachedFixedPoint, |
52 | segment_index: Option<usize>, | 55 | segment_index: Option<usize>, |
56 | krate: Option<CrateId>, | ||
53 | ) -> ResolvePathResult { | 57 | ) -> ResolvePathResult { |
54 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | 58 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate } |
55 | } | 59 | } |
56 | } | 60 | } |
57 | 61 | ||
@@ -67,8 +71,18 @@ impl CrateDefMap { | |||
67 | db: &impl DefDatabase, | 71 | db: &impl DefDatabase, |
68 | mode: ResolveMode, | 72 | mode: ResolveMode, |
69 | original_module: LocalModuleId, | 73 | original_module: LocalModuleId, |
70 | path: &Path, | 74 | path: &ModPath, |
75 | shadow: BuiltinShadowMode, | ||
71 | ) -> ResolvePathResult { | 76 | ) -> ResolvePathResult { |
77 | // if it is not the last segment, we prefer the module to the builtin | ||
78 | let prefer_module = |index| { | ||
79 | if index == path.segments.len() - 1 { | ||
80 | shadow | ||
81 | } else { | ||
82 | BuiltinShadowMode::Module | ||
83 | } | ||
84 | }; | ||
85 | |||
72 | let mut segments = path.segments.iter().enumerate(); | 86 | let mut segments = path.segments.iter().enumerate(); |
73 | let mut curr_per_ns: PerNs = match path.kind { | 87 | let mut curr_per_ns: PerNs = match path.kind { |
74 | PathKind::DollarCrate(krate) => { | 88 | PathKind::DollarCrate(krate) => { |
@@ -85,9 +99,6 @@ impl CrateDefMap { | |||
85 | PathKind::Crate => { | 99 | PathKind::Crate => { |
86 | PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) | 100 | PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) |
87 | } | 101 | } |
88 | PathKind::Self_ => { | ||
89 | PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into()) | ||
90 | } | ||
91 | // plain import or absolute path in 2015: crate-relative with | 102 | // plain import or absolute path in 2015: crate-relative with |
92 | // fallback to extern prelude (with the simplification in | 103 | // fallback to extern prelude (with the simplification in |
93 | // rust-lang/rust#57745) | 104 | // rust-lang/rust#57745) |
@@ -96,24 +107,26 @@ impl CrateDefMap { | |||
96 | if self.edition == Edition::Edition2015 | 107 | if self.edition == Edition::Edition2015 |
97 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | 108 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => |
98 | { | 109 | { |
99 | let segment = match segments.next() { | 110 | let (idx, segment) = match segments.next() { |
100 | Some((_, segment)) => segment, | 111 | Some((idx, segment)) => (idx, segment), |
101 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 112 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
102 | }; | 113 | }; |
103 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | 114 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); |
104 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | 115 | self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx)) |
105 | } | 116 | } |
106 | PathKind::Plain => { | 117 | PathKind::Plain => { |
107 | let segment = match segments.next() { | 118 | let (idx, segment) = match segments.next() { |
108 | Some((_, segment)) => segment, | 119 | Some((idx, segment)) => (idx, segment), |
109 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 120 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
110 | }; | 121 | }; |
111 | log::debug!("resolving {:?} in module", segment); | 122 | log::debug!("resolving {:?} in module", segment); |
112 | self.resolve_name_in_module(db, original_module, &segment.name) | 123 | self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx)) |
113 | } | 124 | } |
114 | PathKind::Super => { | 125 | PathKind::Super(lvl) => { |
115 | if let Some(p) = self.modules[original_module].parent { | 126 | let m = successors(Some(original_module), |m| self.modules[*m].parent) |
116 | PerNs::types(ModuleId { krate: self.krate, local_id: p }.into()) | 127 | .nth(lvl as usize); |
128 | if let Some(local_id) = m { | ||
129 | PerNs::types(ModuleId { krate: self.krate, local_id }.into()) | ||
117 | } else { | 130 | } else { |
118 | log::debug!("super path in root module"); | 131 | log::debug!("super path in root module"); |
119 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 132 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
@@ -125,18 +138,13 @@ impl CrateDefMap { | |||
125 | Some((_, segment)) => segment, | 138 | Some((_, segment)) => segment, |
126 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 139 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
127 | }; | 140 | }; |
128 | if let Some(def) = self.extern_prelude.get(&segment.name) { | 141 | if let Some(def) = self.extern_prelude.get(&segment) { |
129 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | 142 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); |
130 | PerNs::types(*def) | 143 | PerNs::types(*def) |
131 | } else { | 144 | } else { |
132 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 145 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
133 | } | 146 | } |
134 | } | 147 | } |
135 | PathKind::Type(_) => { | ||
136 | // This is handled in `infer::infer_path_expr` | ||
137 | // The result returned here does not matter | ||
138 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
139 | } | ||
140 | }; | 148 | }; |
141 | 149 | ||
142 | for (i, segment) in segments { | 150 | for (i, segment) in segments { |
@@ -156,32 +164,29 @@ impl CrateDefMap { | |||
156 | curr_per_ns = match curr { | 164 | curr_per_ns = match curr { |
157 | ModuleDefId::ModuleId(module) => { | 165 | ModuleDefId::ModuleId(module) => { |
158 | if module.krate != self.krate { | 166 | if module.krate != self.krate { |
159 | let path = | 167 | let path = ModPath { |
160 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | 168 | segments: path.segments[i..].to_vec(), |
169 | kind: PathKind::Super(0), | ||
170 | }; | ||
161 | log::debug!("resolving {:?} in other crate", path); | 171 | log::debug!("resolving {:?} in other crate", path); |
162 | let defp_map = db.crate_def_map(module.krate); | 172 | let defp_map = db.crate_def_map(module.krate); |
163 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path); | 173 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); |
164 | return ResolvePathResult::with( | 174 | return ResolvePathResult::with( |
165 | def, | 175 | def, |
166 | ReachedFixedPoint::Yes, | 176 | ReachedFixedPoint::Yes, |
167 | s.map(|s| s + i), | 177 | s.map(|s| s + i), |
178 | Some(module.krate), | ||
168 | ); | 179 | ); |
169 | } | 180 | } |
170 | 181 | ||
171 | // Since it is a qualified path here, it should not contains legacy macros | 182 | // Since it is a qualified path here, it should not contains legacy macros |
172 | match self[module.local_id].scope.get(&segment.name) { | 183 | self[module.local_id].scope.get(&segment, prefer_module(i)) |
173 | Some(res) => res.def, | ||
174 | _ => { | ||
175 | log::debug!("path segment {:?} not found", segment.name); | ||
176 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
177 | } | ||
178 | } | ||
179 | } | 184 | } |
180 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 185 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
181 | // enum variant | 186 | // enum variant |
182 | tested_by!(can_import_enum_variant); | 187 | tested_by!(can_import_enum_variant); |
183 | let enum_data = db.enum_data(e); | 188 | let enum_data = db.enum_data(e); |
184 | match enum_data.variant(&segment.name) { | 189 | match enum_data.variant(&segment) { |
185 | Some(local_id) => { | 190 | Some(local_id) => { |
186 | let variant = EnumVariantId { parent: e, local_id }; | 191 | let variant = EnumVariantId { parent: e, local_id }; |
187 | PerNs::both(variant.into(), variant.into()) | 192 | PerNs::both(variant.into(), variant.into()) |
@@ -191,6 +196,7 @@ impl CrateDefMap { | |||
191 | PerNs::types(e.into()), | 196 | PerNs::types(e.into()), |
192 | ReachedFixedPoint::Yes, | 197 | ReachedFixedPoint::Yes, |
193 | Some(i), | 198 | Some(i), |
199 | Some(self.krate), | ||
194 | ); | 200 | ); |
195 | } | 201 | } |
196 | } | 202 | } |
@@ -200,7 +206,7 @@ impl CrateDefMap { | |||
200 | // (`Struct::method`), or some other kind of associated item | 206 | // (`Struct::method`), or some other kind of associated item |
201 | log::debug!( | 207 | log::debug!( |
202 | "path segment {:?} resolved to non-module {:?}, but is not last", | 208 | "path segment {:?} resolved to non-module {:?}, but is not last", |
203 | segment.name, | 209 | segment, |
204 | curr, | 210 | curr, |
205 | ); | 211 | ); |
206 | 212 | ||
@@ -208,11 +214,13 @@ impl CrateDefMap { | |||
208 | PerNs::types(s), | 214 | PerNs::types(s), |
209 | ReachedFixedPoint::Yes, | 215 | ReachedFixedPoint::Yes, |
210 | Some(i), | 216 | Some(i), |
217 | Some(self.krate), | ||
211 | ); | 218 | ); |
212 | } | 219 | } |
213 | }; | 220 | }; |
214 | } | 221 | } |
215 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | 222 | |
223 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) | ||
216 | } | 224 | } |
217 | 225 | ||
218 | fn resolve_name_in_module( | 226 | fn resolve_name_in_module( |
@@ -220,6 +228,7 @@ impl CrateDefMap { | |||
220 | db: &impl DefDatabase, | 228 | db: &impl DefDatabase, |
221 | module: LocalModuleId, | 229 | module: LocalModuleId, |
222 | name: &Name, | 230 | name: &Name, |
231 | shadow: BuiltinShadowMode, | ||
223 | ) -> PerNs { | 232 | ) -> PerNs { |
224 | // Resolve in: | 233 | // Resolve in: |
225 | // - legacy scope of macro | 234 | // - legacy scope of macro |
@@ -228,23 +237,31 @@ impl CrateDefMap { | |||
228 | // - std prelude | 237 | // - std prelude |
229 | let from_legacy_macro = | 238 | let from_legacy_macro = |
230 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); | 239 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); |
231 | let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); | 240 | let from_scope = self[module].scope.get(name, shadow); |
232 | let from_extern_prelude = | 241 | let from_extern_prelude = |
233 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 242 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
234 | let from_prelude = self.resolve_in_prelude(db, name); | 243 | let from_prelude = self.resolve_in_prelude(db, name, shadow); |
235 | 244 | ||
236 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) | 245 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) |
237 | } | 246 | } |
238 | 247 | ||
239 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { | 248 | fn resolve_name_in_crate_root_or_extern_prelude( |
240 | let from_crate_root = | 249 | &self, |
241 | self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); | 250 | name: &Name, |
251 | shadow: BuiltinShadowMode, | ||
252 | ) -> PerNs { | ||
253 | let from_crate_root = self[self.root].scope.get(name, shadow); | ||
242 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 254 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
243 | 255 | ||
244 | from_crate_root.or(from_extern_prelude) | 256 | from_crate_root.or(from_extern_prelude) |
245 | } | 257 | } |
246 | 258 | ||
247 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { | 259 | fn resolve_in_prelude( |
260 | &self, | ||
261 | db: &impl DefDatabase, | ||
262 | name: &Name, | ||
263 | shadow: BuiltinShadowMode, | ||
264 | ) -> PerNs { | ||
248 | if let Some(prelude) = self.prelude { | 265 | if let Some(prelude) = self.prelude { |
249 | let keep; | 266 | let keep; |
250 | let def_map = if prelude.krate == self.krate { | 267 | let def_map = if prelude.krate == self.krate { |
@@ -254,7 +271,7 @@ impl CrateDefMap { | |||
254 | keep = db.crate_def_map(prelude.krate); | 271 | keep = db.crate_def_map(prelude.krate); |
255 | &keep | 272 | &keep |
256 | }; | 273 | }; |
257 | def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) | 274 | def_map[prelude.local_id].scope.get(name, shadow) |
258 | } else { | 275 | } else { |
259 | PerNs::none() | 276 | PerNs::none() |
260 | } | 277 | } |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 6eb106094..73dc08745 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -10,21 +10,18 @@ use std::{ops::Index, sync::Arc}; | |||
10 | use hir_expand::{ | 10 | use hir_expand::{ |
11 | ast_id_map::AstIdMap, | 11 | ast_id_map::AstIdMap, |
12 | db::AstDatabase, | 12 | db::AstDatabase, |
13 | either::Either, | ||
14 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
15 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
16 | }; | 15 | }; |
17 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 16 | use ra_arena::{impl_arena_id, Arena, RawId}; |
17 | use ra_prof::profile; | ||
18 | use ra_syntax::{ | 18 | use ra_syntax::{ |
19 | ast::{self, AttrsOwner, NameOwner}, | 19 | ast::{self, AttrsOwner, NameOwner}, |
20 | AstNode, AstPtr, | 20 | AstNode, |
21 | }; | 21 | }; |
22 | use test_utils::tested_by; | 22 | use test_utils::tested_by; |
23 | 23 | ||
24 | use crate::{ | 24 | use crate::{attr::Attrs, db::DefDatabase, path::ModPath, FileAstId, HirFileId, InFile}; |
25 | attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, LocalImportId, | ||
26 | Source, | ||
27 | }; | ||
28 | 25 | ||
29 | /// `RawItems` is a set of top-level items in a file (except for impls). | 26 | /// `RawItems` is a set of top-level items in a file (except for impls). |
30 | /// | 27 | /// |
@@ -33,7 +30,7 @@ use crate::{ | |||
33 | #[derive(Debug, Default, PartialEq, Eq)] | 30 | #[derive(Debug, Default, PartialEq, Eq)] |
34 | pub struct RawItems { | 31 | pub struct RawItems { |
35 | modules: Arena<Module, ModuleData>, | 32 | modules: Arena<Module, ModuleData>, |
36 | imports: Arena<LocalImportId, ImportData>, | 33 | imports: Arena<Import, ImportData>, |
37 | defs: Arena<Def, DefData>, | 34 | defs: Arena<Def, DefData>, |
38 | macros: Arena<Macro, MacroData>, | 35 | macros: Arena<Macro, MacroData>, |
39 | impls: Arena<Impl, ImplData>, | 36 | impls: Arena<Impl, ImplData>, |
@@ -41,35 +38,15 @@ pub struct RawItems { | |||
41 | items: Vec<RawItem>, | 38 | items: Vec<RawItem>, |
42 | } | 39 | } |
43 | 40 | ||
44 | #[derive(Debug, Default, PartialEq, Eq)] | ||
45 | pub struct ImportSourceMap { | ||
46 | map: ArenaMap<LocalImportId, ImportSourcePtr>, | ||
47 | } | ||
48 | |||
49 | type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; | ||
50 | |||
51 | impl ImportSourceMap { | ||
52 | pub fn get(&self, import: LocalImportId) -> ImportSourcePtr { | ||
53 | self.map[import].clone() | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl RawItems { | 41 | impl RawItems { |
58 | pub(crate) fn raw_items_query( | 42 | pub(crate) fn raw_items_query( |
59 | db: &(impl DefDatabase + AstDatabase), | 43 | db: &(impl DefDatabase + AstDatabase), |
60 | file_id: HirFileId, | 44 | file_id: HirFileId, |
61 | ) -> Arc<RawItems> { | 45 | ) -> Arc<RawItems> { |
62 | db.raw_items_with_source_map(file_id).0 | 46 | let _p = profile("raw_items_query"); |
63 | } | ||
64 | |||
65 | pub(crate) fn raw_items_with_source_map_query( | ||
66 | db: &(impl DefDatabase + AstDatabase), | ||
67 | file_id: HirFileId, | ||
68 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { | ||
69 | let mut collector = RawItemsCollector { | 47 | let mut collector = RawItemsCollector { |
70 | raw_items: RawItems::default(), | 48 | raw_items: RawItems::default(), |
71 | source_ast_id_map: db.ast_id_map(file_id), | 49 | source_ast_id_map: db.ast_id_map(file_id), |
72 | imports: Trace::new(), | ||
73 | file_id, | 50 | file_id, |
74 | hygiene: Hygiene::new(db, file_id), | 51 | hygiene: Hygiene::new(db, file_id), |
75 | }; | 52 | }; |
@@ -80,11 +57,8 @@ impl RawItems { | |||
80 | collector.process_module(None, item_list); | 57 | collector.process_module(None, item_list); |
81 | } | 58 | } |
82 | } | 59 | } |
83 | let mut raw_items = collector.raw_items; | 60 | let raw_items = collector.raw_items; |
84 | let (arena, map) = collector.imports.into_arena_and_map(); | 61 | Arc::new(raw_items) |
85 | raw_items.imports = arena; | ||
86 | let source_map = ImportSourceMap { map }; | ||
87 | (Arc::new(raw_items), Arc::new(source_map)) | ||
88 | } | 62 | } |
89 | 63 | ||
90 | pub(super) fn items(&self) -> &[RawItem] { | 64 | pub(super) fn items(&self) -> &[RawItem] { |
@@ -99,9 +73,9 @@ impl Index<Module> for RawItems { | |||
99 | } | 73 | } |
100 | } | 74 | } |
101 | 75 | ||
102 | impl Index<LocalImportId> for RawItems { | 76 | impl Index<Import> for RawItems { |
103 | type Output = ImportData; | 77 | type Output = ImportData; |
104 | fn index(&self, idx: LocalImportId) -> &ImportData { | 78 | fn index(&self, idx: Import) -> &ImportData { |
105 | &self.imports[idx] | 79 | &self.imports[idx] |
106 | } | 80 | } |
107 | } | 81 | } |
@@ -136,7 +110,7 @@ pub(super) struct RawItem { | |||
136 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 110 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
137 | pub(super) enum RawItemKind { | 111 | pub(super) enum RawItemKind { |
138 | Module(Module), | 112 | Module(Module), |
139 | Import(LocalImportId), | 113 | Import(Import), |
140 | Def(Def), | 114 | Def(Def), |
141 | Macro(Macro), | 115 | Macro(Macro), |
142 | Impl(Impl), | 116 | Impl(Impl), |
@@ -152,9 +126,13 @@ pub(super) enum ModuleData { | |||
152 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | 126 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, |
153 | } | 127 | } |
154 | 128 | ||
129 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
130 | pub(crate) struct Import(RawId); | ||
131 | impl_arena_id!(Import); | ||
132 | |||
155 | #[derive(Debug, Clone, PartialEq, Eq)] | 133 | #[derive(Debug, Clone, PartialEq, Eq)] |
156 | pub struct ImportData { | 134 | pub struct ImportData { |
157 | pub(super) path: Path, | 135 | pub(super) path: ModPath, |
158 | pub(super) alias: Option<Name>, | 136 | pub(super) alias: Option<Name>, |
159 | pub(super) is_glob: bool, | 137 | pub(super) is_glob: bool, |
160 | pub(super) is_prelude: bool, | 138 | pub(super) is_prelude: bool, |
@@ -184,6 +162,21 @@ pub(super) enum DefKind { | |||
184 | TypeAlias(FileAstId<ast::TypeAliasDef>), | 162 | TypeAlias(FileAstId<ast::TypeAliasDef>), |
185 | } | 163 | } |
186 | 164 | ||
165 | impl DefKind { | ||
166 | pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> { | ||
167 | match self { | ||
168 | DefKind::Function(it) => it.upcast(), | ||
169 | DefKind::Struct(it) => it.upcast(), | ||
170 | DefKind::Union(it) => it.upcast(), | ||
171 | DefKind::Enum(it) => it.upcast(), | ||
172 | DefKind::Const(it) => it.upcast(), | ||
173 | DefKind::Static(it) => it.upcast(), | ||
174 | DefKind::Trait(it) => it.upcast(), | ||
175 | DefKind::TypeAlias(it) => it.upcast(), | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
187 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 180 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
188 | pub(super) struct Macro(RawId); | 181 | pub(super) struct Macro(RawId); |
189 | impl_arena_id!(Macro); | 182 | impl_arena_id!(Macro); |
@@ -191,7 +184,7 @@ impl_arena_id!(Macro); | |||
191 | #[derive(Debug, PartialEq, Eq)] | 184 | #[derive(Debug, PartialEq, Eq)] |
192 | pub(super) struct MacroData { | 185 | pub(super) struct MacroData { |
193 | pub(super) ast_id: FileAstId<ast::MacroCall>, | 186 | pub(super) ast_id: FileAstId<ast::MacroCall>, |
194 | pub(super) path: Path, | 187 | pub(super) path: ModPath, |
195 | pub(super) name: Option<Name>, | 188 | pub(super) name: Option<Name>, |
196 | pub(super) export: bool, | 189 | pub(super) export: bool, |
197 | pub(super) builtin: bool, | 190 | pub(super) builtin: bool, |
@@ -208,7 +201,6 @@ pub(super) struct ImplData { | |||
208 | 201 | ||
209 | struct RawItemsCollector { | 202 | struct RawItemsCollector { |
210 | raw_items: RawItems, | 203 | raw_items: RawItems, |
211 | imports: Trace<LocalImportId, ImportData, ImportSourcePtr>, | ||
212 | source_ast_id_map: Arc<AstIdMap>, | 204 | source_ast_id_map: Arc<AstIdMap>, |
213 | file_id: HirFileId, | 205 | file_id: HirFileId, |
214 | hygiene: Hygiene, | 206 | hygiene: Hygiene, |
@@ -312,10 +304,10 @@ impl RawItemsCollector { | |||
312 | let attrs = self.parse_attrs(&use_item); | 304 | let attrs = self.parse_attrs(&use_item); |
313 | 305 | ||
314 | let mut buf = Vec::new(); | 306 | let mut buf = Vec::new(); |
315 | Path::expand_use_item( | 307 | ModPath::expand_use_item( |
316 | Source { value: use_item, file_id: self.file_id }, | 308 | InFile { value: use_item, file_id: self.file_id }, |
317 | &self.hygiene, | 309 | &self.hygiene, |
318 | |path, use_tree, is_glob, alias| { | 310 | |path, _use_tree, is_glob, alias| { |
319 | let import_data = ImportData { | 311 | let import_data = ImportData { |
320 | path, | 312 | path, |
321 | alias, | 313 | alias, |
@@ -324,11 +316,11 @@ impl RawItemsCollector { | |||
324 | is_extern_crate: false, | 316 | is_extern_crate: false, |
325 | is_macro_use: false, | 317 | is_macro_use: false, |
326 | }; | 318 | }; |
327 | buf.push((import_data, Either::A(AstPtr::new(use_tree)))); | 319 | buf.push(import_data); |
328 | }, | 320 | }, |
329 | ); | 321 | ); |
330 | for (import_data, ptr) in buf { | 322 | for import_data in buf { |
331 | self.push_import(current_module, attrs.clone(), import_data, ptr); | 323 | self.push_import(current_module, attrs.clone(), import_data); |
332 | } | 324 | } |
333 | } | 325 | } |
334 | 326 | ||
@@ -338,7 +330,7 @@ impl RawItemsCollector { | |||
338 | extern_crate: ast::ExternCrateItem, | 330 | extern_crate: ast::ExternCrateItem, |
339 | ) { | 331 | ) { |
340 | if let Some(name_ref) = extern_crate.name_ref() { | 332 | if let Some(name_ref) = extern_crate.name_ref() { |
341 | let path = Path::from_name_ref(&name_ref); | 333 | let path = ModPath::from_name_ref(&name_ref); |
342 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 334 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
343 | let attrs = self.parse_attrs(&extern_crate); | 335 | let attrs = self.parse_attrs(&extern_crate); |
344 | // FIXME: cfg_attr | 336 | // FIXME: cfg_attr |
@@ -351,18 +343,13 @@ impl RawItemsCollector { | |||
351 | is_extern_crate: true, | 343 | is_extern_crate: true, |
352 | is_macro_use, | 344 | is_macro_use, |
353 | }; | 345 | }; |
354 | self.push_import( | 346 | self.push_import(current_module, attrs, import_data); |
355 | current_module, | ||
356 | attrs, | ||
357 | import_data, | ||
358 | Either::B(AstPtr::new(&extern_crate)), | ||
359 | ); | ||
360 | } | 347 | } |
361 | } | 348 | } |
362 | 349 | ||
363 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { | 350 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { |
364 | let attrs = self.parse_attrs(&m); | 351 | let attrs = self.parse_attrs(&m); |
365 | let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { | 352 | let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) { |
366 | Some(it) => it, | 353 | Some(it) => it, |
367 | _ => return, | 354 | _ => return, |
368 | }; | 355 | }; |
@@ -387,14 +374,8 @@ impl RawItemsCollector { | |||
387 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | 374 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) |
388 | } | 375 | } |
389 | 376 | ||
390 | fn push_import( | 377 | fn push_import(&mut self, current_module: Option<Module>, attrs: Attrs, data: ImportData) { |
391 | &mut self, | 378 | let import = self.raw_items.imports.alloc(data); |
392 | current_module: Option<Module>, | ||
393 | attrs: Attrs, | ||
394 | data: ImportData, | ||
395 | source: ImportSourcePtr, | ||
396 | ) { | ||
397 | let import = self.imports.alloc(|| source, || data); | ||
398 | self.push_item(current_module, attrs, RawItemKind::Import(import)) | 379 | self.push_item(current_module, attrs, RawItemKind::Import(import)) |
399 | } | 380 | } |
400 | 381 | ||
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 87fcd617c..ff474b53b 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -32,27 +32,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { | |||
32 | *buf += path; | 32 | *buf += path; |
33 | *buf += "\n"; | 33 | *buf += "\n"; |
34 | 34 | ||
35 | let mut entries = map.modules[module] | 35 | let mut entries = map.modules[module].scope.collect_resolutions(); |
36 | .scope | 36 | entries.sort_by_key(|(name, _)| name.clone()); |
37 | .items | 37 | |
38 | .iter() | 38 | for (name, def) in entries { |
39 | .map(|(name, res)| (name, res.def)) | ||
40 | .collect::<Vec<_>>(); | ||
41 | entries.sort_by_key(|(name, _)| *name); | ||
42 | |||
43 | for (name, res) in entries { | ||
44 | *buf += &format!("{}:", name); | 39 | *buf += &format!("{}:", name); |
45 | 40 | ||
46 | if res.types.is_some() { | 41 | if def.types.is_some() { |
47 | *buf += " t"; | 42 | *buf += " t"; |
48 | } | 43 | } |
49 | if res.values.is_some() { | 44 | if def.values.is_some() { |
50 | *buf += " v"; | 45 | *buf += " v"; |
51 | } | 46 | } |
52 | if res.macros.is_some() { | 47 | if def.macros.is_some() { |
53 | *buf += " m"; | 48 | *buf += " m"; |
54 | } | 49 | } |
55 | if res.is_none() { | 50 | if def.is_none() { |
56 | *buf += " _"; | 51 | *buf += " _"; |
57 | } | 52 | } |
58 | 53 | ||
@@ -558,3 +553,35 @@ fn cfg_test() { | |||
558 | ⋮Foo: t v | 553 | ⋮Foo: t v |
559 | "###); | 554 | "###); |
560 | } | 555 | } |
556 | |||
557 | #[test] | ||
558 | fn infer_multiple_namespace() { | ||
559 | let map = def_map( | ||
560 | r#" | ||
561 | //- /main.rs | ||
562 | mod a { | ||
563 | pub type T = (); | ||
564 | pub use crate::b::*; | ||
565 | } | ||
566 | |||
567 | use crate::a::T; | ||
568 | |||
569 | mod b { | ||
570 | pub const T: () = (); | ||
571 | } | ||
572 | "#, | ||
573 | ); | ||
574 | |||
575 | assert_snapshot!(map, @r###" | ||
576 | ⋮crate | ||
577 | ⋮T: t v | ||
578 | ⋮a: t | ||
579 | ⋮b: t | ||
580 | ⋮ | ||
581 | ⋮crate::b | ||
582 | ⋮T: v | ||
583 | ⋮ | ||
584 | ⋮crate::a | ||
585 | ⋮T: t v | ||
586 | "###); | ||
587 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index 5b03fe365..5e24cb94d 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs | |||
@@ -112,3 +112,24 @@ fn glob_enum() { | |||
112 | "### | 112 | "### |
113 | ); | 113 | ); |
114 | } | 114 | } |
115 | |||
116 | #[test] | ||
117 | fn glob_enum_group() { | ||
118 | covers!(glob_enum_group); | ||
119 | let map = def_map( | ||
120 | " | ||
121 | //- /lib.rs | ||
122 | enum Foo { | ||
123 | Bar, Baz | ||
124 | } | ||
125 | use self::Foo::{*}; | ||
126 | ", | ||
127 | ); | ||
128 | assert_snapshot!(map, @r###" | ||
129 | ⋮crate | ||
130 | ⋮Bar: t v | ||
131 | ⋮Baz: t v | ||
132 | ⋮Foo: t | ||
133 | "### | ||
134 | ); | ||
135 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 903a22771..ef2e9435c 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
116 | let events = db.log_executed(|| { | 116 | let events = db.log_executed(|| { |
117 | let crate_def_map = db.crate_def_map(krate); | 117 | let crate_def_map = db.crate_def_map(krate); |
118 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | 118 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); |
119 | assert_eq!(module_data.scope.items.len(), 1); | 119 | assert_eq!(module_data.scope.collect_resolutions().len(), 1); |
120 | }); | 120 | }); |
121 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 121 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
122 | } | 122 | } |
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
126 | let events = db.log_executed(|| { | 126 | let events = db.log_executed(|| { |
127 | let crate_def_map = db.crate_def_map(krate); | 127 | let crate_def_map = db.crate_def_map(krate); |
128 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | 128 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); |
129 | assert_eq!(module_data.scope.items.len(), 1); | 129 | assert_eq!(module_data.scope.collect_resolutions().len(), 1); |
130 | }); | 130 | }); |
131 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 131 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
132 | } | 132 | } |
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index 704065633..d104f5993 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs | |||
@@ -600,3 +600,27 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { | |||
600 | ⋮bar: t v | 600 | ⋮bar: t v |
601 | "###); | 601 | "###); |
602 | } | 602 | } |
603 | |||
604 | #[test] | ||
605 | fn expand_derive() { | ||
606 | let map = compute_crate_def_map( | ||
607 | " | ||
608 | //- /main.rs | ||
609 | #[derive(Clone)] | ||
610 | struct Foo; | ||
611 | ", | ||
612 | ); | ||
613 | assert_eq!(map.modules[map.root].scope.impls().len(), 1); | ||
614 | } | ||
615 | |||
616 | #[test] | ||
617 | fn expand_multiple_derive() { | ||
618 | let map = compute_crate_def_map( | ||
619 | " | ||
620 | //- /main.rs | ||
621 | #[derive(Copy, Clone)] | ||
622 | struct Foo; | ||
623 | ", | ||
624 | ); | ||
625 | assert_eq!(map.modules[map.root].scope.impls().len(), 2); | ||
626 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index e11530062..e800cc68e 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -668,7 +668,7 @@ fn unresolved_module_diagnostics() { | |||
668 | module: LocalModuleId( | 668 | module: LocalModuleId( |
669 | 0, | 669 | 0, |
670 | ), | 670 | ), |
671 | declaration: AstId { | 671 | declaration: InFile { |
672 | file_id: HirFileId( | 672 | file_id: HirFileId( |
673 | FileId( | 673 | FileId( |
674 | FileId( | 674 | FileId( |
@@ -676,7 +676,7 @@ fn unresolved_module_diagnostics() { | |||
676 | ), | 676 | ), |
677 | ), | 677 | ), |
678 | ), | 678 | ), |
679 | file_ast_id: FileAstId { | 679 | value: FileAstId { |
680 | raw: ErasedFileAstId( | 680 | raw: ErasedFileAstId( |
681 | 1, | 681 | 1, |
682 | ), | 682 | ), |