aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres.rs')
-rw-r--r--crates/ra_hir_def/src/nameres.rs247
1 files changed, 6 insertions, 241 deletions
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index fb3ba5305..115b0264c 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -52,6 +52,7 @@ pub mod raw;
52pub mod per_ns; 52pub mod per_ns;
53mod collector; 53mod collector;
54mod mod_resolution; 54mod mod_resolution;
55mod path_resolution;
55 56
56#[cfg(test)] 57#[cfg(test)]
57mod tests; 58mod tests;
@@ -65,14 +66,15 @@ use ra_db::{CrateId, Edition, FileId};
65use ra_prof::profile; 66use ra_prof::profile;
66use ra_syntax::ast; 67use ra_syntax::ast;
67use rustc_hash::{FxHashMap, FxHashSet}; 68use rustc_hash::{FxHashMap, FxHashSet};
68use test_utils::tested_by;
69 69
70use crate::{ 70use crate::{
71 builtin_type::BuiltinType, 71 builtin_type::BuiltinType,
72 db::DefDatabase2, 72 db::DefDatabase2,
73 nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId}, 73 nameres::{
74 path::{Path, PathKind}, 74 diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId,
75 AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId, 75 },
76 path::Path,
77 AstId, CrateModuleId, ModuleDefId, ModuleId, TraitId,
76}; 78};
77 79
78/// Contains all top-level defs from a macro-expanded crate 80/// Contains all top-level defs from a macro-expanded crate
@@ -195,39 +197,6 @@ pub struct Resolution {
195 pub import: Option<ImportId>, 197 pub import: Option<ImportId>,
196} 198}
197 199
198#[derive(Debug, Clone)]
199struct ResolvePathResult {
200 resolved_def: PerNs,
201 segment_index: Option<usize>,
202 reached_fixedpoint: ReachedFixedPoint,
203}
204
205impl ResolvePathResult {
206 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
207 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
208 }
209
210 fn with(
211 resolved_def: PerNs,
212 reached_fixedpoint: ReachedFixedPoint,
213 segment_index: Option<usize>,
214 ) -> ResolvePathResult {
215 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
216 }
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
220enum ResolveMode {
221 Import,
222 Other,
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226enum ReachedFixedPoint {
227 Yes,
228 No,
229}
230
231impl CrateDefMap { 200impl CrateDefMap {
232 pub(crate) fn crate_def_map_query( 201 pub(crate) fn crate_def_map_query(
233 // Note that this doesn't have `+ AstDatabase`! 202 // Note that this doesn't have `+ AstDatabase`!
@@ -290,210 +259,6 @@ impl CrateDefMap {
290 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 259 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
291 (res.resolved_def, res.segment_index) 260 (res.resolved_def, res.segment_index)
292 } 261 }
293
294 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
295 // the result.
296 fn resolve_path_fp_with_macro(
297 &self,
298 db: &impl DefDatabase2,
299 mode: ResolveMode,
300 original_module: CrateModuleId,
301 path: &Path,
302 ) -> ResolvePathResult {
303 let mut segments = path.segments.iter().enumerate();
304 let mut curr_per_ns: PerNs = match path.kind {
305 PathKind::DollarCrate(krate) => {
306 if krate == self.krate {
307 tested_by!(macro_dollar_crate_self);
308 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
309 } else {
310 let def_map = db.crate_def_map(krate);
311 let module = ModuleId { krate, module_id: def_map.root };
312 tested_by!(macro_dollar_crate_other);
313 PerNs::types(module.into())
314 }
315 }
316 PathKind::Crate => {
317 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
318 }
319 PathKind::Self_ => {
320 PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
321 }
322 // plain import or absolute path in 2015: crate-relative with
323 // fallback to extern prelude (with the simplification in
324 // rust-lang/rust#57745)
325 // FIXME there must be a nicer way to write this condition
326 PathKind::Plain | PathKind::Abs
327 if self.edition == Edition::Edition2015
328 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
329 {
330 let segment = match segments.next() {
331 Some((_, segment)) => segment,
332 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
333 };
334 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
335 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
336 }
337 PathKind::Plain => {
338 let segment = match segments.next() {
339 Some((_, segment)) => segment,
340 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
341 };
342 log::debug!("resolving {:?} in module", segment);
343 self.resolve_name_in_module(db, original_module, &segment.name)
344 }
345 PathKind::Super => {
346 if let Some(p) = self.modules[original_module].parent {
347 PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
348 } else {
349 log::debug!("super path in root module");
350 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
351 }
352 }
353 PathKind::Abs => {
354 // 2018-style absolute path -- only extern prelude
355 let segment = match segments.next() {
356 Some((_, segment)) => segment,
357 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
358 };
359 if let Some(def) = self.extern_prelude.get(&segment.name) {
360 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
361 PerNs::types(*def)
362 } else {
363 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
364 }
365 }
366 PathKind::Type(_) => {
367 // This is handled in `infer::infer_path_expr`
368 // The result returned here does not matter
369 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
370 }
371 };
372
373 for (i, segment) in segments {
374 let curr = match curr_per_ns.take_types() {
375 Some(r) => r,
376 None => {
377 // we still have path segments left, but the path so far
378 // didn't resolve in the types namespace => no resolution
379 // (don't break here because `curr_per_ns` might contain
380 // something in the value namespace, and it would be wrong
381 // to return that)
382 return ResolvePathResult::empty(ReachedFixedPoint::No);
383 }
384 };
385 // resolve segment in curr
386
387 curr_per_ns = match curr {
388 ModuleDefId::ModuleId(module) => {
389 if module.krate != self.krate {
390 let path =
391 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
392 log::debug!("resolving {:?} in other crate", path);
393 let defp_map = db.crate_def_map(module.krate);
394 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
395 return ResolvePathResult::with(
396 def,
397 ReachedFixedPoint::Yes,
398 s.map(|s| s + i),
399 );
400 }
401
402 // Since it is a qualified path here, it should not contains legacy macros
403 match self[module.module_id].scope.get(&segment.name) {
404 Some(res) => res.def,
405 _ => {
406 log::debug!("path segment {:?} not found", segment.name);
407 return ResolvePathResult::empty(ReachedFixedPoint::No);
408 }
409 }
410 }
411 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
412 // enum variant
413 tested_by!(can_import_enum_variant);
414 let enum_data = db.enum_data(e);
415 match enum_data.variant(&segment.name) {
416 Some(local_id) => {
417 let variant = EnumVariantId { parent: e, local_id };
418 PerNs::both(variant.into(), variant.into())
419 }
420 None => {
421 return ResolvePathResult::with(
422 PerNs::types(e.into()),
423 ReachedFixedPoint::Yes,
424 Some(i),
425 );
426 }
427 }
428 }
429 s => {
430 // could be an inherent method call in UFCS form
431 // (`Struct::method`), or some other kind of associated item
432 log::debug!(
433 "path segment {:?} resolved to non-module {:?}, but is not last",
434 segment.name,
435 curr,
436 );
437
438 return ResolvePathResult::with(
439 PerNs::types(s),
440 ReachedFixedPoint::Yes,
441 Some(i),
442 );
443 }
444 };
445 }
446 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
447 }
448
449 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
450 let from_crate_root =
451 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
452 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
453
454 from_crate_root.or(from_extern_prelude)
455 }
456
457 fn resolve_name_in_module(
458 &self,
459 db: &impl DefDatabase2,
460 module: CrateModuleId,
461 name: &Name,
462 ) -> PerNs {
463 // Resolve in:
464 // - legacy scope of macro
465 // - current module / scope
466 // - extern prelude
467 // - std prelude
468 let from_legacy_macro =
469 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
470 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
471 let from_extern_prelude =
472 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
473 let from_prelude = self.resolve_in_prelude(db, name);
474
475 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
476 }
477
478 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
479 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
480 }
481
482 fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
483 if let Some(prelude) = self.prelude {
484 let keep;
485 let def_map = if prelude.krate == self.krate {
486 self
487 } else {
488 // Extend lifetime
489 keep = db.crate_def_map(prelude.krate);
490 &keep
491 };
492 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
493 } else {
494 PerNs::none()
495 }
496 }
497} 262}
498 263
499mod diagnostics { 264mod diagnostics {