diff options
author | Aleksey Kladov <[email protected]> | 2020-08-13 15:28:27 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-08-13 15:29:33 +0100 |
commit | b28c54a2c239acd73f2eea80fda9ee3960d2c046 (patch) | |
tree | 1bf0ea193bdb3b16ff42c2c01118b13a4276b2bb /crates/hir_def/src/nameres | |
parent | b7aa4898e0841ab8199643f89a0caa967b698ca8 (diff) |
Rename ra_hir_def -> hir_def
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 1279 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/mod_resolution.rs | 139 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 330 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 690 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/globs.rs | 338 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/incremental.rs | 101 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 669 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/mod_resolution.rs | 796 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/primitives.rs | 23 |
9 files changed, 4365 insertions, 0 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs new file mode 100644 index 000000000..3e99c8773 --- /dev/null +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -0,0 +1,1279 @@ | |||
1 | //! The core of the module-level name resolution algorithm. | ||
2 | //! | ||
3 | //! `DefCollector::collect` contains the fixed-point iteration loop which | ||
4 | //! resolves imports and expands macros. | ||
5 | |||
6 | use base_db::{CrateId, FileId, ProcMacroId}; | ||
7 | use cfg::CfgOptions; | ||
8 | use hir_expand::{ | ||
9 | ast_id_map::FileAstId, | ||
10 | builtin_derive::find_builtin_derive, | ||
11 | builtin_macro::find_builtin_macro, | ||
12 | name::{name, AsName, Name}, | ||
13 | proc_macro::ProcMacroExpander, | ||
14 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | ||
15 | }; | ||
16 | use rustc_hash::FxHashMap; | ||
17 | use syntax::ast; | ||
18 | use test_utils::mark; | ||
19 | |||
20 | use crate::{ | ||
21 | attr::Attrs, | ||
22 | db::DefDatabase, | ||
23 | item_scope::{ImportType, PerNsGlobImports}, | ||
24 | item_tree::{ | ||
25 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, | ||
26 | }, | ||
27 | nameres::{ | ||
28 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | ||
29 | BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, | ||
30 | }, | ||
31 | path::{ImportAlias, ModPath, PathKind}, | ||
32 | per_ns::PerNs, | ||
33 | visibility::{RawVisibility, Visibility}, | ||
34 | AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, | ||
35 | FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, | ||
36 | TraitLoc, TypeAliasLoc, UnionLoc, | ||
37 | }; | ||
38 | |||
39 | const GLOB_RECURSION_LIMIT: usize = 100; | ||
40 | const EXPANSION_DEPTH_LIMIT: usize = 128; | ||
41 | const FIXED_POINT_LIMIT: usize = 8192; | ||
42 | |||
43 | pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | ||
44 | let crate_graph = db.crate_graph(); | ||
45 | |||
46 | // populate external prelude | ||
47 | for dep in &crate_graph[def_map.krate].dependencies { | ||
48 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); | ||
49 | let dep_def_map = db.crate_def_map(dep.crate_id); | ||
50 | def_map.extern_prelude.insert( | ||
51 | dep.as_name(), | ||
52 | ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(), | ||
53 | ); | ||
54 | |||
55 | // look for the prelude | ||
56 | // If the dependency defines a prelude, we overwrite an already defined | ||
57 | // prelude. This is necessary to import the "std" prelude if a crate | ||
58 | // depends on both "core" and "std". | ||
59 | if dep_def_map.prelude.is_some() { | ||
60 | def_map.prelude = dep_def_map.prelude; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | let cfg_options = &crate_graph[def_map.krate].cfg_options; | ||
65 | let proc_macros = &crate_graph[def_map.krate].proc_macro; | ||
66 | let proc_macros = proc_macros | ||
67 | .iter() | ||
68 | .enumerate() | ||
69 | .map(|(idx, it)| { | ||
70 | // FIXME: a hacky way to create a Name from string. | ||
71 | let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() }; | ||
72 | (name.as_name(), ProcMacroExpander::new(def_map.krate, ProcMacroId(idx as u32))) | ||
73 | }) | ||
74 | .collect(); | ||
75 | |||
76 | let mut collector = DefCollector { | ||
77 | db, | ||
78 | def_map, | ||
79 | glob_imports: FxHashMap::default(), | ||
80 | unresolved_imports: Vec::new(), | ||
81 | resolved_imports: Vec::new(), | ||
82 | |||
83 | unexpanded_macros: Vec::new(), | ||
84 | unexpanded_attribute_macros: Vec::new(), | ||
85 | mod_dirs: FxHashMap::default(), | ||
86 | cfg_options, | ||
87 | proc_macros, | ||
88 | from_glob_import: Default::default(), | ||
89 | }; | ||
90 | collector.collect(); | ||
91 | collector.finish() | ||
92 | } | ||
93 | |||
94 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
95 | enum PartialResolvedImport { | ||
96 | /// None of any namespaces is resolved | ||
97 | Unresolved, | ||
98 | /// One of namespaces is resolved | ||
99 | Indeterminate(PerNs), | ||
100 | /// All namespaces are resolved, OR it is came from other crate | ||
101 | Resolved(PerNs), | ||
102 | } | ||
103 | |||
104 | impl PartialResolvedImport { | ||
105 | fn namespaces(&self) -> PerNs { | ||
106 | match self { | ||
107 | PartialResolvedImport::Unresolved => PerNs::none(), | ||
108 | PartialResolvedImport::Indeterminate(ns) => *ns, | ||
109 | PartialResolvedImport::Resolved(ns) => *ns, | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
115 | struct Import { | ||
116 | pub path: ModPath, | ||
117 | pub alias: Option<ImportAlias>, | ||
118 | pub visibility: RawVisibility, | ||
119 | pub is_glob: bool, | ||
120 | pub is_prelude: bool, | ||
121 | pub is_extern_crate: bool, | ||
122 | pub is_macro_use: bool, | ||
123 | } | ||
124 | |||
125 | impl Import { | ||
126 | fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self { | ||
127 | let it = &tree[id]; | ||
128 | let visibility = &tree[it.visibility]; | ||
129 | Self { | ||
130 | path: it.path.clone(), | ||
131 | alias: it.alias.clone(), | ||
132 | visibility: visibility.clone(), | ||
133 | is_glob: it.is_glob, | ||
134 | is_prelude: it.is_prelude, | ||
135 | is_extern_crate: false, | ||
136 | is_macro_use: false, | ||
137 | } | ||
138 | } | ||
139 | |||
140 | fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self { | ||
141 | let it = &tree[id]; | ||
142 | let visibility = &tree[it.visibility]; | ||
143 | Self { | ||
144 | path: it.path.clone(), | ||
145 | alias: it.alias.clone(), | ||
146 | visibility: visibility.clone(), | ||
147 | is_glob: false, | ||
148 | is_prelude: false, | ||
149 | is_extern_crate: true, | ||
150 | is_macro_use: it.is_macro_use, | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
156 | struct ImportDirective { | ||
157 | module_id: LocalModuleId, | ||
158 | import: Import, | ||
159 | status: PartialResolvedImport, | ||
160 | } | ||
161 | |||
162 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
163 | struct MacroDirective { | ||
164 | module_id: LocalModuleId, | ||
165 | ast_id: AstIdWithPath<ast::MacroCall>, | ||
166 | legacy: Option<MacroCallId>, | ||
167 | depth: usize, | ||
168 | } | ||
169 | |||
170 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
171 | struct DeriveDirective { | ||
172 | module_id: LocalModuleId, | ||
173 | ast_id: AstIdWithPath<ast::Item>, | ||
174 | } | ||
175 | |||
176 | struct DefData<'a> { | ||
177 | id: ModuleDefId, | ||
178 | name: &'a Name, | ||
179 | visibility: &'a RawVisibility, | ||
180 | has_constructor: bool, | ||
181 | } | ||
182 | |||
183 | /// Walks the tree of module recursively | ||
184 | struct DefCollector<'a> { | ||
185 | db: &'a dyn DefDatabase, | ||
186 | def_map: CrateDefMap, | ||
187 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>, | ||
188 | unresolved_imports: Vec<ImportDirective>, | ||
189 | resolved_imports: Vec<ImportDirective>, | ||
190 | unexpanded_macros: Vec<MacroDirective>, | ||
191 | unexpanded_attribute_macros: Vec<DeriveDirective>, | ||
192 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | ||
193 | cfg_options: &'a CfgOptions, | ||
194 | proc_macros: Vec<(Name, ProcMacroExpander)>, | ||
195 | from_glob_import: PerNsGlobImports, | ||
196 | } | ||
197 | |||
198 | impl DefCollector<'_> { | ||
199 | fn collect(&mut self) { | ||
200 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; | ||
201 | let item_tree = self.db.item_tree(file_id.into()); | ||
202 | let module_id = self.def_map.root; | ||
203 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | ||
204 | ModCollector { | ||
205 | def_collector: &mut *self, | ||
206 | macro_depth: 0, | ||
207 | module_id, | ||
208 | file_id: file_id.into(), | ||
209 | item_tree: &item_tree, | ||
210 | mod_dir: ModDir::root(), | ||
211 | } | ||
212 | .collect(item_tree.top_level_items()); | ||
213 | |||
214 | // main name resolution fixed-point loop. | ||
215 | let mut i = 0; | ||
216 | loop { | ||
217 | self.db.check_canceled(); | ||
218 | self.resolve_imports(); | ||
219 | |||
220 | match self.resolve_macros() { | ||
221 | ReachedFixedPoint::Yes => break, | ||
222 | ReachedFixedPoint::No => i += 1, | ||
223 | } | ||
224 | if i == FIXED_POINT_LIMIT { | ||
225 | log::error!("name resolution is stuck"); | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | // Resolve all indeterminate resolved imports again | ||
231 | // As some of the macros will expand newly import shadowing partial resolved imports | ||
232 | // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports` | ||
233 | // correctly | ||
234 | let partial_resolved = self.resolved_imports.iter().filter_map(|directive| { | ||
235 | if let PartialResolvedImport::Indeterminate(_) = directive.status { | ||
236 | let mut directive = directive.clone(); | ||
237 | directive.status = PartialResolvedImport::Unresolved; | ||
238 | Some(directive) | ||
239 | } else { | ||
240 | None | ||
241 | } | ||
242 | }); | ||
243 | self.unresolved_imports.extend(partial_resolved); | ||
244 | self.resolve_imports(); | ||
245 | |||
246 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | ||
247 | // show unresolved imports in completion, etc | ||
248 | for directive in unresolved_imports { | ||
249 | self.record_resolved_import(&directive) | ||
250 | } | ||
251 | |||
252 | // Record proc-macros | ||
253 | self.collect_proc_macro(); | ||
254 | } | ||
255 | |||
256 | fn collect_proc_macro(&mut self) { | ||
257 | let proc_macros = std::mem::take(&mut self.proc_macros); | ||
258 | for (name, expander) in proc_macros { | ||
259 | let krate = self.def_map.krate; | ||
260 | |||
261 | let macro_id = MacroDefId { | ||
262 | ast_id: None, | ||
263 | krate: Some(krate), | ||
264 | kind: MacroDefKind::CustomDerive(expander), | ||
265 | local_inner: false, | ||
266 | }; | ||
267 | |||
268 | self.define_proc_macro(name.clone(), macro_id); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | /// Define a macro with `macro_rules`. | ||
273 | /// | ||
274 | /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, | ||
275 | /// then it is also defined in the root module scope. | ||
276 | /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition. | ||
277 | /// | ||
278 | /// It is surprising that the macro will never be in the current module scope. | ||
279 | /// These code fails with "unresolved import/macro", | ||
280 | /// ```rust,compile_fail | ||
281 | /// mod m { macro_rules! foo { () => {} } } | ||
282 | /// use m::foo as bar; | ||
283 | /// ``` | ||
284 | /// | ||
285 | /// ```rust,compile_fail | ||
286 | /// macro_rules! foo { () => {} } | ||
287 | /// self::foo!(); | ||
288 | /// crate::foo!(); | ||
289 | /// ``` | ||
290 | /// | ||
291 | /// Well, this code compiles, because the plain path `foo` in `use` is searched | ||
292 | /// in the legacy textual scope only. | ||
293 | /// ```rust | ||
294 | /// macro_rules! foo { () => {} } | ||
295 | /// use foo as bar; | ||
296 | /// ``` | ||
297 | fn define_macro( | ||
298 | &mut self, | ||
299 | module_id: LocalModuleId, | ||
300 | name: Name, | ||
301 | macro_: MacroDefId, | ||
302 | export: bool, | ||
303 | ) { | ||
304 | // Textual scoping | ||
305 | self.define_legacy_macro(module_id, name.clone(), macro_); | ||
306 | |||
307 | // Module scoping | ||
308 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | ||
309 | // crate root, even if the parent modules is **not** visible. | ||
310 | if export { | ||
311 | self.update( | ||
312 | self.def_map.root, | ||
313 | &[(Some(name), PerNs::macros(macro_, Visibility::Public))], | ||
314 | Visibility::Public, | ||
315 | ImportType::Named, | ||
316 | ); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | /// Define a legacy textual scoped macro in module | ||
321 | /// | ||
322 | /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module. | ||
323 | /// It will clone all macros from parent legacy scope, whose definition is prior to | ||
324 | /// the definition of current module. | ||
325 | /// And also, `macro_use` on a module will import all legacy macros visible inside to | ||
326 | /// current legacy scope, with possible shadowing. | ||
327 | fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) { | ||
328 | // Always shadowing | ||
329 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); | ||
330 | } | ||
331 | |||
332 | /// Define a proc macro | ||
333 | /// | ||
334 | /// A proc macro is similar to normal macro scope, but it would not visiable in legacy textual scoped. | ||
335 | /// And unconditionally exported. | ||
336 | fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { | ||
337 | self.update( | ||
338 | self.def_map.root, | ||
339 | &[(Some(name), PerNs::macros(macro_, Visibility::Public))], | ||
340 | Visibility::Public, | ||
341 | ImportType::Named, | ||
342 | ); | ||
343 | } | ||
344 | |||
345 | /// Import macros from `#[macro_use] extern crate`. | ||
346 | fn import_macros_from_extern_crate( | ||
347 | &mut self, | ||
348 | current_module_id: LocalModuleId, | ||
349 | import: &item_tree::ExternCrate, | ||
350 | ) { | ||
351 | log::debug!( | ||
352 | "importing macros from extern crate: {:?} ({:?})", | ||
353 | import, | ||
354 | self.def_map.edition, | ||
355 | ); | ||
356 | |||
357 | let res = self.def_map.resolve_name_in_extern_prelude( | ||
358 | &import | ||
359 | .path | ||
360 | .as_ident() | ||
361 | .expect("extern crate should have been desugared to one-element path"), | ||
362 | ); | ||
363 | |||
364 | if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { | ||
365 | mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
366 | self.import_all_macros_exported(current_module_id, m.krate); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /// Import all exported macros from another crate | ||
371 | /// | ||
372 | /// Exported macros are just all macros in the root module scope. | ||
373 | /// Note that it contains not only all `#[macro_export]` macros, but also all aliases | ||
374 | /// created by `use` in the root module, ignoring the visibility of `use`. | ||
375 | fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) { | ||
376 | let def_map = self.db.crate_def_map(krate); | ||
377 | for (name, def) in def_map[def_map.root].scope.macros() { | ||
378 | // `macro_use` only bring things into legacy scope. | ||
379 | self.define_legacy_macro(current_module_id, name.clone(), def); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | /// Import resolution | ||
384 | /// | ||
385 | /// This is a fix point algorithm. We resolve imports until no forward | ||
386 | /// progress in resolving imports is made | ||
387 | fn resolve_imports(&mut self) { | ||
388 | let mut n_previous_unresolved = self.unresolved_imports.len() + 1; | ||
389 | |||
390 | while self.unresolved_imports.len() < n_previous_unresolved { | ||
391 | n_previous_unresolved = self.unresolved_imports.len(); | ||
392 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | ||
393 | for mut directive in imports { | ||
394 | directive.status = self.resolve_import(directive.module_id, &directive.import); | ||
395 | match directive.status { | ||
396 | PartialResolvedImport::Indeterminate(_) => { | ||
397 | self.record_resolved_import(&directive); | ||
398 | // FIXME: For avoid performance regression, | ||
399 | // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved) | ||
400 | self.resolved_imports.push(directive) | ||
401 | } | ||
402 | PartialResolvedImport::Resolved(_) => { | ||
403 | self.record_resolved_import(&directive); | ||
404 | self.resolved_imports.push(directive) | ||
405 | } | ||
406 | PartialResolvedImport::Unresolved => { | ||
407 | self.unresolved_imports.push(directive); | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { | ||
415 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | ||
416 | if import.is_extern_crate { | ||
417 | let res = self.def_map.resolve_name_in_extern_prelude( | ||
418 | &import | ||
419 | .path | ||
420 | .as_ident() | ||
421 | .expect("extern crate should have been desugared to one-element path"), | ||
422 | ); | ||
423 | PartialResolvedImport::Resolved(res) | ||
424 | } else { | ||
425 | let res = self.def_map.resolve_path_fp_with_macro( | ||
426 | self.db, | ||
427 | ResolveMode::Import, | ||
428 | module_id, | ||
429 | &import.path, | ||
430 | BuiltinShadowMode::Module, | ||
431 | ); | ||
432 | |||
433 | let def = res.resolved_def; | ||
434 | if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() { | ||
435 | return PartialResolvedImport::Unresolved; | ||
436 | } | ||
437 | |||
438 | if let Some(krate) = res.krate { | ||
439 | if krate != self.def_map.krate { | ||
440 | return PartialResolvedImport::Resolved(def); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | // Check whether all namespace is resolved | ||
445 | if def.take_types().is_some() | ||
446 | && def.take_values().is_some() | ||
447 | && def.take_macros().is_some() | ||
448 | { | ||
449 | PartialResolvedImport::Resolved(def) | ||
450 | } else { | ||
451 | PartialResolvedImport::Indeterminate(def) | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | fn record_resolved_import(&mut self, directive: &ImportDirective) { | ||
457 | let module_id = directive.module_id; | ||
458 | let import = &directive.import; | ||
459 | let def = directive.status.namespaces(); | ||
460 | let vis = self | ||
461 | .def_map | ||
462 | .resolve_visibility(self.db, module_id, &directive.import.visibility) | ||
463 | .unwrap_or(Visibility::Public); | ||
464 | |||
465 | if import.is_glob { | ||
466 | log::debug!("glob import: {:?}", import); | ||
467 | match def.take_types() { | ||
468 | Some(ModuleDefId::ModuleId(m)) => { | ||
469 | if import.is_prelude { | ||
470 | mark::hit!(std_prelude); | ||
471 | self.def_map.prelude = Some(m); | ||
472 | } else if m.krate != self.def_map.krate { | ||
473 | mark::hit!(glob_across_crates); | ||
474 | // glob import from other crate => we can just import everything once | ||
475 | let item_map = self.db.crate_def_map(m.krate); | ||
476 | let scope = &item_map[m.local_id].scope; | ||
477 | |||
478 | // Module scoped macros is included | ||
479 | let items = scope | ||
480 | .resolutions() | ||
481 | // only keep visible names... | ||
482 | .map(|(n, res)| { | ||
483 | (n, res.filter_visibility(|v| v.is_visible_from_other_crate())) | ||
484 | }) | ||
485 | .filter(|(_, res)| !res.is_none()) | ||
486 | .collect::<Vec<_>>(); | ||
487 | |||
488 | self.update(module_id, &items, vis, ImportType::Glob); | ||
489 | } else { | ||
490 | // glob import from same crate => we do an initial | ||
491 | // import, and then need to propagate any further | ||
492 | // additions | ||
493 | let scope = &self.def_map[m.local_id].scope; | ||
494 | |||
495 | // Module scoped macros is included | ||
496 | let items = scope | ||
497 | .resolutions() | ||
498 | // only keep visible names... | ||
499 | .map(|(n, res)| { | ||
500 | ( | ||
501 | n, | ||
502 | res.filter_visibility(|v| { | ||
503 | v.is_visible_from_def_map(&self.def_map, module_id) | ||
504 | }), | ||
505 | ) | ||
506 | }) | ||
507 | .filter(|(_, res)| !res.is_none()) | ||
508 | .collect::<Vec<_>>(); | ||
509 | |||
510 | self.update(module_id, &items, vis, ImportType::Glob); | ||
511 | // record the glob import in case we add further items | ||
512 | let glob = self.glob_imports.entry(m.local_id).or_default(); | ||
513 | if !glob.iter().any(|(mid, _)| *mid == module_id) { | ||
514 | glob.push((module_id, vis)); | ||
515 | } | ||
516 | } | ||
517 | } | ||
518 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | ||
519 | mark::hit!(glob_enum); | ||
520 | // glob import from enum => just import all the variants | ||
521 | |||
522 | // XXX: urgh, so this works by accident! Here, we look at | ||
523 | // the enum data, and, in theory, this might require us to | ||
524 | // look back at the crate_def_map, creating a cycle. For | ||
525 | // example, `enum E { crate::some_macro!(); }`. Luckely, the | ||
526 | // only kind of macro that is allowed inside enum is a | ||
527 | // `cfg_macro`, and we don't need to run name resolution for | ||
528 | // it, but this is sheer luck! | ||
529 | let enum_data = self.db.enum_data(e); | ||
530 | let resolutions = enum_data | ||
531 | .variants | ||
532 | .iter() | ||
533 | .map(|(local_id, variant_data)| { | ||
534 | let name = variant_data.name.clone(); | ||
535 | let variant = EnumVariantId { parent: e, local_id }; | ||
536 | let res = PerNs::both(variant.into(), variant.into(), vis); | ||
537 | (Some(name), res) | ||
538 | }) | ||
539 | .collect::<Vec<_>>(); | ||
540 | self.update(module_id, &resolutions, vis, ImportType::Glob); | ||
541 | } | ||
542 | Some(d) => { | ||
543 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | ||
544 | } | ||
545 | None => { | ||
546 | log::debug!("glob import {:?} didn't resolve as type", import); | ||
547 | } | ||
548 | } | ||
549 | } else { | ||
550 | match import.path.segments.last() { | ||
551 | Some(last_segment) => { | ||
552 | let name = match &import.alias { | ||
553 | Some(ImportAlias::Alias(name)) => Some(name.clone()), | ||
554 | Some(ImportAlias::Underscore) => None, | ||
555 | None => Some(last_segment.clone()), | ||
556 | }; | ||
557 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | ||
558 | |||
559 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | ||
560 | if import.is_extern_crate && module_id == self.def_map.root { | ||
561 | if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) { | ||
562 | self.def_map.extern_prelude.insert(name.clone(), def); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | self.update(module_id, &[(name, def)], vis, ImportType::Named); | ||
567 | } | ||
568 | None => mark::hit!(bogus_paths), | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | |||
573 | fn update( | ||
574 | &mut self, | ||
575 | module_id: LocalModuleId, | ||
576 | resolutions: &[(Option<Name>, PerNs)], | ||
577 | vis: Visibility, | ||
578 | import_type: ImportType, | ||
579 | ) { | ||
580 | self.db.check_canceled(); | ||
581 | self.update_recursive(module_id, resolutions, vis, import_type, 0) | ||
582 | } | ||
583 | |||
584 | fn update_recursive( | ||
585 | &mut self, | ||
586 | module_id: LocalModuleId, | ||
587 | resolutions: &[(Option<Name>, PerNs)], | ||
588 | // All resolutions are imported with this visibility; the visibilies in | ||
589 | // the `PerNs` values are ignored and overwritten | ||
590 | vis: Visibility, | ||
591 | import_type: ImportType, | ||
592 | depth: usize, | ||
593 | ) { | ||
594 | if depth > GLOB_RECURSION_LIMIT { | ||
595 | // prevent stack overflows (but this shouldn't be possible) | ||
596 | panic!("infinite recursion in glob imports!"); | ||
597 | } | ||
598 | let mut changed = false; | ||
599 | |||
600 | for (name, res) in resolutions { | ||
601 | match name { | ||
602 | Some(name) => { | ||
603 | let scope = &mut self.def_map.modules[module_id].scope; | ||
604 | changed |= scope.push_res_with_import( | ||
605 | &mut self.from_glob_import, | ||
606 | (module_id, name.clone()), | ||
607 | res.with_visibility(vis), | ||
608 | import_type, | ||
609 | ); | ||
610 | } | ||
611 | None => { | ||
612 | let tr = match res.take_types() { | ||
613 | Some(ModuleDefId::TraitId(tr)) => tr, | ||
614 | Some(other) => { | ||
615 | log::debug!("non-trait `_` import of {:?}", other); | ||
616 | continue; | ||
617 | } | ||
618 | None => continue, | ||
619 | }; | ||
620 | let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr); | ||
621 | let should_update = match old_vis { | ||
622 | None => true, | ||
623 | Some(old_vis) => { | ||
624 | let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| { | ||
625 | panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr); | ||
626 | }); | ||
627 | |||
628 | if max_vis == old_vis { | ||
629 | false | ||
630 | } else { | ||
631 | mark::hit!(upgrade_underscore_visibility); | ||
632 | true | ||
633 | } | ||
634 | } | ||
635 | }; | ||
636 | |||
637 | if should_update { | ||
638 | changed = true; | ||
639 | self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis); | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | |||
645 | if !changed { | ||
646 | return; | ||
647 | } | ||
648 | let glob_imports = self | ||
649 | .glob_imports | ||
650 | .get(&module_id) | ||
651 | .into_iter() | ||
652 | .flat_map(|v| v.iter()) | ||
653 | .filter(|(glob_importing_module, _)| { | ||
654 | // we know all resolutions have the same visibility (`vis`), so we | ||
655 | // just need to check that once | ||
656 | vis.is_visible_from_def_map(&self.def_map, *glob_importing_module) | ||
657 | }) | ||
658 | .cloned() | ||
659 | .collect::<Vec<_>>(); | ||
660 | |||
661 | for (glob_importing_module, glob_import_vis) in glob_imports { | ||
662 | self.update_recursive( | ||
663 | glob_importing_module, | ||
664 | resolutions, | ||
665 | glob_import_vis, | ||
666 | ImportType::Glob, | ||
667 | depth + 1, | ||
668 | ); | ||
669 | } | ||
670 | } | ||
671 | |||
672 | fn resolve_macros(&mut self) -> ReachedFixedPoint { | ||
673 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | ||
674 | let mut attribute_macros = | ||
675 | std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new()); | ||
676 | let mut resolved = Vec::new(); | ||
677 | let mut res = ReachedFixedPoint::Yes; | ||
678 | macros.retain(|directive| { | ||
679 | if let Some(call_id) = directive.legacy { | ||
680 | res = ReachedFixedPoint::No; | ||
681 | resolved.push((directive.module_id, call_id, directive.depth)); | ||
682 | return false; | ||
683 | } | ||
684 | |||
685 | if let Some(call_id) = | ||
686 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { | ||
687 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | ||
688 | self.db, | ||
689 | ResolveMode::Other, | ||
690 | directive.module_id, | ||
691 | &path, | ||
692 | BuiltinShadowMode::Module, | ||
693 | ); | ||
694 | resolved_res.resolved_def.take_macros() | ||
695 | }) | ||
696 | { | ||
697 | resolved.push((directive.module_id, call_id, directive.depth)); | ||
698 | res = ReachedFixedPoint::No; | ||
699 | return false; | ||
700 | } | ||
701 | |||
702 | true | ||
703 | }); | ||
704 | attribute_macros.retain(|directive| { | ||
705 | if let Some(call_id) = | ||
706 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { | ||
707 | self.resolve_attribute_macro(&directive, &path) | ||
708 | }) | ||
709 | { | ||
710 | resolved.push((directive.module_id, call_id, 0)); | ||
711 | res = ReachedFixedPoint::No; | ||
712 | return false; | ||
713 | } | ||
714 | |||
715 | true | ||
716 | }); | ||
717 | |||
718 | self.unexpanded_macros = macros; | ||
719 | self.unexpanded_attribute_macros = attribute_macros; | ||
720 | |||
721 | for (module_id, macro_call_id, depth) in resolved { | ||
722 | self.collect_macro_expansion(module_id, macro_call_id, depth); | ||
723 | } | ||
724 | |||
725 | res | ||
726 | } | ||
727 | |||
728 | fn resolve_attribute_macro( | ||
729 | &self, | ||
730 | directive: &DeriveDirective, | ||
731 | path: &ModPath, | ||
732 | ) -> Option<MacroDefId> { | ||
733 | if let Some(name) = path.as_ident() { | ||
734 | // FIXME this should actually be handled with the normal name | ||
735 | // resolution; the std lib defines built-in stubs for the derives, | ||
736 | // but these are new-style `macro`s, which we don't support yet | ||
737 | if let Some(def_id) = find_builtin_derive(name) { | ||
738 | return Some(def_id); | ||
739 | } | ||
740 | } | ||
741 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | ||
742 | self.db, | ||
743 | ResolveMode::Other, | ||
744 | directive.module_id, | ||
745 | &path, | ||
746 | BuiltinShadowMode::Module, | ||
747 | ); | ||
748 | |||
749 | resolved_res.resolved_def.take_macros() | ||
750 | } | ||
751 | |||
752 | fn collect_macro_expansion( | ||
753 | &mut self, | ||
754 | module_id: LocalModuleId, | ||
755 | macro_call_id: MacroCallId, | ||
756 | depth: usize, | ||
757 | ) { | ||
758 | if depth > EXPANSION_DEPTH_LIMIT { | ||
759 | mark::hit!(macro_expansion_overflow); | ||
760 | log::warn!("macro expansion is too deep"); | ||
761 | return; | ||
762 | } | ||
763 | let file_id: HirFileId = macro_call_id.as_file(); | ||
764 | let item_tree = self.db.item_tree(file_id); | ||
765 | let mod_dir = self.mod_dirs[&module_id].clone(); | ||
766 | ModCollector { | ||
767 | def_collector: &mut *self, | ||
768 | macro_depth: depth, | ||
769 | file_id, | ||
770 | module_id, | ||
771 | item_tree: &item_tree, | ||
772 | mod_dir, | ||
773 | } | ||
774 | .collect(item_tree.top_level_items()); | ||
775 | } | ||
776 | |||
777 | fn finish(self) -> CrateDefMap { | ||
778 | self.def_map | ||
779 | } | ||
780 | } | ||
781 | |||
782 | /// Walks a single module, populating defs, imports and macros | ||
783 | struct ModCollector<'a, 'b> { | ||
784 | def_collector: &'a mut DefCollector<'b>, | ||
785 | macro_depth: usize, | ||
786 | module_id: LocalModuleId, | ||
787 | file_id: HirFileId, | ||
788 | item_tree: &'a ItemTree, | ||
789 | mod_dir: ModDir, | ||
790 | } | ||
791 | |||
792 | impl ModCollector<'_, '_> { | ||
793 | fn collect(&mut self, items: &[ModItem]) { | ||
794 | // Note: don't assert that inserted value is fresh: it's simply not true | ||
795 | // for macros. | ||
796 | self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); | ||
797 | |||
798 | // Prelude module is always considered to be `#[macro_use]`. | ||
799 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | ||
800 | if prelude_module.krate != self.def_collector.def_map.krate { | ||
801 | mark::hit!(prelude_is_macro_use); | ||
802 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | // This should be processed eagerly instead of deferred to resolving. | ||
807 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | ||
808 | // any other items. | ||
809 | for item in items { | ||
810 | if self.is_cfg_enabled(self.item_tree.attrs((*item).into())) { | ||
811 | if let ModItem::ExternCrate(id) = item { | ||
812 | let import = self.item_tree[*id].clone(); | ||
813 | if import.is_macro_use { | ||
814 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | ||
815 | } | ||
816 | } | ||
817 | } | ||
818 | } | ||
819 | |||
820 | for &item in items { | ||
821 | let attrs = self.item_tree.attrs(item.into()); | ||
822 | if self.is_cfg_enabled(attrs) { | ||
823 | let module = | ||
824 | ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | ||
825 | let container = ContainerId::ModuleId(module); | ||
826 | |||
827 | let mut def = None; | ||
828 | match item { | ||
829 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs), | ||
830 | ModItem::Import(import_id) => { | ||
831 | self.def_collector.unresolved_imports.push(ImportDirective { | ||
832 | module_id: self.module_id, | ||
833 | import: Import::from_use(&self.item_tree, import_id), | ||
834 | status: PartialResolvedImport::Unresolved, | ||
835 | }) | ||
836 | } | ||
837 | ModItem::ExternCrate(import_id) => { | ||
838 | self.def_collector.unresolved_imports.push(ImportDirective { | ||
839 | module_id: self.module_id, | ||
840 | import: Import::from_extern_crate(&self.item_tree, import_id), | ||
841 | status: PartialResolvedImport::Unresolved, | ||
842 | }) | ||
843 | } | ||
844 | ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]), | ||
845 | ModItem::Impl(imp) => { | ||
846 | let module = ModuleId { | ||
847 | krate: self.def_collector.def_map.krate, | ||
848 | local_id: self.module_id, | ||
849 | }; | ||
850 | let container = ContainerId::ModuleId(module); | ||
851 | let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } | ||
852 | .intern(self.def_collector.db); | ||
853 | self.def_collector.def_map.modules[self.module_id] | ||
854 | .scope | ||
855 | .define_impl(impl_id) | ||
856 | } | ||
857 | ModItem::Function(id) => { | ||
858 | let func = &self.item_tree[id]; | ||
859 | def = Some(DefData { | ||
860 | id: FunctionLoc { | ||
861 | container: container.into(), | ||
862 | id: ItemTreeId::new(self.file_id, id), | ||
863 | } | ||
864 | .intern(self.def_collector.db) | ||
865 | .into(), | ||
866 | name: &func.name, | ||
867 | visibility: &self.item_tree[func.visibility], | ||
868 | has_constructor: false, | ||
869 | }); | ||
870 | } | ||
871 | ModItem::Struct(id) => { | ||
872 | let it = &self.item_tree[id]; | ||
873 | |||
874 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
875 | // in which case we don't add the invocation, just a single attribute | ||
876 | // macro invocation | ||
877 | self.collect_derives(attrs, it.ast_id.upcast()); | ||
878 | |||
879 | def = Some(DefData { | ||
880 | id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
881 | .intern(self.def_collector.db) | ||
882 | .into(), | ||
883 | name: &it.name, | ||
884 | visibility: &self.item_tree[it.visibility], | ||
885 | has_constructor: it.kind != StructDefKind::Record, | ||
886 | }); | ||
887 | } | ||
888 | ModItem::Union(id) => { | ||
889 | let it = &self.item_tree[id]; | ||
890 | |||
891 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
892 | // in which case we don't add the invocation, just a single attribute | ||
893 | // macro invocation | ||
894 | self.collect_derives(attrs, it.ast_id.upcast()); | ||
895 | |||
896 | def = Some(DefData { | ||
897 | id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
898 | .intern(self.def_collector.db) | ||
899 | .into(), | ||
900 | name: &it.name, | ||
901 | visibility: &self.item_tree[it.visibility], | ||
902 | has_constructor: false, | ||
903 | }); | ||
904 | } | ||
905 | ModItem::Enum(id) => { | ||
906 | let it = &self.item_tree[id]; | ||
907 | |||
908 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
909 | // in which case we don't add the invocation, just a single attribute | ||
910 | // macro invocation | ||
911 | self.collect_derives(attrs, it.ast_id.upcast()); | ||
912 | |||
913 | def = Some(DefData { | ||
914 | id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
915 | .intern(self.def_collector.db) | ||
916 | .into(), | ||
917 | name: &it.name, | ||
918 | visibility: &self.item_tree[it.visibility], | ||
919 | has_constructor: false, | ||
920 | }); | ||
921 | } | ||
922 | ModItem::Const(id) => { | ||
923 | let it = &self.item_tree[id]; | ||
924 | |||
925 | if let Some(name) = &it.name { | ||
926 | def = Some(DefData { | ||
927 | id: ConstLoc { | ||
928 | container: container.into(), | ||
929 | id: ItemTreeId::new(self.file_id, id), | ||
930 | } | ||
931 | .intern(self.def_collector.db) | ||
932 | .into(), | ||
933 | name, | ||
934 | visibility: &self.item_tree[it.visibility], | ||
935 | has_constructor: false, | ||
936 | }); | ||
937 | } | ||
938 | } | ||
939 | ModItem::Static(id) => { | ||
940 | let it = &self.item_tree[id]; | ||
941 | |||
942 | def = Some(DefData { | ||
943 | id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
944 | .intern(self.def_collector.db) | ||
945 | .into(), | ||
946 | name: &it.name, | ||
947 | visibility: &self.item_tree[it.visibility], | ||
948 | has_constructor: false, | ||
949 | }); | ||
950 | } | ||
951 | ModItem::Trait(id) => { | ||
952 | let it = &self.item_tree[id]; | ||
953 | |||
954 | def = Some(DefData { | ||
955 | id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) } | ||
956 | .intern(self.def_collector.db) | ||
957 | .into(), | ||
958 | name: &it.name, | ||
959 | visibility: &self.item_tree[it.visibility], | ||
960 | has_constructor: false, | ||
961 | }); | ||
962 | } | ||
963 | ModItem::TypeAlias(id) => { | ||
964 | let it = &self.item_tree[id]; | ||
965 | |||
966 | def = Some(DefData { | ||
967 | id: TypeAliasLoc { | ||
968 | container: container.into(), | ||
969 | id: ItemTreeId::new(self.file_id, id), | ||
970 | } | ||
971 | .intern(self.def_collector.db) | ||
972 | .into(), | ||
973 | name: &it.name, | ||
974 | visibility: &self.item_tree[it.visibility], | ||
975 | has_constructor: false, | ||
976 | }); | ||
977 | } | ||
978 | } | ||
979 | |||
980 | if let Some(DefData { id, name, visibility, has_constructor }) = def { | ||
981 | self.def_collector.def_map.modules[self.module_id].scope.define_def(id); | ||
982 | let vis = self | ||
983 | .def_collector | ||
984 | .def_map | ||
985 | .resolve_visibility(self.def_collector.db, self.module_id, visibility) | ||
986 | .unwrap_or(Visibility::Public); | ||
987 | self.def_collector.update( | ||
988 | self.module_id, | ||
989 | &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))], | ||
990 | vis, | ||
991 | ImportType::Named, | ||
992 | ) | ||
993 | } | ||
994 | } | ||
995 | } | ||
996 | } | ||
997 | |||
998 | fn collect_module(&mut self, module: &Mod, attrs: &Attrs) { | ||
999 | let path_attr = attrs.by_key("path").string_value(); | ||
1000 | let is_macro_use = attrs.by_key("macro_use").exists(); | ||
1001 | match &module.kind { | ||
1002 | // inline module, just recurse | ||
1003 | ModKind::Inline { items } => { | ||
1004 | let module_id = self.push_child_module( | ||
1005 | module.name.clone(), | ||
1006 | AstId::new(self.file_id, module.ast_id), | ||
1007 | None, | ||
1008 | &self.item_tree[module.visibility], | ||
1009 | ); | ||
1010 | |||
1011 | ModCollector { | ||
1012 | def_collector: &mut *self.def_collector, | ||
1013 | macro_depth: self.macro_depth, | ||
1014 | module_id, | ||
1015 | file_id: self.file_id, | ||
1016 | item_tree: self.item_tree, | ||
1017 | mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr), | ||
1018 | } | ||
1019 | .collect(&*items); | ||
1020 | if is_macro_use { | ||
1021 | self.import_all_legacy_macros(module_id); | ||
1022 | } | ||
1023 | } | ||
1024 | // out of line module, resolve, parse and recurse | ||
1025 | ModKind::Outline {} => { | ||
1026 | let ast_id = AstId::new(self.file_id, module.ast_id); | ||
1027 | match self.mod_dir.resolve_declaration( | ||
1028 | self.def_collector.db, | ||
1029 | self.file_id, | ||
1030 | &module.name, | ||
1031 | path_attr, | ||
1032 | ) { | ||
1033 | Ok((file_id, is_mod_rs, mod_dir)) => { | ||
1034 | let module_id = self.push_child_module( | ||
1035 | module.name.clone(), | ||
1036 | ast_id, | ||
1037 | Some((file_id, is_mod_rs)), | ||
1038 | &self.item_tree[module.visibility], | ||
1039 | ); | ||
1040 | let item_tree = self.def_collector.db.item_tree(file_id.into()); | ||
1041 | ModCollector { | ||
1042 | def_collector: &mut *self.def_collector, | ||
1043 | macro_depth: self.macro_depth, | ||
1044 | module_id, | ||
1045 | file_id: file_id.into(), | ||
1046 | item_tree: &item_tree, | ||
1047 | mod_dir, | ||
1048 | } | ||
1049 | .collect(item_tree.top_level_items()); | ||
1050 | if is_macro_use { | ||
1051 | self.import_all_legacy_macros(module_id); | ||
1052 | } | ||
1053 | } | ||
1054 | Err(candidate) => self.def_collector.def_map.diagnostics.push( | ||
1055 | DefDiagnostic::UnresolvedModule { | ||
1056 | module: self.module_id, | ||
1057 | declaration: ast_id, | ||
1058 | candidate, | ||
1059 | }, | ||
1060 | ), | ||
1061 | }; | ||
1062 | } | ||
1063 | } | ||
1064 | } | ||
1065 | |||
1066 | fn push_child_module( | ||
1067 | &mut self, | ||
1068 | name: Name, | ||
1069 | declaration: AstId<ast::Module>, | ||
1070 | definition: Option<(FileId, bool)>, | ||
1071 | visibility: &crate::visibility::RawVisibility, | ||
1072 | ) -> LocalModuleId { | ||
1073 | let vis = self | ||
1074 | .def_collector | ||
1075 | .def_map | ||
1076 | .resolve_visibility(self.def_collector.db, self.module_id, visibility) | ||
1077 | .unwrap_or(Visibility::Public); | ||
1078 | let modules = &mut self.def_collector.def_map.modules; | ||
1079 | let res = modules.alloc(ModuleData::default()); | ||
1080 | modules[res].parent = Some(self.module_id); | ||
1081 | modules[res].origin = match definition { | ||
1082 | None => ModuleOrigin::Inline { definition: declaration }, | ||
1083 | Some((definition, is_mod_rs)) => { | ||
1084 | ModuleOrigin::File { declaration, definition, is_mod_rs } | ||
1085 | } | ||
1086 | }; | ||
1087 | for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { | ||
1088 | modules[res].scope.define_legacy_macro(name, mac) | ||
1089 | } | ||
1090 | modules[self.module_id].children.insert(name.clone(), res); | ||
1091 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; | ||
1092 | let def: ModuleDefId = module.into(); | ||
1093 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); | ||
1094 | self.def_collector.update( | ||
1095 | self.module_id, | ||
1096 | &[(Some(name), PerNs::from_def(def, vis, false))], | ||
1097 | vis, | ||
1098 | ImportType::Named, | ||
1099 | ); | ||
1100 | res | ||
1101 | } | ||
1102 | |||
1103 | fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { | ||
1104 | for derive_subtree in attrs.by_key("derive").tt_values() { | ||
1105 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | ||
1106 | for tt in &derive_subtree.token_trees { | ||
1107 | let ident = match &tt { | ||
1108 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, | ||
1109 | tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok | ||
1110 | _ => continue, // anything else would be an error (which we currently ignore) | ||
1111 | }; | ||
1112 | let path = ModPath::from_tt_ident(ident); | ||
1113 | |||
1114 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); | ||
1115 | self.def_collector | ||
1116 | .unexpanded_attribute_macros | ||
1117 | .push(DeriveDirective { module_id: self.module_id, ast_id }); | ||
1118 | } | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | fn collect_macro(&mut self, mac: &MacroCall) { | ||
1123 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | ||
1124 | |||
1125 | // Case 0: builtin macros | ||
1126 | if mac.is_builtin { | ||
1127 | if let Some(name) = &mac.name { | ||
1128 | let krate = self.def_collector.def_map.krate; | ||
1129 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) { | ||
1130 | self.def_collector.define_macro( | ||
1131 | self.module_id, | ||
1132 | name.clone(), | ||
1133 | macro_id, | ||
1134 | mac.is_export, | ||
1135 | ); | ||
1136 | return; | ||
1137 | } | ||
1138 | } | ||
1139 | } | ||
1140 | |||
1141 | // Case 1: macro rules, define a macro in crate-global mutable scope | ||
1142 | if is_macro_rules(&mac.path) { | ||
1143 | if let Some(name) = &mac.name { | ||
1144 | let macro_id = MacroDefId { | ||
1145 | ast_id: Some(ast_id.ast_id), | ||
1146 | krate: Some(self.def_collector.def_map.krate), | ||
1147 | kind: MacroDefKind::Declarative, | ||
1148 | local_inner: mac.is_local_inner, | ||
1149 | }; | ||
1150 | self.def_collector.define_macro( | ||
1151 | self.module_id, | ||
1152 | name.clone(), | ||
1153 | macro_id, | ||
1154 | mac.is_export, | ||
1155 | ); | ||
1156 | } | ||
1157 | return; | ||
1158 | } | ||
1159 | |||
1160 | // Case 2: try to resolve in legacy scope and expand macro_rules | ||
1161 | if let Some(macro_call_id) = | ||
1162 | ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| { | ||
1163 | path.as_ident().and_then(|name| { | ||
1164 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | ||
1165 | }) | ||
1166 | }) | ||
1167 | { | ||
1168 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
1169 | module_id: self.module_id, | ||
1170 | ast_id, | ||
1171 | legacy: Some(macro_call_id), | ||
1172 | depth: self.macro_depth + 1, | ||
1173 | }); | ||
1174 | |||
1175 | return; | ||
1176 | } | ||
1177 | |||
1178 | // Case 3: resolve in module scope, expand during name resolution. | ||
1179 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. | ||
1180 | if ast_id.path.is_ident() { | ||
1181 | ast_id.path.kind = PathKind::Super(0); | ||
1182 | } | ||
1183 | |||
1184 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
1185 | module_id: self.module_id, | ||
1186 | ast_id, | ||
1187 | legacy: None, | ||
1188 | depth: self.macro_depth + 1, | ||
1189 | }); | ||
1190 | } | ||
1191 | |||
1192 | fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { | ||
1193 | let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); | ||
1194 | for (name, macro_) in macros { | ||
1195 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | ||
1200 | attrs.is_cfg_enabled(self.def_collector.cfg_options) | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | fn is_macro_rules(path: &ModPath) -> bool { | ||
1205 | path.as_ident() == Some(&name![macro_rules]) | ||
1206 | } | ||
1207 | |||
1208 | #[cfg(test)] | ||
1209 | mod tests { | ||
1210 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
1211 | use arena::Arena; | ||
1212 | use base_db::{fixture::WithFixture, SourceDatabase}; | ||
1213 | |||
1214 | use super::*; | ||
1215 | |||
1216 | fn do_collect_defs(db: &dyn DefDatabase, def_map: CrateDefMap) -> CrateDefMap { | ||
1217 | let mut collector = DefCollector { | ||
1218 | db, | ||
1219 | def_map, | ||
1220 | glob_imports: FxHashMap::default(), | ||
1221 | unresolved_imports: Vec::new(), | ||
1222 | resolved_imports: Vec::new(), | ||
1223 | unexpanded_macros: Vec::new(), | ||
1224 | unexpanded_attribute_macros: Vec::new(), | ||
1225 | mod_dirs: FxHashMap::default(), | ||
1226 | cfg_options: &CfgOptions::default(), | ||
1227 | proc_macros: Default::default(), | ||
1228 | from_glob_import: Default::default(), | ||
1229 | }; | ||
1230 | collector.collect(); | ||
1231 | collector.def_map | ||
1232 | } | ||
1233 | |||
1234 | fn do_resolve(code: &str) -> CrateDefMap { | ||
1235 | let (db, _file_id) = TestDB::with_single_file(&code); | ||
1236 | let krate = db.test_crate(); | ||
1237 | |||
1238 | let def_map = { | ||
1239 | let edition = db.crate_graph()[krate].edition; | ||
1240 | let mut modules: Arena<ModuleData> = Arena::default(); | ||
1241 | let root = modules.alloc(ModuleData::default()); | ||
1242 | CrateDefMap { | ||
1243 | krate, | ||
1244 | edition, | ||
1245 | extern_prelude: FxHashMap::default(), | ||
1246 | prelude: None, | ||
1247 | root, | ||
1248 | modules, | ||
1249 | diagnostics: Vec::new(), | ||
1250 | } | ||
1251 | }; | ||
1252 | do_collect_defs(&db, def_map) | ||
1253 | } | ||
1254 | |||
1255 | #[test] | ||
1256 | fn test_macro_expand_will_stop_1() { | ||
1257 | do_resolve( | ||
1258 | r#" | ||
1259 | macro_rules! foo { | ||
1260 | ($($ty:ty)*) => { foo!($($ty)*); } | ||
1261 | } | ||
1262 | foo!(KABOOM); | ||
1263 | "#, | ||
1264 | ); | ||
1265 | } | ||
1266 | |||
1267 | #[ignore] // this test does succeed, but takes quite a while :/ | ||
1268 | #[test] | ||
1269 | fn test_macro_expand_will_stop_2() { | ||
1270 | do_resolve( | ||
1271 | r#" | ||
1272 | macro_rules! foo { | ||
1273 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } | ||
1274 | } | ||
1275 | foo!(KABOOM); | ||
1276 | "#, | ||
1277 | ); | ||
1278 | } | ||
1279 | } | ||
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs new file mode 100644 index 000000000..e8389b484 --- /dev/null +++ b/crates/hir_def/src/nameres/mod_resolution.rs | |||
@@ -0,0 +1,139 @@ | |||
1 | //! This module resolves `mod foo;` declaration to file. | ||
2 | use base_db::FileId; | ||
3 | use hir_expand::name::Name; | ||
4 | use syntax::SmolStr; | ||
5 | |||
6 | use crate::{db::DefDatabase, HirFileId}; | ||
7 | |||
8 | #[derive(Clone, Debug)] | ||
9 | pub(super) struct ModDir { | ||
10 | /// `` for `mod.rs`, `lib.rs` | ||
11 | /// `foo/` for `foo.rs` | ||
12 | /// `foo/bar/` for `mod bar { mod x; }` nested in `foo.rs` | ||
13 | /// Invariant: path.is_empty() || path.ends_with('/') | ||
14 | dir_path: DirPath, | ||
15 | /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` | ||
16 | root_non_dir_owner: bool, | ||
17 | } | ||
18 | |||
19 | impl ModDir { | ||
20 | pub(super) fn root() -> ModDir { | ||
21 | ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false } | ||
22 | } | ||
23 | |||
24 | pub(super) fn descend_into_definition( | ||
25 | &self, | ||
26 | name: &Name, | ||
27 | attr_path: Option<&SmolStr>, | ||
28 | ) -> ModDir { | ||
29 | let path = match attr_path.map(|it| it.as_str()) { | ||
30 | None => { | ||
31 | let mut path = self.dir_path.clone(); | ||
32 | path.push(&name.to_string()); | ||
33 | path | ||
34 | } | ||
35 | Some(attr_path) => { | ||
36 | let mut path = self.dir_path.join_attr(attr_path, self.root_non_dir_owner); | ||
37 | if !(path.is_empty() || path.ends_with('/')) { | ||
38 | path.push('/') | ||
39 | } | ||
40 | DirPath::new(path) | ||
41 | } | ||
42 | }; | ||
43 | ModDir { dir_path: path, root_non_dir_owner: false } | ||
44 | } | ||
45 | |||
46 | pub(super) fn resolve_declaration( | ||
47 | &self, | ||
48 | db: &dyn DefDatabase, | ||
49 | file_id: HirFileId, | ||
50 | name: &Name, | ||
51 | attr_path: Option<&SmolStr>, | ||
52 | ) -> Result<(FileId, bool, ModDir), String> { | ||
53 | let file_id = file_id.original_file(db.upcast()); | ||
54 | |||
55 | let mut candidate_files = Vec::new(); | ||
56 | match attr_path { | ||
57 | Some(attr_path) => { | ||
58 | candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) | ||
59 | } | ||
60 | None => { | ||
61 | candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); | ||
62 | candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); | ||
63 | } | ||
64 | }; | ||
65 | |||
66 | for candidate in candidate_files.iter() { | ||
67 | if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) { | ||
68 | let is_mod_rs = candidate.ends_with("mod.rs"); | ||
69 | |||
70 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { | ||
71 | (DirPath::empty(), false) | ||
72 | } else { | ||
73 | (DirPath::new(format!("{}/", name)), true) | ||
74 | }; | ||
75 | return Ok((file_id, is_mod_rs, ModDir { dir_path, root_non_dir_owner })); | ||
76 | } | ||
77 | } | ||
78 | Err(candidate_files.remove(0)) | ||
79 | } | ||
80 | } | ||
81 | |||
82 | #[derive(Clone, Debug)] | ||
83 | struct DirPath(String); | ||
84 | |||
85 | impl DirPath { | ||
86 | fn assert_invariant(&self) { | ||
87 | assert!(self.0.is_empty() || self.0.ends_with('/')); | ||
88 | } | ||
89 | fn new(repr: String) -> DirPath { | ||
90 | let res = DirPath(repr); | ||
91 | res.assert_invariant(); | ||
92 | res | ||
93 | } | ||
94 | fn empty() -> DirPath { | ||
95 | DirPath::new(String::new()) | ||
96 | } | ||
97 | fn push(&mut self, name: &str) { | ||
98 | self.0.push_str(name); | ||
99 | self.0.push('/'); | ||
100 | self.assert_invariant(); | ||
101 | } | ||
102 | fn parent(&self) -> Option<&str> { | ||
103 | if self.0.is_empty() { | ||
104 | return None; | ||
105 | }; | ||
106 | let idx = | ||
107 | self.0[..self.0.len() - '/'.len_utf8()].rfind('/').map_or(0, |it| it + '/'.len_utf8()); | ||
108 | Some(&self.0[..idx]) | ||
109 | } | ||
110 | /// So this is the case which doesn't really work I think if we try to be | ||
111 | /// 100% platform agnostic: | ||
112 | /// | ||
113 | /// ``` | ||
114 | /// mod a { | ||
115 | /// #[path="C://sad/face"] | ||
116 | /// mod b { mod c; } | ||
117 | /// } | ||
118 | /// ``` | ||
119 | /// | ||
120 | /// Here, we need to join logical dir path to a string path from an | ||
121 | /// attribute. Ideally, we should somehow losslessly communicate the whole | ||
122 | /// construction to `FileLoader`. | ||
123 | fn join_attr(&self, mut attr: &str, relative_to_parent: bool) -> String { | ||
124 | let base = if relative_to_parent { self.parent().unwrap() } else { &self.0 }; | ||
125 | |||
126 | if attr.starts_with("./") { | ||
127 | attr = &attr["./".len()..]; | ||
128 | } | ||
129 | let tmp; | ||
130 | let attr = if attr.contains('\\') { | ||
131 | tmp = attr.replace('\\', "/"); | ||
132 | &tmp | ||
133 | } else { | ||
134 | attr | ||
135 | }; | ||
136 | let res = format!("{}{}", base, attr); | ||
137 | res | ||
138 | } | ||
139 | } | ||
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs new file mode 100644 index 000000000..88e10574e --- /dev/null +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -0,0 +1,330 @@ | |||
1 | //! This modules implements a function to resolve a path `foo::bar::baz` to a | ||
2 | //! def, which is used within the name resolution. | ||
3 | //! | ||
4 | //! When name resolution is finished, the result of resolving a path is either | ||
5 | //! `Some(def)` or `None`. However, when we are in process of resolving imports | ||
6 | //! or macros, there's a third possibility: | ||
7 | //! | ||
8 | //! I can't resolve this path right now, but I might be resolve this path | ||
9 | //! later, when more macros are expanded. | ||
10 | //! | ||
11 | //! `ReachedFixedPoint` signals about this. | ||
12 | |||
13 | use std::iter::successors; | ||
14 | |||
15 | use base_db::Edition; | ||
16 | use hir_expand::name::Name; | ||
17 | use test_utils::mark; | ||
18 | |||
19 | use crate::{ | ||
20 | db::DefDatabase, | ||
21 | item_scope::BUILTIN_SCOPE, | ||
22 | nameres::{BuiltinShadowMode, CrateDefMap}, | ||
23 | path::{ModPath, PathKind}, | ||
24 | per_ns::PerNs, | ||
25 | visibility::{RawVisibility, Visibility}, | ||
26 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, | ||
27 | }; | ||
28 | |||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
30 | pub(super) enum ResolveMode { | ||
31 | Import, | ||
32 | Other, | ||
33 | } | ||
34 | |||
35 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
36 | pub(super) enum ReachedFixedPoint { | ||
37 | Yes, | ||
38 | No, | ||
39 | } | ||
40 | |||
41 | #[derive(Debug, Clone)] | ||
42 | pub(super) struct ResolvePathResult { | ||
43 | pub(super) resolved_def: PerNs, | ||
44 | pub(super) segment_index: Option<usize>, | ||
45 | pub(super) reached_fixedpoint: ReachedFixedPoint, | ||
46 | pub(super) krate: Option<CrateId>, | ||
47 | } | ||
48 | |||
49 | impl ResolvePathResult { | ||
50 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | ||
51 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None) | ||
52 | } | ||
53 | |||
54 | fn with( | ||
55 | resolved_def: PerNs, | ||
56 | reached_fixedpoint: ReachedFixedPoint, | ||
57 | segment_index: Option<usize>, | ||
58 | krate: Option<CrateId>, | ||
59 | ) -> ResolvePathResult { | ||
60 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | impl CrateDefMap { | ||
65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | ||
66 | self.extern_prelude | ||
67 | .get(name) | ||
68 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) | ||
69 | } | ||
70 | |||
71 | pub(crate) fn resolve_visibility( | ||
72 | &self, | ||
73 | db: &dyn DefDatabase, | ||
74 | original_module: LocalModuleId, | ||
75 | visibility: &RawVisibility, | ||
76 | ) -> Option<Visibility> { | ||
77 | match visibility { | ||
78 | RawVisibility::Module(path) => { | ||
79 | let (result, remaining) = | ||
80 | self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module); | ||
81 | if remaining.is_some() { | ||
82 | return None; | ||
83 | } | ||
84 | let types = result.take_types()?; | ||
85 | match types { | ||
86 | ModuleDefId::ModuleId(m) => Some(Visibility::Module(m)), | ||
87 | _ => { | ||
88 | // error: visibility needs to refer to module | ||
89 | None | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | RawVisibility::Public => Some(Visibility::Public), | ||
94 | } | ||
95 | } | ||
96 | |||
97 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | ||
98 | // the result. | ||
99 | pub(super) fn resolve_path_fp_with_macro( | ||
100 | &self, | ||
101 | db: &dyn DefDatabase, | ||
102 | mode: ResolveMode, | ||
103 | original_module: LocalModuleId, | ||
104 | path: &ModPath, | ||
105 | shadow: BuiltinShadowMode, | ||
106 | ) -> ResolvePathResult { | ||
107 | let mut segments = path.segments.iter().enumerate(); | ||
108 | let mut curr_per_ns: PerNs = match path.kind { | ||
109 | PathKind::DollarCrate(krate) => { | ||
110 | if krate == self.krate { | ||
111 | mark::hit!(macro_dollar_crate_self); | ||
112 | PerNs::types( | ||
113 | ModuleId { krate: self.krate, local_id: self.root }.into(), | ||
114 | Visibility::Public, | ||
115 | ) | ||
116 | } else { | ||
117 | let def_map = db.crate_def_map(krate); | ||
118 | let module = ModuleId { krate, local_id: def_map.root }; | ||
119 | mark::hit!(macro_dollar_crate_other); | ||
120 | PerNs::types(module.into(), Visibility::Public) | ||
121 | } | ||
122 | } | ||
123 | PathKind::Crate => PerNs::types( | ||
124 | ModuleId { krate: self.krate, local_id: self.root }.into(), | ||
125 | Visibility::Public, | ||
126 | ), | ||
127 | // plain import or absolute path in 2015: crate-relative with | ||
128 | // fallback to extern prelude (with the simplification in | ||
129 | // rust-lang/rust#57745) | ||
130 | // FIXME there must be a nicer way to write this condition | ||
131 | PathKind::Plain | PathKind::Abs | ||
132 | if self.edition == Edition::Edition2015 | ||
133 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
134 | { | ||
135 | let (_, segment) = match segments.next() { | ||
136 | Some((idx, segment)) => (idx, segment), | ||
137 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
138 | }; | ||
139 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
140 | self.resolve_name_in_crate_root_or_extern_prelude(&segment) | ||
141 | } | ||
142 | PathKind::Plain => { | ||
143 | let (_, segment) = match segments.next() { | ||
144 | Some((idx, segment)) => (idx, segment), | ||
145 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
146 | }; | ||
147 | // The first segment may be a builtin type. If the path has more | ||
148 | // than one segment, we first try resolving it as a module | ||
149 | // anyway. | ||
150 | // FIXME: If the next segment doesn't resolve in the module and | ||
151 | // BuiltinShadowMode wasn't Module, then we need to try | ||
152 | // resolving it as a builtin. | ||
153 | let prefer_module = | ||
154 | if path.segments.len() == 1 { shadow } else { BuiltinShadowMode::Module }; | ||
155 | |||
156 | log::debug!("resolving {:?} in module", segment); | ||
157 | self.resolve_name_in_module(db, original_module, &segment, prefer_module) | ||
158 | } | ||
159 | PathKind::Super(lvl) => { | ||
160 | let m = successors(Some(original_module), |m| self.modules[*m].parent) | ||
161 | .nth(lvl as usize); | ||
162 | if let Some(local_id) = m { | ||
163 | PerNs::types( | ||
164 | ModuleId { krate: self.krate, local_id }.into(), | ||
165 | Visibility::Public, | ||
166 | ) | ||
167 | } else { | ||
168 | log::debug!("super path in root module"); | ||
169 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
170 | } | ||
171 | } | ||
172 | PathKind::Abs => { | ||
173 | // 2018-style absolute path -- only extern prelude | ||
174 | let segment = match segments.next() { | ||
175 | Some((_, segment)) => segment, | ||
176 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
177 | }; | ||
178 | if let Some(def) = self.extern_prelude.get(&segment) { | ||
179 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
180 | PerNs::types(*def, Visibility::Public) | ||
181 | } else { | ||
182 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | ||
183 | } | ||
184 | } | ||
185 | }; | ||
186 | |||
187 | for (i, segment) in segments { | ||
188 | let (curr, vis) = match curr_per_ns.take_types_vis() { | ||
189 | Some(r) => r, | ||
190 | None => { | ||
191 | // we still have path segments left, but the path so far | ||
192 | // didn't resolve in the types namespace => no resolution | ||
193 | // (don't break here because `curr_per_ns` might contain | ||
194 | // something in the value namespace, and it would be wrong | ||
195 | // to return that) | ||
196 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
197 | } | ||
198 | }; | ||
199 | // resolve segment in curr | ||
200 | |||
201 | curr_per_ns = match curr { | ||
202 | ModuleDefId::ModuleId(module) => { | ||
203 | if module.krate != self.krate { | ||
204 | let path = ModPath { | ||
205 | segments: path.segments[i..].to_vec(), | ||
206 | kind: PathKind::Super(0), | ||
207 | }; | ||
208 | log::debug!("resolving {:?} in other crate", path); | ||
209 | let defp_map = db.crate_def_map(module.krate); | ||
210 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); | ||
211 | return ResolvePathResult::with( | ||
212 | def, | ||
213 | ReachedFixedPoint::Yes, | ||
214 | s.map(|s| s + i), | ||
215 | Some(module.krate), | ||
216 | ); | ||
217 | } | ||
218 | |||
219 | // Since it is a qualified path here, it should not contains legacy macros | ||
220 | self[module.local_id].scope.get(&segment) | ||
221 | } | ||
222 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | ||
223 | // enum variant | ||
224 | mark::hit!(can_import_enum_variant); | ||
225 | let enum_data = db.enum_data(e); | ||
226 | match enum_data.variant(&segment) { | ||
227 | Some(local_id) => { | ||
228 | let variant = EnumVariantId { parent: e, local_id }; | ||
229 | match &*enum_data.variants[local_id].variant_data { | ||
230 | crate::adt::VariantData::Record(_) => { | ||
231 | PerNs::types(variant.into(), Visibility::Public) | ||
232 | } | ||
233 | crate::adt::VariantData::Tuple(_) | ||
234 | | crate::adt::VariantData::Unit => { | ||
235 | PerNs::both(variant.into(), variant.into(), Visibility::Public) | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | None => { | ||
240 | return ResolvePathResult::with( | ||
241 | PerNs::types(e.into(), vis), | ||
242 | ReachedFixedPoint::Yes, | ||
243 | Some(i), | ||
244 | Some(self.krate), | ||
245 | ); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | s => { | ||
250 | // could be an inherent method call in UFCS form | ||
251 | // (`Struct::method`), or some other kind of associated item | ||
252 | log::debug!( | ||
253 | "path segment {:?} resolved to non-module {:?}, but is not last", | ||
254 | segment, | ||
255 | curr, | ||
256 | ); | ||
257 | |||
258 | return ResolvePathResult::with( | ||
259 | PerNs::types(s, vis), | ||
260 | ReachedFixedPoint::Yes, | ||
261 | Some(i), | ||
262 | Some(self.krate), | ||
263 | ); | ||
264 | } | ||
265 | }; | ||
266 | } | ||
267 | |||
268 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) | ||
269 | } | ||
270 | |||
271 | fn resolve_name_in_module( | ||
272 | &self, | ||
273 | db: &dyn DefDatabase, | ||
274 | module: LocalModuleId, | ||
275 | name: &Name, | ||
276 | shadow: BuiltinShadowMode, | ||
277 | ) -> PerNs { | ||
278 | // Resolve in: | ||
279 | // - legacy scope of macro | ||
280 | // - current module / scope | ||
281 | // - extern prelude | ||
282 | // - std prelude | ||
283 | let from_legacy_macro = self[module] | ||
284 | .scope | ||
285 | .get_legacy_macro(name) | ||
286 | .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); | ||
287 | let from_scope = self[module].scope.get(name); | ||
288 | let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none); | ||
289 | let from_scope_or_builtin = match shadow { | ||
290 | BuiltinShadowMode::Module => from_scope.or(from_builtin), | ||
291 | BuiltinShadowMode::Other => { | ||
292 | if let Some(ModuleDefId::ModuleId(_)) = from_scope.take_types() { | ||
293 | from_builtin.or(from_scope) | ||
294 | } else { | ||
295 | from_scope.or(from_builtin) | ||
296 | } | ||
297 | } | ||
298 | }; | ||
299 | let from_extern_prelude = self | ||
300 | .extern_prelude | ||
301 | .get(name) | ||
302 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)); | ||
303 | let from_prelude = self.resolve_in_prelude(db, name); | ||
304 | |||
305 | from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) | ||
306 | } | ||
307 | |||
308 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { | ||
309 | let from_crate_root = self[self.root].scope.get(name); | ||
310 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | ||
311 | |||
312 | from_crate_root.or(from_extern_prelude) | ||
313 | } | ||
314 | |||
315 | fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { | ||
316 | if let Some(prelude) = self.prelude { | ||
317 | let keep; | ||
318 | let def_map = if prelude.krate == self.krate { | ||
319 | self | ||
320 | } else { | ||
321 | // Extend lifetime | ||
322 | keep = db.crate_def_map(prelude.krate); | ||
323 | &keep | ||
324 | }; | ||
325 | def_map[prelude.local_id].scope.get(name) | ||
326 | } else { | ||
327 | PerNs::none() | ||
328 | } | ||
329 | } | ||
330 | } | ||
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs new file mode 100644 index 000000000..b105d56b2 --- /dev/null +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -0,0 +1,690 @@ | |||
1 | mod globs; | ||
2 | mod incremental; | ||
3 | mod macros; | ||
4 | mod mod_resolution; | ||
5 | mod primitives; | ||
6 | |||
7 | use std::sync::Arc; | ||
8 | |||
9 | use base_db::{fixture::WithFixture, SourceDatabase}; | ||
10 | use expect::{expect, Expect}; | ||
11 | use test_utils::mark; | ||
12 | |||
13 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | ||
14 | |||
15 | fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { | ||
16 | let db = TestDB::with_files(fixture); | ||
17 | let krate = db.crate_graph().iter().next().unwrap(); | ||
18 | db.crate_def_map(krate) | ||
19 | } | ||
20 | |||
21 | fn check(ra_fixture: &str, expect: Expect) { | ||
22 | let db = TestDB::with_files(ra_fixture); | ||
23 | let krate = db.crate_graph().iter().next().unwrap(); | ||
24 | let actual = db.crate_def_map(krate).dump(); | ||
25 | expect.assert_eq(&actual); | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn crate_def_map_smoke_test() { | ||
30 | check( | ||
31 | r#" | ||
32 | //- /lib.rs | ||
33 | mod foo; | ||
34 | struct S; | ||
35 | use crate::foo::bar::E; | ||
36 | use self::E::V; | ||
37 | |||
38 | //- /foo/mod.rs | ||
39 | pub mod bar; | ||
40 | fn f() {} | ||
41 | |||
42 | //- /foo/bar.rs | ||
43 | pub struct Baz; | ||
44 | |||
45 | union U { to_be: bool, not_to_be: u8 } | ||
46 | enum E { V } | ||
47 | |||
48 | extern { | ||
49 | static EXT: u8; | ||
50 | fn ext(); | ||
51 | } | ||
52 | "#, | ||
53 | expect![[r#" | ||
54 | crate | ||
55 | E: t | ||
56 | S: t v | ||
57 | V: t v | ||
58 | foo: t | ||
59 | |||
60 | crate::foo | ||
61 | bar: t | ||
62 | f: v | ||
63 | |||
64 | crate::foo::bar | ||
65 | Baz: t v | ||
66 | E: t | ||
67 | EXT: v | ||
68 | U: t | ||
69 | ext: v | ||
70 | "#]], | ||
71 | ); | ||
72 | } | ||
73 | |||
74 | #[test] | ||
75 | fn crate_def_map_super_super() { | ||
76 | check( | ||
77 | r#" | ||
78 | mod a { | ||
79 | const A: usize = 0; | ||
80 | mod b { | ||
81 | const B: usize = 0; | ||
82 | mod c { | ||
83 | use super::super::*; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | "#, | ||
88 | expect![[r#" | ||
89 | crate | ||
90 | a: t | ||
91 | |||
92 | crate::a | ||
93 | A: v | ||
94 | b: t | ||
95 | |||
96 | crate::a::b | ||
97 | B: v | ||
98 | c: t | ||
99 | |||
100 | crate::a::b::c | ||
101 | A: v | ||
102 | b: t | ||
103 | "#]], | ||
104 | ); | ||
105 | } | ||
106 | |||
107 | #[test] | ||
108 | fn crate_def_map_fn_mod_same_name() { | ||
109 | check( | ||
110 | r#" | ||
111 | mod m { | ||
112 | pub mod z {} | ||
113 | pub fn z() {} | ||
114 | } | ||
115 | "#, | ||
116 | expect![[r#" | ||
117 | crate | ||
118 | m: t | ||
119 | |||
120 | crate::m | ||
121 | z: t v | ||
122 | |||
123 | crate::m::z | ||
124 | "#]], | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | #[test] | ||
129 | fn bogus_paths() { | ||
130 | mark::check!(bogus_paths); | ||
131 | check( | ||
132 | r#" | ||
133 | //- /lib.rs | ||
134 | mod foo; | ||
135 | struct S; | ||
136 | use self; | ||
137 | |||
138 | //- /foo/mod.rs | ||
139 | use super; | ||
140 | use crate; | ||
141 | "#, | ||
142 | expect![[r#" | ||
143 | crate | ||
144 | S: t v | ||
145 | foo: t | ||
146 | |||
147 | crate::foo | ||
148 | "#]], | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn use_as() { | ||
154 | check( | ||
155 | r#" | ||
156 | //- /lib.rs | ||
157 | mod foo; | ||
158 | use crate::foo::Baz as Foo; | ||
159 | |||
160 | //- /foo/mod.rs | ||
161 | pub struct Baz; | ||
162 | "#, | ||
163 | expect![[r#" | ||
164 | crate | ||
165 | Foo: t v | ||
166 | foo: t | ||
167 | |||
168 | crate::foo | ||
169 | Baz: t v | ||
170 | "#]], | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn use_trees() { | ||
176 | check( | ||
177 | r#" | ||
178 | //- /lib.rs | ||
179 | mod foo; | ||
180 | use crate::foo::bar::{Baz, Quux}; | ||
181 | |||
182 | //- /foo/mod.rs | ||
183 | pub mod bar; | ||
184 | |||
185 | //- /foo/bar.rs | ||
186 | pub struct Baz; | ||
187 | pub enum Quux {}; | ||
188 | "#, | ||
189 | expect![[r#" | ||
190 | crate | ||
191 | Baz: t v | ||
192 | Quux: t | ||
193 | foo: t | ||
194 | |||
195 | crate::foo | ||
196 | bar: t | ||
197 | |||
198 | crate::foo::bar | ||
199 | Baz: t v | ||
200 | Quux: t | ||
201 | "#]], | ||
202 | ); | ||
203 | } | ||
204 | |||
205 | #[test] | ||
206 | fn re_exports() { | ||
207 | check( | ||
208 | r#" | ||
209 | //- /lib.rs | ||
210 | mod foo; | ||
211 | use self::foo::Baz; | ||
212 | |||
213 | //- /foo/mod.rs | ||
214 | pub mod bar; | ||
215 | pub use self::bar::Baz; | ||
216 | |||
217 | //- /foo/bar.rs | ||
218 | pub struct Baz; | ||
219 | "#, | ||
220 | expect![[r#" | ||
221 | crate | ||
222 | Baz: t v | ||
223 | foo: t | ||
224 | |||
225 | crate::foo | ||
226 | Baz: t v | ||
227 | bar: t | ||
228 | |||
229 | crate::foo::bar | ||
230 | Baz: t v | ||
231 | "#]], | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn std_prelude() { | ||
237 | mark::check!(std_prelude); | ||
238 | check( | ||
239 | r#" | ||
240 | //- /main.rs crate:main deps:test_crate | ||
241 | use Foo::*; | ||
242 | |||
243 | //- /lib.rs crate:test_crate | ||
244 | mod prelude; | ||
245 | #[prelude_import] | ||
246 | use prelude::*; | ||
247 | |||
248 | //- /prelude.rs | ||
249 | pub enum Foo { Bar, Baz }; | ||
250 | "#, | ||
251 | expect![[r#" | ||
252 | crate | ||
253 | Bar: t v | ||
254 | Baz: t v | ||
255 | "#]], | ||
256 | ); | ||
257 | } | ||
258 | |||
259 | #[test] | ||
260 | fn can_import_enum_variant() { | ||
261 | mark::check!(can_import_enum_variant); | ||
262 | check( | ||
263 | r#" | ||
264 | enum E { V } | ||
265 | use self::E::V; | ||
266 | "#, | ||
267 | expect![[r#" | ||
268 | crate | ||
269 | E: t | ||
270 | V: t v | ||
271 | "#]], | ||
272 | ); | ||
273 | } | ||
274 | |||
275 | #[test] | ||
276 | fn edition_2015_imports() { | ||
277 | check( | ||
278 | r#" | ||
279 | //- /main.rs crate:main deps:other_crate edition:2015 | ||
280 | mod foo; | ||
281 | mod bar; | ||
282 | |||
283 | //- /bar.rs | ||
284 | struct Bar; | ||
285 | |||
286 | //- /foo.rs | ||
287 | use bar::Bar; | ||
288 | use other_crate::FromLib; | ||
289 | |||
290 | //- /lib.rs crate:other_crate edition:2018 | ||
291 | struct FromLib; | ||
292 | "#, | ||
293 | expect![[r#" | ||
294 | crate | ||
295 | bar: t | ||
296 | foo: t | ||
297 | |||
298 | crate::bar | ||
299 | Bar: t v | ||
300 | |||
301 | crate::foo | ||
302 | Bar: t v | ||
303 | FromLib: t v | ||
304 | "#]], | ||
305 | ); | ||
306 | } | ||
307 | |||
308 | #[test] | ||
309 | fn item_map_using_self() { | ||
310 | check( | ||
311 | r#" | ||
312 | //- /lib.rs | ||
313 | mod foo; | ||
314 | use crate::foo::bar::Baz::{self}; | ||
315 | |||
316 | //- /foo/mod.rs | ||
317 | pub mod bar; | ||
318 | |||
319 | //- /foo/bar.rs | ||
320 | pub struct Baz; | ||
321 | "#, | ||
322 | expect![[r#" | ||
323 | crate | ||
324 | Baz: t v | ||
325 | foo: t | ||
326 | |||
327 | crate::foo | ||
328 | bar: t | ||
329 | |||
330 | crate::foo::bar | ||
331 | Baz: t v | ||
332 | "#]], | ||
333 | ); | ||
334 | } | ||
335 | |||
336 | #[test] | ||
337 | fn item_map_across_crates() { | ||
338 | check( | ||
339 | r#" | ||
340 | //- /main.rs crate:main deps:test_crate | ||
341 | use test_crate::Baz; | ||
342 | |||
343 | //- /lib.rs crate:test_crate | ||
344 | pub struct Baz; | ||
345 | "#, | ||
346 | expect![[r#" | ||
347 | crate | ||
348 | Baz: t v | ||
349 | "#]], | ||
350 | ); | ||
351 | } | ||
352 | |||
353 | #[test] | ||
354 | fn extern_crate_rename() { | ||
355 | check( | ||
356 | r#" | ||
357 | //- /main.rs crate:main deps:alloc | ||
358 | extern crate alloc as alloc_crate; | ||
359 | mod alloc; | ||
360 | mod sync; | ||
361 | |||
362 | //- /sync.rs | ||
363 | use alloc_crate::Arc; | ||
364 | |||
365 | //- /lib.rs crate:alloc | ||
366 | struct Arc; | ||
367 | "#, | ||
368 | expect![[r#" | ||
369 | crate | ||
370 | alloc_crate: t | ||
371 | sync: t | ||
372 | |||
373 | crate::sync | ||
374 | Arc: t v | ||
375 | "#]], | ||
376 | ); | ||
377 | } | ||
378 | |||
379 | #[test] | ||
380 | fn extern_crate_rename_2015_edition() { | ||
381 | check( | ||
382 | r#" | ||
383 | //- /main.rs crate:main deps:alloc edition:2015 | ||
384 | extern crate alloc as alloc_crate; | ||
385 | mod alloc; | ||
386 | mod sync; | ||
387 | |||
388 | //- /sync.rs | ||
389 | use alloc_crate::Arc; | ||
390 | |||
391 | //- /lib.rs crate:alloc | ||
392 | struct Arc; | ||
393 | "#, | ||
394 | expect![[r#" | ||
395 | crate | ||
396 | alloc_crate: t | ||
397 | sync: t | ||
398 | |||
399 | crate::sync | ||
400 | Arc: t v | ||
401 | "#]], | ||
402 | ); | ||
403 | } | ||
404 | |||
405 | #[test] | ||
406 | fn reexport_across_crates() { | ||
407 | check( | ||
408 | r#" | ||
409 | //- /main.rs crate:main deps:test_crate | ||
410 | use test_crate::Baz; | ||
411 | |||
412 | //- /lib.rs crate:test_crate | ||
413 | pub use foo::Baz; | ||
414 | mod foo; | ||
415 | |||
416 | //- /foo.rs | ||
417 | pub struct Baz; | ||
418 | "#, | ||
419 | expect![[r#" | ||
420 | crate | ||
421 | Baz: t v | ||
422 | "#]], | ||
423 | ); | ||
424 | } | ||
425 | |||
426 | #[test] | ||
427 | fn values_dont_shadow_extern_crates() { | ||
428 | check( | ||
429 | r#" | ||
430 | //- /main.rs crate:main deps:foo | ||
431 | fn foo() {} | ||
432 | use foo::Bar; | ||
433 | |||
434 | //- /foo/lib.rs crate:foo | ||
435 | pub struct Bar; | ||
436 | "#, | ||
437 | expect![[r#" | ||
438 | crate | ||
439 | Bar: t v | ||
440 | foo: v | ||
441 | "#]], | ||
442 | ); | ||
443 | } | ||
444 | |||
445 | #[test] | ||
446 | fn std_prelude_takes_precedence_above_core_prelude() { | ||
447 | check( | ||
448 | r#" | ||
449 | //- /main.rs crate:main deps:core,std | ||
450 | use {Foo, Bar}; | ||
451 | |||
452 | //- /std.rs crate:std deps:core | ||
453 | #[prelude_import] | ||
454 | pub use self::prelude::*; | ||
455 | mod prelude { | ||
456 | pub struct Foo; | ||
457 | pub use core::prelude::Bar; | ||
458 | } | ||
459 | |||
460 | //- /core.rs crate:core | ||
461 | #[prelude_import] | ||
462 | pub use self::prelude::*; | ||
463 | mod prelude { | ||
464 | pub struct Bar; | ||
465 | } | ||
466 | "#, | ||
467 | expect![[r#" | ||
468 | crate | ||
469 | Bar: t v | ||
470 | Foo: t v | ||
471 | "#]], | ||
472 | ); | ||
473 | } | ||
474 | |||
475 | #[test] | ||
476 | fn cfg_not_test() { | ||
477 | check( | ||
478 | r#" | ||
479 | //- /main.rs crate:main deps:std | ||
480 | use {Foo, Bar, Baz}; | ||
481 | |||
482 | //- /lib.rs crate:std | ||
483 | #[prelude_import] | ||
484 | pub use self::prelude::*; | ||
485 | mod prelude { | ||
486 | #[cfg(test)] | ||
487 | pub struct Foo; | ||
488 | #[cfg(not(test))] | ||
489 | pub struct Bar; | ||
490 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | ||
491 | pub struct Baz; | ||
492 | } | ||
493 | "#, | ||
494 | expect![[r#" | ||
495 | crate | ||
496 | Bar: t v | ||
497 | Baz: _ | ||
498 | Foo: _ | ||
499 | "#]], | ||
500 | ); | ||
501 | } | ||
502 | |||
503 | #[test] | ||
504 | fn cfg_test() { | ||
505 | check( | ||
506 | r#" | ||
507 | //- /main.rs crate:main deps:std | ||
508 | use {Foo, Bar, Baz}; | ||
509 | |||
510 | //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 | ||
511 | #[prelude_import] | ||
512 | pub use self::prelude::*; | ||
513 | mod prelude { | ||
514 | #[cfg(test)] | ||
515 | pub struct Foo; | ||
516 | #[cfg(not(test))] | ||
517 | pub struct Bar; | ||
518 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | ||
519 | pub struct Baz; | ||
520 | } | ||
521 | "#, | ||
522 | expect![[r#" | ||
523 | crate | ||
524 | Bar: _ | ||
525 | Baz: t v | ||
526 | Foo: t v | ||
527 | "#]], | ||
528 | ); | ||
529 | } | ||
530 | |||
531 | #[test] | ||
532 | fn infer_multiple_namespace() { | ||
533 | check( | ||
534 | r#" | ||
535 | //- /main.rs | ||
536 | mod a { | ||
537 | pub type T = (); | ||
538 | pub use crate::b::*; | ||
539 | } | ||
540 | |||
541 | use crate::a::T; | ||
542 | |||
543 | mod b { | ||
544 | pub const T: () = (); | ||
545 | } | ||
546 | "#, | ||
547 | expect![[r#" | ||
548 | crate | ||
549 | T: t v | ||
550 | a: t | ||
551 | b: t | ||
552 | |||
553 | crate::b | ||
554 | T: v | ||
555 | |||
556 | crate::a | ||
557 | T: t v | ||
558 | "#]], | ||
559 | ); | ||
560 | } | ||
561 | |||
562 | #[test] | ||
563 | fn underscore_import() { | ||
564 | check( | ||
565 | r#" | ||
566 | //- /main.rs | ||
567 | use tr::Tr as _; | ||
568 | use tr::Tr2 as _; | ||
569 | |||
570 | mod tr { | ||
571 | pub trait Tr {} | ||
572 | pub trait Tr2 {} | ||
573 | } | ||
574 | "#, | ||
575 | expect![[r#" | ||
576 | crate | ||
577 | _: t | ||
578 | _: t | ||
579 | tr: t | ||
580 | |||
581 | crate::tr | ||
582 | Tr: t | ||
583 | Tr2: t | ||
584 | "#]], | ||
585 | ); | ||
586 | } | ||
587 | |||
588 | #[test] | ||
589 | fn underscore_reexport() { | ||
590 | check( | ||
591 | r#" | ||
592 | //- /main.rs | ||
593 | mod tr { | ||
594 | pub trait PubTr {} | ||
595 | pub trait PrivTr {} | ||
596 | } | ||
597 | mod reex { | ||
598 | use crate::tr::PrivTr as _; | ||
599 | pub use crate::tr::PubTr as _; | ||
600 | } | ||
601 | use crate::reex::*; | ||
602 | "#, | ||
603 | expect![[r#" | ||
604 | crate | ||
605 | _: t | ||
606 | reex: t | ||
607 | tr: t | ||
608 | |||
609 | crate::tr | ||
610 | PrivTr: t | ||
611 | PubTr: t | ||
612 | |||
613 | crate::reex | ||
614 | _: t | ||
615 | _: t | ||
616 | "#]], | ||
617 | ); | ||
618 | } | ||
619 | |||
620 | #[test] | ||
621 | fn underscore_pub_crate_reexport() { | ||
622 | mark::check!(upgrade_underscore_visibility); | ||
623 | check( | ||
624 | r#" | ||
625 | //- /main.rs crate:main deps:lib | ||
626 | use lib::*; | ||
627 | |||
628 | //- /lib.rs crate:lib | ||
629 | use tr::Tr as _; | ||
630 | pub use tr::Tr as _; | ||
631 | |||
632 | mod tr { | ||
633 | pub trait Tr {} | ||
634 | } | ||
635 | "#, | ||
636 | expect![[r#" | ||
637 | crate | ||
638 | _: t | ||
639 | "#]], | ||
640 | ); | ||
641 | } | ||
642 | |||
643 | #[test] | ||
644 | fn underscore_nontrait() { | ||
645 | check( | ||
646 | r#" | ||
647 | //- /main.rs | ||
648 | mod m { | ||
649 | pub struct Struct; | ||
650 | pub enum Enum {} | ||
651 | pub const CONST: () = (); | ||
652 | } | ||
653 | use crate::m::{Struct as _, Enum as _, CONST as _}; | ||
654 | "#, | ||
655 | expect![[r#" | ||
656 | crate | ||
657 | m: t | ||
658 | |||
659 | crate::m | ||
660 | CONST: v | ||
661 | Enum: t | ||
662 | Struct: t v | ||
663 | "#]], | ||
664 | ); | ||
665 | } | ||
666 | |||
667 | #[test] | ||
668 | fn underscore_name_conflict() { | ||
669 | check( | ||
670 | r#" | ||
671 | //- /main.rs | ||
672 | struct Tr; | ||
673 | |||
674 | use tr::Tr as _; | ||
675 | |||
676 | mod tr { | ||
677 | pub trait Tr {} | ||
678 | } | ||
679 | "#, | ||
680 | expect![[r#" | ||
681 | crate | ||
682 | _: t | ||
683 | Tr: t v | ||
684 | tr: t | ||
685 | |||
686 | crate::tr | ||
687 | Tr: t | ||
688 | "#]], | ||
689 | ); | ||
690 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/globs.rs b/crates/hir_def/src/nameres/tests/globs.rs new file mode 100644 index 000000000..2ae836e3c --- /dev/null +++ b/crates/hir_def/src/nameres/tests/globs.rs | |||
@@ -0,0 +1,338 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn glob_1() { | ||
5 | check( | ||
6 | r#" | ||
7 | //- /lib.rs | ||
8 | mod foo; | ||
9 | use foo::*; | ||
10 | |||
11 | //- /foo/mod.rs | ||
12 | pub mod bar; | ||
13 | pub use self::bar::Baz; | ||
14 | pub struct Foo; | ||
15 | |||
16 | //- /foo/bar.rs | ||
17 | pub struct Baz; | ||
18 | "#, | ||
19 | expect![[r#" | ||
20 | crate | ||
21 | Baz: t v | ||
22 | Foo: t v | ||
23 | bar: t | ||
24 | foo: t | ||
25 | |||
26 | crate::foo | ||
27 | Baz: t v | ||
28 | Foo: t v | ||
29 | bar: t | ||
30 | |||
31 | crate::foo::bar | ||
32 | Baz: t v | ||
33 | "#]], | ||
34 | ); | ||
35 | } | ||
36 | |||
37 | #[test] | ||
38 | fn glob_2() { | ||
39 | check( | ||
40 | r#" | ||
41 | //- /lib.rs | ||
42 | mod foo; | ||
43 | use foo::*; | ||
44 | |||
45 | //- /foo/mod.rs | ||
46 | pub mod bar; | ||
47 | pub use self::bar::*; | ||
48 | pub struct Foo; | ||
49 | |||
50 | //- /foo/bar.rs | ||
51 | pub struct Baz; | ||
52 | pub use super::*; | ||
53 | "#, | ||
54 | expect![[r#" | ||
55 | crate | ||
56 | Baz: t v | ||
57 | Foo: t v | ||
58 | bar: t | ||
59 | foo: t | ||
60 | |||
61 | crate::foo | ||
62 | Baz: t v | ||
63 | Foo: t v | ||
64 | bar: t | ||
65 | |||
66 | crate::foo::bar | ||
67 | Baz: t v | ||
68 | Foo: t v | ||
69 | bar: t | ||
70 | "#]], | ||
71 | ); | ||
72 | } | ||
73 | |||
74 | #[test] | ||
75 | fn glob_privacy_1() { | ||
76 | check( | ||
77 | r" | ||
78 | //- /lib.rs | ||
79 | mod foo; | ||
80 | use foo::*; | ||
81 | |||
82 | //- /foo/mod.rs | ||
83 | pub mod bar; | ||
84 | pub use self::bar::*; | ||
85 | struct PrivateStructFoo; | ||
86 | |||
87 | //- /foo/bar.rs | ||
88 | pub struct Baz; | ||
89 | struct PrivateStructBar; | ||
90 | pub use super::*; | ||
91 | ", | ||
92 | expect![[r#" | ||
93 | crate | ||
94 | Baz: t v | ||
95 | bar: t | ||
96 | foo: t | ||
97 | |||
98 | crate::foo | ||
99 | Baz: t v | ||
100 | PrivateStructFoo: t v | ||
101 | bar: t | ||
102 | |||
103 | crate::foo::bar | ||
104 | Baz: t v | ||
105 | PrivateStructBar: t v | ||
106 | PrivateStructFoo: t v | ||
107 | bar: t | ||
108 | "#]], | ||
109 | ); | ||
110 | } | ||
111 | |||
112 | #[test] | ||
113 | fn glob_privacy_2() { | ||
114 | check( | ||
115 | r" | ||
116 | //- /lib.rs | ||
117 | mod foo; | ||
118 | use foo::*; | ||
119 | use foo::bar::*; | ||
120 | |||
121 | //- /foo/mod.rs | ||
122 | mod bar; | ||
123 | fn Foo() {}; | ||
124 | pub struct Foo {}; | ||
125 | |||
126 | //- /foo/bar.rs | ||
127 | pub(super) struct PrivateBaz; | ||
128 | struct PrivateBar; | ||
129 | pub(crate) struct PubCrateStruct; | ||
130 | ", | ||
131 | expect![[r#" | ||
132 | crate | ||
133 | Foo: t | ||
134 | PubCrateStruct: t v | ||
135 | foo: t | ||
136 | |||
137 | crate::foo | ||
138 | Foo: t v | ||
139 | bar: t | ||
140 | |||
141 | crate::foo::bar | ||
142 | PrivateBar: t v | ||
143 | PrivateBaz: t v | ||
144 | PubCrateStruct: t v | ||
145 | "#]], | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | #[test] | ||
150 | fn glob_across_crates() { | ||
151 | mark::check!(glob_across_crates); | ||
152 | check( | ||
153 | r#" | ||
154 | //- /main.rs crate:main deps:test_crate | ||
155 | use test_crate::*; | ||
156 | |||
157 | //- /lib.rs crate:test_crate | ||
158 | pub struct Baz; | ||
159 | "#, | ||
160 | expect![[r#" | ||
161 | crate | ||
162 | Baz: t v | ||
163 | "#]], | ||
164 | ); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn glob_privacy_across_crates() { | ||
169 | check( | ||
170 | r#" | ||
171 | //- /main.rs crate:main deps:test_crate | ||
172 | use test_crate::*; | ||
173 | |||
174 | //- /lib.rs crate:test_crate | ||
175 | pub struct Baz; | ||
176 | struct Foo; | ||
177 | "#, | ||
178 | expect![[r#" | ||
179 | crate | ||
180 | Baz: t v | ||
181 | "#]], | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn glob_enum() { | ||
187 | mark::check!(glob_enum); | ||
188 | check( | ||
189 | r#" | ||
190 | enum Foo { Bar, Baz } | ||
191 | use self::Foo::*; | ||
192 | "#, | ||
193 | expect![[r#" | ||
194 | crate | ||
195 | Bar: t v | ||
196 | Baz: t v | ||
197 | Foo: t | ||
198 | "#]], | ||
199 | ); | ||
200 | } | ||
201 | |||
202 | #[test] | ||
203 | fn glob_enum_group() { | ||
204 | mark::check!(glob_enum_group); | ||
205 | check( | ||
206 | r#" | ||
207 | enum Foo { Bar, Baz } | ||
208 | use self::Foo::{*}; | ||
209 | "#, | ||
210 | expect![[r#" | ||
211 | crate | ||
212 | Bar: t v | ||
213 | Baz: t v | ||
214 | Foo: t | ||
215 | "#]], | ||
216 | ); | ||
217 | } | ||
218 | |||
219 | #[test] | ||
220 | fn glob_shadowed_def() { | ||
221 | mark::check!(import_shadowed); | ||
222 | check( | ||
223 | r#" | ||
224 | //- /lib.rs | ||
225 | mod foo; | ||
226 | mod bar; | ||
227 | use foo::*; | ||
228 | use bar::baz; | ||
229 | use baz::Bar; | ||
230 | |||
231 | //- /foo.rs | ||
232 | pub mod baz { pub struct Foo; } | ||
233 | |||
234 | //- /bar.rs | ||
235 | pub mod baz { pub struct Bar; } | ||
236 | "#, | ||
237 | expect![[r#" | ||
238 | crate | ||
239 | Bar: t v | ||
240 | bar: t | ||
241 | baz: t | ||
242 | foo: t | ||
243 | |||
244 | crate::bar | ||
245 | baz: t | ||
246 | |||
247 | crate::bar::baz | ||
248 | Bar: t v | ||
249 | |||
250 | crate::foo | ||
251 | baz: t | ||
252 | |||
253 | crate::foo::baz | ||
254 | Foo: t v | ||
255 | "#]], | ||
256 | ); | ||
257 | } | ||
258 | |||
259 | #[test] | ||
260 | fn glob_shadowed_def_reversed() { | ||
261 | check( | ||
262 | r#" | ||
263 | //- /lib.rs | ||
264 | mod foo; | ||
265 | mod bar; | ||
266 | use bar::baz; | ||
267 | use foo::*; | ||
268 | use baz::Bar; | ||
269 | |||
270 | //- /foo.rs | ||
271 | pub mod baz { pub struct Foo; } | ||
272 | |||
273 | //- /bar.rs | ||
274 | pub mod baz { pub struct Bar; } | ||
275 | "#, | ||
276 | expect![[r#" | ||
277 | crate | ||
278 | Bar: t v | ||
279 | bar: t | ||
280 | baz: t | ||
281 | foo: t | ||
282 | |||
283 | crate::bar | ||
284 | baz: t | ||
285 | |||
286 | crate::bar::baz | ||
287 | Bar: t v | ||
288 | |||
289 | crate::foo | ||
290 | baz: t | ||
291 | |||
292 | crate::foo::baz | ||
293 | Foo: t v | ||
294 | "#]], | ||
295 | ); | ||
296 | } | ||
297 | |||
298 | #[test] | ||
299 | fn glob_shadowed_def_dependencies() { | ||
300 | check( | ||
301 | r#" | ||
302 | mod a { pub mod foo { pub struct X; } } | ||
303 | mod b { pub use super::a::foo; } | ||
304 | mod c { pub mod foo { pub struct Y; } } | ||
305 | mod d { | ||
306 | use super::c::foo; | ||
307 | use super::b::*; | ||
308 | use foo::Y; | ||
309 | } | ||
310 | "#, | ||
311 | expect![[r#" | ||
312 | crate | ||
313 | a: t | ||
314 | b: t | ||
315 | c: t | ||
316 | d: t | ||
317 | |||
318 | crate::d | ||
319 | Y: t v | ||
320 | foo: t | ||
321 | |||
322 | crate::c | ||
323 | foo: t | ||
324 | |||
325 | crate::c::foo | ||
326 | Y: t v | ||
327 | |||
328 | crate::b | ||
329 | foo: t | ||
330 | |||
331 | crate::a | ||
332 | foo: t | ||
333 | |||
334 | crate::a::foo | ||
335 | X: t v | ||
336 | "#]], | ||
337 | ); | ||
338 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs new file mode 100644 index 000000000..cfbc62cc4 --- /dev/null +++ b/crates/hir_def/src/nameres/tests/incremental.rs | |||
@@ -0,0 +1,101 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use base_db::SourceDatabaseExt; | ||
4 | |||
5 | use super::*; | ||
6 | |||
7 | fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) { | ||
8 | let (mut db, pos) = TestDB::with_position(ra_fixture_initial); | ||
9 | let krate = db.test_crate(); | ||
10 | { | ||
11 | let events = db.log_executed(|| { | ||
12 | db.crate_def_map(krate); | ||
13 | }); | ||
14 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | ||
15 | } | ||
16 | db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string())); | ||
17 | |||
18 | { | ||
19 | let events = db.log_executed(|| { | ||
20 | db.crate_def_map(krate); | ||
21 | }); | ||
22 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | #[test] | ||
27 | fn typing_inside_a_function_should_not_invalidate_def_map() { | ||
28 | check_def_map_is_not_recomputed( | ||
29 | r" | ||
30 | //- /lib.rs | ||
31 | mod foo;<|> | ||
32 | |||
33 | use crate::foo::bar::Baz; | ||
34 | |||
35 | enum E { A, B } | ||
36 | use E::*; | ||
37 | |||
38 | fn foo() -> i32 { | ||
39 | 1 + 1 | ||
40 | } | ||
41 | //- /foo/mod.rs | ||
42 | pub mod bar; | ||
43 | |||
44 | //- /foo/bar.rs | ||
45 | pub struct Baz; | ||
46 | ", | ||
47 | r" | ||
48 | mod foo; | ||
49 | |||
50 | use crate::foo::bar::Baz; | ||
51 | |||
52 | enum E { A, B } | ||
53 | use E::*; | ||
54 | |||
55 | fn foo() -> i32 { 92 } | ||
56 | ", | ||
57 | ); | ||
58 | } | ||
59 | |||
60 | #[test] | ||
61 | fn typing_inside_a_macro_should_not_invalidate_def_map() { | ||
62 | let (mut db, pos) = TestDB::with_position( | ||
63 | r" | ||
64 | //- /lib.rs | ||
65 | macro_rules! m { | ||
66 | ($ident:ident) => { | ||
67 | fn f() { | ||
68 | $ident + $ident; | ||
69 | }; | ||
70 | } | ||
71 | } | ||
72 | mod foo; | ||
73 | |||
74 | //- /foo/mod.rs | ||
75 | pub mod bar; | ||
76 | |||
77 | //- /foo/bar.rs | ||
78 | <|> | ||
79 | m!(X); | ||
80 | ", | ||
81 | ); | ||
82 | let krate = db.test_crate(); | ||
83 | { | ||
84 | let events = db.log_executed(|| { | ||
85 | let crate_def_map = db.crate_def_map(krate); | ||
86 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
87 | assert_eq!(module_data.scope.resolutions().count(), 1); | ||
88 | }); | ||
89 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | ||
90 | } | ||
91 | db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string())); | ||
92 | |||
93 | { | ||
94 | let events = db.log_executed(|| { | ||
95 | let crate_def_map = db.crate_def_map(krate); | ||
96 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
97 | assert_eq!(module_data.scope.resolutions().count(), 1); | ||
98 | }); | ||
99 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | ||
100 | } | ||
101 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs new file mode 100644 index 000000000..e0fb8bdef --- /dev/null +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -0,0 +1,669 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn macro_rules_are_globally_visible() { | ||
5 | check( | ||
6 | r#" | ||
7 | //- /lib.rs | ||
8 | macro_rules! structs { | ||
9 | ($($i:ident),*) => { | ||
10 | $(struct $i { field: u32 } )* | ||
11 | } | ||
12 | } | ||
13 | structs!(Foo); | ||
14 | mod nested; | ||
15 | |||
16 | //- /nested.rs | ||
17 | structs!(Bar, Baz); | ||
18 | "#, | ||
19 | expect![[r#" | ||
20 | crate | ||
21 | Foo: t | ||
22 | nested: t | ||
23 | |||
24 | crate::nested | ||
25 | Bar: t | ||
26 | Baz: t | ||
27 | "#]], | ||
28 | ); | ||
29 | } | ||
30 | |||
31 | #[test] | ||
32 | fn macro_rules_can_define_modules() { | ||
33 | check( | ||
34 | r#" | ||
35 | //- /lib.rs | ||
36 | macro_rules! m { | ||
37 | ($name:ident) => { mod $name; } | ||
38 | } | ||
39 | m!(n1); | ||
40 | mod m { m!(n3) } | ||
41 | |||
42 | //- /n1.rs | ||
43 | m!(n2) | ||
44 | //- /n1/n2.rs | ||
45 | struct X; | ||
46 | //- /m/n3.rs | ||
47 | struct Y; | ||
48 | "#, | ||
49 | expect![[r#" | ||
50 | crate | ||
51 | m: t | ||
52 | n1: t | ||
53 | |||
54 | crate::m | ||
55 | n3: t | ||
56 | |||
57 | crate::m::n3 | ||
58 | Y: t v | ||
59 | |||
60 | crate::n1 | ||
61 | n2: t | ||
62 | |||
63 | crate::n1::n2 | ||
64 | X: t v | ||
65 | "#]], | ||
66 | ); | ||
67 | } | ||
68 | |||
69 | #[test] | ||
70 | fn macro_rules_from_other_crates_are_visible() { | ||
71 | check( | ||
72 | r#" | ||
73 | //- /main.rs crate:main deps:foo | ||
74 | foo::structs!(Foo, Bar) | ||
75 | mod bar; | ||
76 | |||
77 | //- /bar.rs | ||
78 | use crate::*; | ||
79 | |||
80 | //- /lib.rs crate:foo | ||
81 | #[macro_export] | ||
82 | macro_rules! structs { | ||
83 | ($($i:ident),*) => { | ||
84 | $(struct $i { field: u32 } )* | ||
85 | } | ||
86 | } | ||
87 | "#, | ||
88 | expect![[r#" | ||
89 | crate | ||
90 | Bar: t | ||
91 | Foo: t | ||
92 | bar: t | ||
93 | |||
94 | crate::bar | ||
95 | Bar: t | ||
96 | Foo: t | ||
97 | bar: t | ||
98 | "#]], | ||
99 | ); | ||
100 | } | ||
101 | |||
102 | #[test] | ||
103 | fn macro_rules_export_with_local_inner_macros_are_visible() { | ||
104 | check( | ||
105 | r#" | ||
106 | //- /main.rs crate:main deps:foo | ||
107 | foo::structs!(Foo, Bar) | ||
108 | mod bar; | ||
109 | |||
110 | //- /bar.rs | ||
111 | use crate::*; | ||
112 | |||
113 | //- /lib.rs crate:foo | ||
114 | #[macro_export(local_inner_macros)] | ||
115 | macro_rules! structs { | ||
116 | ($($i:ident),*) => { | ||
117 | $(struct $i { field: u32 } )* | ||
118 | } | ||
119 | } | ||
120 | "#, | ||
121 | expect![[r#" | ||
122 | crate | ||
123 | Bar: t | ||
124 | Foo: t | ||
125 | bar: t | ||
126 | |||
127 | crate::bar | ||
128 | Bar: t | ||
129 | Foo: t | ||
130 | bar: t | ||
131 | "#]], | ||
132 | ); | ||
133 | } | ||
134 | |||
135 | #[test] | ||
136 | fn local_inner_macros_makes_local_macros_usable() { | ||
137 | check( | ||
138 | r#" | ||
139 | //- /main.rs crate:main deps:foo | ||
140 | foo::structs!(Foo, Bar); | ||
141 | mod bar; | ||
142 | |||
143 | //- /bar.rs | ||
144 | use crate::*; | ||
145 | |||
146 | //- /lib.rs crate:foo | ||
147 | #[macro_export(local_inner_macros)] | ||
148 | macro_rules! structs { | ||
149 | ($($i:ident),*) => { | ||
150 | inner!($($i),*); | ||
151 | } | ||
152 | } | ||
153 | #[macro_export] | ||
154 | macro_rules! inner { | ||
155 | ($($i:ident),*) => { | ||
156 | $(struct $i { field: u32 } )* | ||
157 | } | ||
158 | } | ||
159 | "#, | ||
160 | expect![[r#" | ||
161 | crate | ||
162 | Bar: t | ||
163 | Foo: t | ||
164 | bar: t | ||
165 | |||
166 | crate::bar | ||
167 | Bar: t | ||
168 | Foo: t | ||
169 | bar: t | ||
170 | "#]], | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | ||
176 | check( | ||
177 | r#" | ||
178 | //- /main.rs crate:main deps:foo | ||
179 | macro_rules! baz { | ||
180 | () => { | ||
181 | use foo::bar; | ||
182 | } | ||
183 | } | ||
184 | foo!(); | ||
185 | bar!(); | ||
186 | baz!(); | ||
187 | |||
188 | //- /lib.rs crate:foo | ||
189 | #[macro_export] | ||
190 | macro_rules! foo { | ||
191 | () => { | ||
192 | struct Foo { field: u32 } | ||
193 | } | ||
194 | } | ||
195 | #[macro_export] | ||
196 | macro_rules! bar { | ||
197 | () => { | ||
198 | use foo::foo; | ||
199 | } | ||
200 | } | ||
201 | "#, | ||
202 | expect![[r#" | ||
203 | crate | ||
204 | Foo: t | ||
205 | bar: m | ||
206 | foo: m | ||
207 | "#]], | ||
208 | ); | ||
209 | } | ||
210 | |||
211 | #[test] | ||
212 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | ||
213 | mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
214 | check( | ||
215 | r#" | ||
216 | //- /main.rs crate:main deps:foo | ||
217 | structs!(Foo); | ||
218 | structs_priv!(Bar); | ||
219 | structs_not_exported!(MacroNotResolved1); | ||
220 | crate::structs!(MacroNotResolved2); | ||
221 | |||
222 | mod bar; | ||
223 | |||
224 | #[macro_use] | ||
225 | extern crate foo; | ||
226 | |||
227 | //- /bar.rs | ||
228 | structs!(Baz); | ||
229 | crate::structs!(MacroNotResolved3); | ||
230 | |||
231 | //- /lib.rs crate:foo | ||
232 | #[macro_export] | ||
233 | macro_rules! structs { | ||
234 | ($i:ident) => { struct $i; } | ||
235 | } | ||
236 | |||
237 | macro_rules! structs_not_exported { | ||
238 | ($i:ident) => { struct $i; } | ||
239 | } | ||
240 | |||
241 | mod priv_mod { | ||
242 | #[macro_export] | ||
243 | macro_rules! structs_priv { | ||
244 | ($i:ident) => { struct $i; } | ||
245 | } | ||
246 | } | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | crate | ||
250 | Bar: t v | ||
251 | Foo: t v | ||
252 | bar: t | ||
253 | foo: t | ||
254 | |||
255 | crate::bar | ||
256 | Baz: t v | ||
257 | "#]], | ||
258 | ); | ||
259 | } | ||
260 | |||
261 | #[test] | ||
262 | fn prelude_is_macro_use() { | ||
263 | mark::check!(prelude_is_macro_use); | ||
264 | check( | ||
265 | r#" | ||
266 | //- /main.rs crate:main deps:foo | ||
267 | structs!(Foo); | ||
268 | structs_priv!(Bar); | ||
269 | structs_outside!(Out); | ||
270 | crate::structs!(MacroNotResolved2); | ||
271 | |||
272 | mod bar; | ||
273 | |||
274 | //- /bar.rs | ||
275 | structs!(Baz); | ||
276 | crate::structs!(MacroNotResolved3); | ||
277 | |||
278 | //- /lib.rs crate:foo | ||
279 | #[prelude_import] | ||
280 | use self::prelude::*; | ||
281 | |||
282 | mod prelude { | ||
283 | #[macro_export] | ||
284 | macro_rules! structs { | ||
285 | ($i:ident) => { struct $i; } | ||
286 | } | ||
287 | |||
288 | mod priv_mod { | ||
289 | #[macro_export] | ||
290 | macro_rules! structs_priv { | ||
291 | ($i:ident) => { struct $i; } | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | #[macro_export] | ||
297 | macro_rules! structs_outside { | ||
298 | ($i:ident) => { struct $i; } | ||
299 | } | ||
300 | "#, | ||
301 | expect![[r#" | ||
302 | crate | ||
303 | Bar: t v | ||
304 | Foo: t v | ||
305 | Out: t v | ||
306 | bar: t | ||
307 | |||
308 | crate::bar | ||
309 | Baz: t v | ||
310 | "#]], | ||
311 | ); | ||
312 | } | ||
313 | |||
314 | #[test] | ||
315 | fn prelude_cycle() { | ||
316 | check( | ||
317 | r#" | ||
318 | #[prelude_import] | ||
319 | use self::prelude::*; | ||
320 | |||
321 | declare_mod!(); | ||
322 | |||
323 | mod prelude { | ||
324 | macro_rules! declare_mod { | ||
325 | () => (mod foo {}) | ||
326 | } | ||
327 | } | ||
328 | "#, | ||
329 | expect![[r#" | ||
330 | crate | ||
331 | prelude: t | ||
332 | |||
333 | crate::prelude | ||
334 | "#]], | ||
335 | ); | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn plain_macros_are_legacy_textual_scoped() { | ||
340 | check( | ||
341 | r#" | ||
342 | //- /main.rs | ||
343 | mod m1; | ||
344 | bar!(NotFoundNotMacroUse); | ||
345 | |||
346 | mod m2 { foo!(NotFoundBeforeInside2); } | ||
347 | |||
348 | macro_rules! foo { | ||
349 | ($x:ident) => { struct $x; } | ||
350 | } | ||
351 | foo!(Ok); | ||
352 | |||
353 | mod m3; | ||
354 | foo!(OkShadowStop); | ||
355 | bar!(NotFoundMacroUseStop); | ||
356 | |||
357 | #[macro_use] | ||
358 | mod m5 { | ||
359 | #[macro_use] | ||
360 | mod m6 { | ||
361 | macro_rules! foo { | ||
362 | ($x:ident) => { fn $x() {} } | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | foo!(ok_double_macro_use_shadow); | ||
367 | |||
368 | baz!(NotFoundBefore); | ||
369 | #[macro_use] | ||
370 | mod m7 { | ||
371 | macro_rules! baz { | ||
372 | ($x:ident) => { struct $x; } | ||
373 | } | ||
374 | } | ||
375 | baz!(OkAfter); | ||
376 | |||
377 | //- /m1.rs | ||
378 | foo!(NotFoundBeforeInside1); | ||
379 | macro_rules! bar { | ||
380 | ($x:ident) => { struct $x; } | ||
381 | } | ||
382 | |||
383 | //- /m3/mod.rs | ||
384 | foo!(OkAfterInside); | ||
385 | macro_rules! foo { | ||
386 | ($x:ident) => { fn $x() {} } | ||
387 | } | ||
388 | foo!(ok_shadow); | ||
389 | |||
390 | #[macro_use] | ||
391 | mod m4; | ||
392 | bar!(OkMacroUse); | ||
393 | |||
394 | //- /m3/m4.rs | ||
395 | foo!(ok_shadow_deep); | ||
396 | macro_rules! bar { | ||
397 | ($x:ident) => { struct $x; } | ||
398 | } | ||
399 | "#, | ||
400 | expect![[r#" | ||
401 | crate | ||
402 | Ok: t v | ||
403 | OkAfter: t v | ||
404 | OkShadowStop: t v | ||
405 | m1: t | ||
406 | m2: t | ||
407 | m3: t | ||
408 | m5: t | ||
409 | m7: t | ||
410 | ok_double_macro_use_shadow: v | ||
411 | |||
412 | crate::m7 | ||
413 | |||
414 | crate::m1 | ||
415 | |||
416 | crate::m5 | ||
417 | m6: t | ||
418 | |||
419 | crate::m5::m6 | ||
420 | |||
421 | crate::m2 | ||
422 | |||
423 | crate::m3 | ||
424 | OkAfterInside: t v | ||
425 | OkMacroUse: t v | ||
426 | m4: t | ||
427 | ok_shadow: v | ||
428 | |||
429 | crate::m3::m4 | ||
430 | ok_shadow_deep: v | ||
431 | "#]], | ||
432 | ); | ||
433 | } | ||
434 | |||
435 | #[test] | ||
436 | fn type_value_macro_live_in_different_scopes() { | ||
437 | check( | ||
438 | r#" | ||
439 | #[macro_export] | ||
440 | macro_rules! foo { | ||
441 | ($x:ident) => { type $x = (); } | ||
442 | } | ||
443 | |||
444 | foo!(foo); | ||
445 | use foo as bar; | ||
446 | |||
447 | use self::foo as baz; | ||
448 | fn baz() {} | ||
449 | "#, | ||
450 | expect![[r#" | ||
451 | crate | ||
452 | bar: t m | ||
453 | baz: t v m | ||
454 | foo: t m | ||
455 | "#]], | ||
456 | ); | ||
457 | } | ||
458 | |||
459 | #[test] | ||
460 | fn macro_use_can_be_aliased() { | ||
461 | check( | ||
462 | r#" | ||
463 | //- /main.rs crate:main deps:foo | ||
464 | #[macro_use] | ||
465 | extern crate foo; | ||
466 | |||
467 | foo!(Direct); | ||
468 | bar!(Alias); | ||
469 | |||
470 | //- /lib.rs crate:foo | ||
471 | use crate::foo as bar; | ||
472 | |||
473 | mod m { | ||
474 | #[macro_export] | ||
475 | macro_rules! foo { | ||
476 | ($x:ident) => { struct $x; } | ||
477 | } | ||
478 | } | ||
479 | "#, | ||
480 | expect![[r#" | ||
481 | crate | ||
482 | Alias: t v | ||
483 | Direct: t v | ||
484 | foo: t | ||
485 | "#]], | ||
486 | ); | ||
487 | } | ||
488 | |||
489 | #[test] | ||
490 | fn path_qualified_macros() { | ||
491 | check( | ||
492 | r#" | ||
493 | macro_rules! foo { | ||
494 | ($x:ident) => { struct $x; } | ||
495 | } | ||
496 | |||
497 | crate::foo!(NotResolved); | ||
498 | |||
499 | crate::bar!(OkCrate); | ||
500 | bar!(OkPlain); | ||
501 | alias1!(NotHere); | ||
502 | m::alias1!(OkAliasPlain); | ||
503 | m::alias2!(OkAliasSuper); | ||
504 | m::alias3!(OkAliasCrate); | ||
505 | not_found!(NotFound); | ||
506 | |||
507 | mod m { | ||
508 | #[macro_export] | ||
509 | macro_rules! bar { | ||
510 | ($x:ident) => { struct $x; } | ||
511 | } | ||
512 | pub use bar as alias1; | ||
513 | pub use super::bar as alias2; | ||
514 | pub use crate::bar as alias3; | ||
515 | pub use self::bar as not_found; | ||
516 | } | ||
517 | "#, | ||
518 | expect![[r#" | ||
519 | crate | ||
520 | OkAliasCrate: t v | ||
521 | OkAliasPlain: t v | ||
522 | OkAliasSuper: t v | ||
523 | OkCrate: t v | ||
524 | OkPlain: t v | ||
525 | bar: m | ||
526 | m: t | ||
527 | |||
528 | crate::m | ||
529 | alias1: m | ||
530 | alias2: m | ||
531 | alias3: m | ||
532 | not_found: _ | ||
533 | "#]], | ||
534 | ); | ||
535 | } | ||
536 | |||
537 | #[test] | ||
538 | fn macro_dollar_crate_is_correct_in_item() { | ||
539 | mark::check!(macro_dollar_crate_self); | ||
540 | check( | ||
541 | r#" | ||
542 | //- /main.rs crate:main deps:foo | ||
543 | #[macro_use] | ||
544 | extern crate foo; | ||
545 | |||
546 | #[macro_use] | ||
547 | mod m { | ||
548 | macro_rules! current { | ||
549 | () => { | ||
550 | use $crate::Foo as FooSelf; | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | |||
555 | struct Foo; | ||
556 | |||
557 | current!(); | ||
558 | not_current1!(); | ||
559 | foo::not_current2!(); | ||
560 | |||
561 | //- /lib.rs crate:foo | ||
562 | mod m { | ||
563 | #[macro_export] | ||
564 | macro_rules! not_current1 { | ||
565 | () => { | ||
566 | use $crate::Bar; | ||
567 | } | ||
568 | } | ||
569 | } | ||
570 | |||
571 | #[macro_export] | ||
572 | macro_rules! not_current2 { | ||
573 | () => { | ||
574 | use $crate::Baz; | ||
575 | } | ||
576 | } | ||
577 | |||
578 | struct Bar; | ||
579 | struct Baz; | ||
580 | "#, | ||
581 | expect![[r#" | ||
582 | crate | ||
583 | Bar: t v | ||
584 | Baz: t v | ||
585 | Foo: t v | ||
586 | FooSelf: t v | ||
587 | foo: t | ||
588 | m: t | ||
589 | |||
590 | crate::m | ||
591 | "#]], | ||
592 | ); | ||
593 | } | ||
594 | |||
595 | #[test] | ||
596 | fn macro_dollar_crate_is_correct_in_indirect_deps() { | ||
597 | mark::check!(macro_dollar_crate_other); | ||
598 | // From std | ||
599 | check( | ||
600 | r#" | ||
601 | //- /main.rs crate:main deps:std | ||
602 | foo!(); | ||
603 | |||
604 | //- /std.rs crate:std deps:core | ||
605 | #[prelude_import] | ||
606 | use self::prelude::*; | ||
607 | |||
608 | pub use core::foo; | ||
609 | |||
610 | mod prelude {} | ||
611 | |||
612 | #[macro_use] | ||
613 | mod std_macros; | ||
614 | |||
615 | //- /core.rs crate:core | ||
616 | #[macro_export] | ||
617 | macro_rules! foo { | ||
618 | () => { | ||
619 | use $crate::bar; | ||
620 | } | ||
621 | } | ||
622 | |||
623 | pub struct bar; | ||
624 | "#, | ||
625 | expect![[r#" | ||
626 | crate | ||
627 | bar: t v | ||
628 | "#]], | ||
629 | ); | ||
630 | } | ||
631 | |||
632 | #[test] | ||
633 | fn expand_derive() { | ||
634 | let map = compute_crate_def_map( | ||
635 | " | ||
636 | //- /main.rs | ||
637 | #[derive(Copy, Clone)] | ||
638 | struct Foo; | ||
639 | ", | ||
640 | ); | ||
641 | assert_eq!(map.modules[map.root].scope.impls().len(), 2); | ||
642 | } | ||
643 | |||
644 | #[test] | ||
645 | fn macro_expansion_overflow() { | ||
646 | mark::check!(macro_expansion_overflow); | ||
647 | check( | ||
648 | r#" | ||
649 | macro_rules! a { | ||
650 | ($e:expr; $($t:tt)*) => { | ||
651 | b!($($t)*); | ||
652 | }; | ||
653 | () => {}; | ||
654 | } | ||
655 | |||
656 | macro_rules! b { | ||
657 | (static = $e:expr; $($t:tt)*) => { | ||
658 | a!($e; $($t)*); | ||
659 | }; | ||
660 | () => {}; | ||
661 | } | ||
662 | |||
663 | b! { static = #[] (); } | ||
664 | "#, | ||
665 | expect![[r#" | ||
666 | crate | ||
667 | "#]], | ||
668 | ); | ||
669 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs new file mode 100644 index 000000000..1f619787e --- /dev/null +++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -0,0 +1,796 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn name_res_works_for_broken_modules() { | ||
5 | mark::check!(name_res_works_for_broken_modules); | ||
6 | check( | ||
7 | r" | ||
8 | //- /lib.rs | ||
9 | mod foo // no `;`, no body | ||
10 | use self::foo::Baz; | ||
11 | |||
12 | //- /foo/mod.rs | ||
13 | pub mod bar; | ||
14 | pub use self::bar::Baz; | ||
15 | |||
16 | //- /foo/bar.rs | ||
17 | pub struct Baz; | ||
18 | ", | ||
19 | expect![[r#" | ||
20 | crate | ||
21 | Baz: _ | ||
22 | foo: t | ||
23 | |||
24 | crate::foo | ||
25 | "#]], | ||
26 | ); | ||
27 | } | ||
28 | |||
29 | #[test] | ||
30 | fn nested_module_resolution() { | ||
31 | check( | ||
32 | r#" | ||
33 | //- /lib.rs | ||
34 | mod n1; | ||
35 | |||
36 | //- /n1.rs | ||
37 | mod n2; | ||
38 | |||
39 | //- /n1/n2.rs | ||
40 | struct X; | ||
41 | "#, | ||
42 | expect![[r#" | ||
43 | crate | ||
44 | n1: t | ||
45 | |||
46 | crate::n1 | ||
47 | n2: t | ||
48 | |||
49 | crate::n1::n2 | ||
50 | X: t v | ||
51 | "#]], | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | #[test] | ||
56 | fn nested_module_resolution_2() { | ||
57 | check( | ||
58 | r#" | ||
59 | //- /lib.rs | ||
60 | mod prelude; | ||
61 | mod iter; | ||
62 | |||
63 | //- /prelude.rs | ||
64 | pub use crate::iter::Iterator; | ||
65 | |||
66 | //- /iter.rs | ||
67 | pub use self::traits::Iterator; | ||
68 | mod traits; | ||
69 | |||
70 | //- /iter/traits.rs | ||
71 | pub use self::iterator::Iterator; | ||
72 | mod iterator; | ||
73 | |||
74 | //- /iter/traits/iterator.rs | ||
75 | pub trait Iterator; | ||
76 | "#, | ||
77 | expect![[r#" | ||
78 | crate | ||
79 | iter: t | ||
80 | prelude: t | ||
81 | |||
82 | crate::iter | ||
83 | Iterator: t | ||
84 | traits: t | ||
85 | |||
86 | crate::iter::traits | ||
87 | Iterator: t | ||
88 | iterator: t | ||
89 | |||
90 | crate::iter::traits::iterator | ||
91 | Iterator: t | ||
92 | |||
93 | crate::prelude | ||
94 | Iterator: t | ||
95 | "#]], | ||
96 | ); | ||
97 | } | ||
98 | |||
99 | #[test] | ||
100 | fn module_resolution_works_for_non_standard_filenames() { | ||
101 | check( | ||
102 | r#" | ||
103 | //- /my_library.rs crate:my_library | ||
104 | mod foo; | ||
105 | use self::foo::Bar; | ||
106 | |||
107 | //- /foo/mod.rs | ||
108 | pub struct Bar; | ||
109 | "#, | ||
110 | expect![[r#" | ||
111 | crate | ||
112 | Bar: t v | ||
113 | foo: t | ||
114 | |||
115 | crate::foo | ||
116 | Bar: t v | ||
117 | "#]], | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | #[test] | ||
122 | fn module_resolution_works_for_raw_modules() { | ||
123 | check( | ||
124 | r#" | ||
125 | //- /lib.rs | ||
126 | mod r#async; | ||
127 | use self::r#async::Bar; | ||
128 | |||
129 | //- /async.rs | ||
130 | pub struct Bar; | ||
131 | "#, | ||
132 | expect![[r#" | ||
133 | crate | ||
134 | Bar: t v | ||
135 | async: t | ||
136 | |||
137 | crate::async | ||
138 | Bar: t v | ||
139 | "#]], | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | #[test] | ||
144 | fn module_resolution_decl_path() { | ||
145 | check( | ||
146 | r#" | ||
147 | //- /lib.rs | ||
148 | #[path = "bar/baz/foo.rs"] | ||
149 | mod foo; | ||
150 | use self::foo::Bar; | ||
151 | |||
152 | //- /bar/baz/foo.rs | ||
153 | pub struct Bar; | ||
154 | "#, | ||
155 | expect![[r#" | ||
156 | crate | ||
157 | Bar: t v | ||
158 | foo: t | ||
159 | |||
160 | crate::foo | ||
161 | Bar: t v | ||
162 | "#]], | ||
163 | ); | ||
164 | } | ||
165 | |||
166 | #[test] | ||
167 | fn module_resolution_module_with_path_in_mod_rs() { | ||
168 | check( | ||
169 | r#" | ||
170 | //- /main.rs | ||
171 | mod foo; | ||
172 | |||
173 | //- /foo/mod.rs | ||
174 | #[path = "baz.rs"] | ||
175 | pub mod bar; | ||
176 | use self::bar::Baz; | ||
177 | |||
178 | //- /foo/baz.rs | ||
179 | pub struct Baz; | ||
180 | "#, | ||
181 | expect![[r#" | ||
182 | crate | ||
183 | foo: t | ||
184 | |||
185 | crate::foo | ||
186 | Baz: t v | ||
187 | bar: t | ||
188 | |||
189 | crate::foo::bar | ||
190 | Baz: t v | ||
191 | "#]], | ||
192 | ); | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn module_resolution_module_with_path_non_crate_root() { | ||
197 | check( | ||
198 | r#" | ||
199 | //- /main.rs | ||
200 | mod foo; | ||
201 | |||
202 | //- /foo.rs | ||
203 | #[path = "baz.rs"] | ||
204 | pub mod bar; | ||
205 | use self::bar::Baz; | ||
206 | |||
207 | //- /baz.rs | ||
208 | pub struct Baz; | ||
209 | "#, | ||
210 | expect![[r#" | ||
211 | crate | ||
212 | foo: t | ||
213 | |||
214 | crate::foo | ||
215 | Baz: t v | ||
216 | bar: t | ||
217 | |||
218 | crate::foo::bar | ||
219 | Baz: t v | ||
220 | "#]], | ||
221 | ); | ||
222 | } | ||
223 | |||
224 | #[test] | ||
225 | fn module_resolution_module_decl_path_super() { | ||
226 | check( | ||
227 | r#" | ||
228 | //- /main.rs | ||
229 | #[path = "bar/baz/module.rs"] | ||
230 | mod foo; | ||
231 | pub struct Baz; | ||
232 | |||
233 | //- /bar/baz/module.rs | ||
234 | use super::Baz; | ||
235 | "#, | ||
236 | expect![[r#" | ||
237 | crate | ||
238 | Baz: t v | ||
239 | foo: t | ||
240 | |||
241 | crate::foo | ||
242 | Baz: t v | ||
243 | "#]], | ||
244 | ); | ||
245 | } | ||
246 | |||
247 | #[test] | ||
248 | fn module_resolution_explicit_path_mod_rs() { | ||
249 | check( | ||
250 | r#" | ||
251 | //- /main.rs | ||
252 | #[path = "module/mod.rs"] | ||
253 | mod foo; | ||
254 | |||
255 | //- /module/mod.rs | ||
256 | pub struct Baz; | ||
257 | "#, | ||
258 | expect![[r#" | ||
259 | crate | ||
260 | foo: t | ||
261 | |||
262 | crate::foo | ||
263 | Baz: t v | ||
264 | "#]], | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | #[test] | ||
269 | fn module_resolution_relative_path() { | ||
270 | check( | ||
271 | r#" | ||
272 | //- /main.rs | ||
273 | mod foo; | ||
274 | |||
275 | //- /foo.rs | ||
276 | #[path = "./sub.rs"] | ||
277 | pub mod foo_bar; | ||
278 | |||
279 | //- /sub.rs | ||
280 | pub struct Baz; | ||
281 | "#, | ||
282 | expect![[r#" | ||
283 | crate | ||
284 | foo: t | ||
285 | |||
286 | crate::foo | ||
287 | foo_bar: t | ||
288 | |||
289 | crate::foo::foo_bar | ||
290 | Baz: t v | ||
291 | "#]], | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn module_resolution_relative_path_2() { | ||
297 | check( | ||
298 | r#" | ||
299 | //- /main.rs | ||
300 | mod foo; | ||
301 | |||
302 | //- /foo/mod.rs | ||
303 | #[path="../sub.rs"] | ||
304 | pub mod foo_bar; | ||
305 | |||
306 | //- /sub.rs | ||
307 | pub struct Baz; | ||
308 | "#, | ||
309 | expect![[r#" | ||
310 | crate | ||
311 | foo: t | ||
312 | |||
313 | crate::foo | ||
314 | foo_bar: t | ||
315 | |||
316 | crate::foo::foo_bar | ||
317 | Baz: t v | ||
318 | "#]], | ||
319 | ); | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn module_resolution_relative_path_outside_root() { | ||
324 | check( | ||
325 | r#" | ||
326 | //- /main.rs | ||
327 | #[path="../../../../../outside.rs"] | ||
328 | mod foo; | ||
329 | "#, | ||
330 | expect![[r#" | ||
331 | crate | ||
332 | "#]], | ||
333 | ); | ||
334 | } | ||
335 | |||
336 | #[test] | ||
337 | fn module_resolution_explicit_path_mod_rs_2() { | ||
338 | check( | ||
339 | r#" | ||
340 | //- /main.rs | ||
341 | #[path = "module/bar/mod.rs"] | ||
342 | mod foo; | ||
343 | |||
344 | //- /module/bar/mod.rs | ||
345 | pub struct Baz; | ||
346 | "#, | ||
347 | expect![[r#" | ||
348 | crate | ||
349 | foo: t | ||
350 | |||
351 | crate::foo | ||
352 | Baz: t v | ||
353 | "#]], | ||
354 | ); | ||
355 | } | ||
356 | |||
357 | #[test] | ||
358 | fn module_resolution_explicit_path_mod_rs_with_win_separator() { | ||
359 | check( | ||
360 | r#" | ||
361 | //- /main.rs | ||
362 | #[path = "module\bar\mod.rs"] | ||
363 | mod foo; | ||
364 | |||
365 | //- /module/bar/mod.rs | ||
366 | pub struct Baz; | ||
367 | "#, | ||
368 | expect![[r#" | ||
369 | crate | ||
370 | foo: t | ||
371 | |||
372 | crate::foo | ||
373 | Baz: t v | ||
374 | "#]], | ||
375 | ); | ||
376 | } | ||
377 | |||
378 | #[test] | ||
379 | fn module_resolution_decl_inside_inline_module_with_path_attribute() { | ||
380 | check( | ||
381 | r#" | ||
382 | //- /main.rs | ||
383 | #[path = "models"] | ||
384 | mod foo { mod bar; } | ||
385 | |||
386 | //- /models/bar.rs | ||
387 | pub struct Baz; | ||
388 | "#, | ||
389 | expect![[r#" | ||
390 | crate | ||
391 | foo: t | ||
392 | |||
393 | crate::foo | ||
394 | bar: t | ||
395 | |||
396 | crate::foo::bar | ||
397 | Baz: t v | ||
398 | "#]], | ||
399 | ); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn module_resolution_decl_inside_inline_module() { | ||
404 | check( | ||
405 | r#" | ||
406 | //- /main.rs | ||
407 | mod foo { mod bar; } | ||
408 | |||
409 | //- /foo/bar.rs | ||
410 | pub struct Baz; | ||
411 | "#, | ||
412 | expect![[r#" | ||
413 | crate | ||
414 | foo: t | ||
415 | |||
416 | crate::foo | ||
417 | bar: t | ||
418 | |||
419 | crate::foo::bar | ||
420 | Baz: t v | ||
421 | "#]], | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
426 | fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { | ||
427 | check( | ||
428 | r#" | ||
429 | //- /main.rs | ||
430 | #[path = "models/db"] | ||
431 | mod foo { mod bar; } | ||
432 | |||
433 | //- /models/db/bar.rs | ||
434 | pub struct Baz; | ||
435 | "#, | ||
436 | expect![[r#" | ||
437 | crate | ||
438 | foo: t | ||
439 | |||
440 | crate::foo | ||
441 | bar: t | ||
442 | |||
443 | crate::foo::bar | ||
444 | Baz: t v | ||
445 | "#]], | ||
446 | ); | ||
447 | } | ||
448 | |||
449 | #[test] | ||
450 | fn module_resolution_decl_inside_inline_module_3() { | ||
451 | check( | ||
452 | r#" | ||
453 | //- /main.rs | ||
454 | #[path = "models/db"] | ||
455 | mod foo { | ||
456 | #[path = "users.rs"] | ||
457 | mod bar; | ||
458 | } | ||
459 | |||
460 | //- /models/db/users.rs | ||
461 | pub struct Baz; | ||
462 | "#, | ||
463 | expect![[r#" | ||
464 | crate | ||
465 | foo: t | ||
466 | |||
467 | crate::foo | ||
468 | bar: t | ||
469 | |||
470 | crate::foo::bar | ||
471 | Baz: t v | ||
472 | "#]], | ||
473 | ); | ||
474 | } | ||
475 | |||
476 | #[test] | ||
477 | fn module_resolution_decl_inside_inline_module_empty_path() { | ||
478 | check( | ||
479 | r#" | ||
480 | //- /main.rs | ||
481 | #[path = ""] | ||
482 | mod foo { | ||
483 | #[path = "users.rs"] | ||
484 | mod bar; | ||
485 | } | ||
486 | |||
487 | //- /users.rs | ||
488 | pub struct Baz; | ||
489 | "#, | ||
490 | expect![[r#" | ||
491 | crate | ||
492 | foo: t | ||
493 | |||
494 | crate::foo | ||
495 | bar: t | ||
496 | |||
497 | crate::foo::bar | ||
498 | Baz: t v | ||
499 | "#]], | ||
500 | ); | ||
501 | } | ||
502 | |||
503 | #[test] | ||
504 | fn module_resolution_decl_empty_path() { | ||
505 | check( | ||
506 | r#" | ||
507 | //- /main.rs | ||
508 | #[path = ""] // Should try to read `/` (a directory) | ||
509 | mod foo; | ||
510 | |||
511 | //- /foo.rs | ||
512 | pub struct Baz; | ||
513 | "#, | ||
514 | expect![[r#" | ||
515 | crate | ||
516 | "#]], | ||
517 | ); | ||
518 | } | ||
519 | |||
520 | #[test] | ||
521 | fn module_resolution_decl_inside_inline_module_relative_path() { | ||
522 | check( | ||
523 | r#" | ||
524 | //- /main.rs | ||
525 | #[path = "./models"] | ||
526 | mod foo { mod bar; } | ||
527 | |||
528 | //- /models/bar.rs | ||
529 | pub struct Baz; | ||
530 | "#, | ||
531 | expect![[r#" | ||
532 | crate | ||
533 | foo: t | ||
534 | |||
535 | crate::foo | ||
536 | bar: t | ||
537 | |||
538 | crate::foo::bar | ||
539 | Baz: t v | ||
540 | "#]], | ||
541 | ); | ||
542 | } | ||
543 | |||
544 | #[test] | ||
545 | fn module_resolution_decl_inside_inline_module_in_crate_root() { | ||
546 | check( | ||
547 | r#" | ||
548 | //- /main.rs | ||
549 | mod foo { | ||
550 | #[path = "baz.rs"] | ||
551 | mod bar; | ||
552 | } | ||
553 | use self::foo::bar::Baz; | ||
554 | |||
555 | //- /foo/baz.rs | ||
556 | pub struct Baz; | ||
557 | "#, | ||
558 | expect![[r#" | ||
559 | crate | ||
560 | Baz: t v | ||
561 | foo: t | ||
562 | |||
563 | crate::foo | ||
564 | bar: t | ||
565 | |||
566 | crate::foo::bar | ||
567 | Baz: t v | ||
568 | "#]], | ||
569 | ); | ||
570 | } | ||
571 | |||
572 | #[test] | ||
573 | fn module_resolution_decl_inside_inline_module_in_mod_rs() { | ||
574 | check( | ||
575 | r#" | ||
576 | //- /main.rs | ||
577 | mod foo; | ||
578 | |||
579 | //- /foo/mod.rs | ||
580 | mod bar { | ||
581 | #[path = "qwe.rs"] | ||
582 | pub mod baz; | ||
583 | } | ||
584 | use self::bar::baz::Baz; | ||
585 | |||
586 | //- /foo/bar/qwe.rs | ||
587 | pub struct Baz; | ||
588 | "#, | ||
589 | expect![[r#" | ||
590 | crate | ||
591 | foo: t | ||
592 | |||
593 | crate::foo | ||
594 | Baz: t v | ||
595 | bar: t | ||
596 | |||
597 | crate::foo::bar | ||
598 | baz: t | ||
599 | |||
600 | crate::foo::bar::baz | ||
601 | Baz: t v | ||
602 | "#]], | ||
603 | ); | ||
604 | } | ||
605 | |||
606 | #[test] | ||
607 | fn module_resolution_decl_inside_inline_module_in_non_crate_root() { | ||
608 | check( | ||
609 | r#" | ||
610 | //- /main.rs | ||
611 | mod foo; | ||
612 | |||
613 | //- /foo.rs | ||
614 | mod bar { | ||
615 | #[path = "qwe.rs"] | ||
616 | pub mod baz; | ||
617 | } | ||
618 | use self::bar::baz::Baz; | ||
619 | |||
620 | //- /foo/bar/qwe.rs | ||
621 | pub struct Baz; | ||
622 | "#, | ||
623 | expect![[r#" | ||
624 | crate | ||
625 | foo: t | ||
626 | |||
627 | crate::foo | ||
628 | Baz: t v | ||
629 | bar: t | ||
630 | |||
631 | crate::foo::bar | ||
632 | baz: t | ||
633 | |||
634 | crate::foo::bar::baz | ||
635 | Baz: t v | ||
636 | "#]], | ||
637 | ); | ||
638 | } | ||
639 | |||
640 | #[test] | ||
641 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { | ||
642 | check( | ||
643 | r#" | ||
644 | //- /main.rs | ||
645 | mod foo; | ||
646 | |||
647 | //- /foo.rs | ||
648 | #[path = "bar"] | ||
649 | mod bar { | ||
650 | pub mod baz; | ||
651 | } | ||
652 | use self::bar::baz::Baz; | ||
653 | |||
654 | //- /bar/baz.rs | ||
655 | pub struct Baz; | ||
656 | "#, | ||
657 | expect![[r#" | ||
658 | crate | ||
659 | foo: t | ||
660 | |||
661 | crate::foo | ||
662 | Baz: t v | ||
663 | bar: t | ||
664 | |||
665 | crate::foo::bar | ||
666 | baz: t | ||
667 | |||
668 | crate::foo::bar::baz | ||
669 | Baz: t v | ||
670 | "#]], | ||
671 | ); | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn unresolved_module_diagnostics() { | ||
676 | let db = TestDB::with_files( | ||
677 | r" | ||
678 | //- /lib.rs | ||
679 | mod foo; | ||
680 | mod bar; | ||
681 | mod baz {} | ||
682 | //- /foo.rs | ||
683 | ", | ||
684 | ); | ||
685 | let krate = db.test_crate(); | ||
686 | |||
687 | let crate_def_map = db.crate_def_map(krate); | ||
688 | |||
689 | expect![[r#" | ||
690 | [ | ||
691 | UnresolvedModule { | ||
692 | module: Idx::<ModuleData>(0), | ||
693 | declaration: InFile { | ||
694 | file_id: HirFileId( | ||
695 | FileId( | ||
696 | FileId( | ||
697 | 0, | ||
698 | ), | ||
699 | ), | ||
700 | ), | ||
701 | value: FileAstId::<syntax::ast::generated::nodes::Module>(1), | ||
702 | }, | ||
703 | candidate: "bar.rs", | ||
704 | }, | ||
705 | ] | ||
706 | "#]] | ||
707 | .assert_debug_eq(&crate_def_map.diagnostics); | ||
708 | } | ||
709 | |||
710 | #[test] | ||
711 | fn module_resolution_decl_inside_module_in_non_crate_root_2() { | ||
712 | check( | ||
713 | r#" | ||
714 | //- /main.rs | ||
715 | #[path="module/m2.rs"] | ||
716 | mod module; | ||
717 | |||
718 | //- /module/m2.rs | ||
719 | pub mod submod; | ||
720 | |||
721 | //- /module/submod.rs | ||
722 | pub struct Baz; | ||
723 | "#, | ||
724 | expect![[r#" | ||
725 | crate | ||
726 | module: t | ||
727 | |||
728 | crate::module | ||
729 | submod: t | ||
730 | |||
731 | crate::module::submod | ||
732 | Baz: t v | ||
733 | "#]], | ||
734 | ); | ||
735 | } | ||
736 | |||
737 | #[test] | ||
738 | fn nested_out_of_line_module() { | ||
739 | check( | ||
740 | r#" | ||
741 | //- /lib.rs | ||
742 | mod a { | ||
743 | mod b { | ||
744 | mod c; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | //- /a/b/c.rs | ||
749 | struct X; | ||
750 | "#, | ||
751 | expect![[r#" | ||
752 | crate | ||
753 | a: t | ||
754 | |||
755 | crate::a | ||
756 | b: t | ||
757 | |||
758 | crate::a::b | ||
759 | c: t | ||
760 | |||
761 | crate::a::b::c | ||
762 | X: t v | ||
763 | "#]], | ||
764 | ); | ||
765 | } | ||
766 | |||
767 | #[test] | ||
768 | fn nested_out_of_line_module_with_path() { | ||
769 | check( | ||
770 | r#" | ||
771 | //- /lib.rs | ||
772 | mod a { | ||
773 | #[path = "d/e"] | ||
774 | mod b { | ||
775 | mod c; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | //- /a/d/e/c.rs | ||
780 | struct X; | ||
781 | "#, | ||
782 | expect![[r#" | ||
783 | crate | ||
784 | a: t | ||
785 | |||
786 | crate::a | ||
787 | b: t | ||
788 | |||
789 | crate::a::b | ||
790 | c: t | ||
791 | |||
792 | crate::a::b::c | ||
793 | X: t v | ||
794 | "#]], | ||
795 | ); | ||
796 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/primitives.rs b/crates/hir_def/src/nameres/tests/primitives.rs new file mode 100644 index 000000000..215e8952d --- /dev/null +++ b/crates/hir_def/src/nameres/tests/primitives.rs | |||
@@ -0,0 +1,23 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn primitive_reexport() { | ||
5 | check( | ||
6 | r#" | ||
7 | //- /lib.rs | ||
8 | mod foo; | ||
9 | use foo::int; | ||
10 | |||
11 | //- /foo.rs | ||
12 | pub use i32 as int; | ||
13 | "#, | ||
14 | expect![[r#" | ||
15 | crate | ||
16 | foo: t | ||
17 | int: t | ||
18 | |||
19 | crate::foo | ||
20 | int: t | ||
21 | "#]], | ||
22 | ); | ||
23 | } | ||