aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/code_model_api.rs9
-rw-r--r--crates/ra_hir/src/nameres.rs68
-rw-r--r--crates/ra_hir/src/nameres/tests.rs45
3 files changed, 114 insertions, 8 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 2ac05c836..fb7ad0867 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use ra_db::{CrateId, FileId, SourceRootId}; 4use ra_db::{CrateId, FileId, SourceRootId, Edition};
5use ra_syntax::{ast::self, TreeArc, SyntaxNode}; 5use ra_syntax::{ast::self, TreeArc, SyntaxNode};
6 6
7use crate::{ 7use crate::{
@@ -38,13 +38,20 @@ impl Crate {
38 pub fn crate_id(&self) -> CrateId { 38 pub fn crate_id(&self) -> CrateId {
39 self.crate_id 39 self.crate_id
40 } 40 }
41
41 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> { 42 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> {
42 self.dependencies_impl(db) 43 self.dependencies_impl(db)
43 } 44 }
45
44 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 46 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
45 self.root_module_impl(db) 47 self.root_module_impl(db)
46 } 48 }
47 49
50 pub fn edition(&self, db: &impl PersistentHirDatabase) -> Edition {
51 let crate_graph = db.crate_graph();
52 crate_graph.edition(self.crate_id)
53 }
54
48 // TODO: should this be in source_binder? 55 // TODO: should this be in source_binder?
49 pub fn source_root_crates( 56 pub fn source_root_crates(
50 db: &impl PersistentHirDatabase, 57 db: &impl PersistentHirDatabase,
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 2ba6038c6..028e2bee3 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -18,9 +18,11 @@ pub(crate) mod lower;
18 18
19use std::{time, sync::Arc}; 19use std::{time, sync::Arc};
20 20
21use rustc_hash::{FxHashMap, FxHashSet};
22
21use ra_arena::map::ArenaMap; 23use ra_arena::map::ArenaMap;
24use ra_db::Edition;
22use test_utils::tested_by; 25use test_utils::tested_by;
23use rustc_hash::{FxHashMap, FxHashSet};
24 26
25use crate::{ 27use crate::{
26 Module, ModuleDef, 28 Module, ModuleDef,
@@ -32,8 +34,9 @@ use crate::{
32 34
33/// `ItemMap` is the result of module name resolution. It contains, for each 35/// `ItemMap` is the result of module name resolution. It contains, for each
34/// module, the set of visible items. 36/// module, the set of visible items.
35#[derive(Default, Debug, PartialEq, Eq)] 37#[derive(Debug, PartialEq, Eq)]
36pub struct ItemMap { 38pub struct ItemMap {
39 edition: Edition,
37 /// The prelude module for this crate. This either comes from an import 40 /// The prelude module for this crate. This either comes from an import
38 /// marked with the `prelude_import` attribute, or (in the normal case) from 41 /// marked with the `prelude_import` attribute, or (in the normal case) from
39 /// a dependency (`std` or `core`). 42 /// a dependency (`std` or `core`).
@@ -180,7 +183,12 @@ where
180 module_tree, 183 module_tree,
181 processed_imports: FxHashSet::default(), 184 processed_imports: FxHashSet::default(),
182 glob_imports: FxHashMap::default(), 185 glob_imports: FxHashMap::default(),
183 result: ItemMap::default(), 186 result: ItemMap {
187 edition: krate.edition(db),
188 prelude: None,
189 extern_prelude: FxHashMap::default(),
190 per_module: ArenaMap::default(),
191 },
184 } 192 }
185 } 193 }
186 194
@@ -277,10 +285,14 @@ where
277 import_id: ImportId, 285 import_id: ImportId,
278 import: &ImportData, 286 import: &ImportData,
279 ) -> ReachedFixedPoint { 287 ) -> ReachedFixedPoint {
280 log::debug!("resolving import: {:?}", import); 288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
281 let original_module = Module { krate: self.krate, module_id }; 289 let original_module = Module { krate: self.krate, module_id };
282 let (def, reached_fixedpoint) = 290 let (def, reached_fixedpoint) = self.result.resolve_path_fp(
283 self.result.resolve_path_fp(self.db, original_module, &import.path); 291 self.db,
292 ResolveMode::Import,
293 original_module,
294 &import.path,
295 );
284 296
285 if reached_fixedpoint != ReachedFixedPoint::Yes { 297 if reached_fixedpoint != ReachedFixedPoint::Yes {
286 return reached_fixedpoint; 298 return reached_fixedpoint;
@@ -418,6 +430,12 @@ where
418} 430}
419 431
420#[derive(Debug, Clone, Copy, PartialEq, Eq)] 432#[derive(Debug, Clone, Copy, PartialEq, Eq)]
433enum ResolveMode {
434 Import,
435 Other,
436}
437
438#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421enum ReachedFixedPoint { 439enum ReachedFixedPoint {
422 Yes, 440 Yes,
423 No, 441 No,
@@ -445,7 +463,7 @@ impl ItemMap {
445 original_module: Module, 463 original_module: Module,
446 path: &Path, 464 path: &Path,
447 ) -> PerNs<ModuleDef> { 465 ) -> PerNs<ModuleDef> {
448 self.resolve_path_fp(db, original_module, path).0 466 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0
449 } 467 }
450 468
451 fn resolve_in_prelude( 469 fn resolve_in_prelude(
@@ -484,11 +502,27 @@ impl ItemMap {
484 from_scope.or(from_extern_prelude).or(from_prelude) 502 from_scope.or(from_extern_prelude).or(from_prelude)
485 } 503 }
486 504
505 fn resolve_name_in_crate_root_or_extern_prelude(
506 &self,
507 db: &impl PersistentHirDatabase,
508 module: Module,
509 name: &Name,
510 ) -> PerNs<ModuleDef> {
511 let crate_root = module.crate_root(db);
512 let from_crate_root =
513 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
514 let from_extern_prelude =
515 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
516
517 from_crate_root.or(from_extern_prelude)
518 }
519
487 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 520 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
488 // the result. 521 // the result.
489 fn resolve_path_fp( 522 fn resolve_path_fp(
490 &self, 523 &self,
491 db: &impl PersistentHirDatabase, 524 db: &impl PersistentHirDatabase,
525 mode: ResolveMode,
492 original_module: Module, 526 original_module: Module,
493 path: &Path, 527 path: &Path,
494 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 528 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
@@ -496,11 +530,31 @@ impl ItemMap {
496 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 530 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
497 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 531 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
498 PathKind::Self_ => PerNs::types(original_module.into()), 532 PathKind::Self_ => PerNs::types(original_module.into()),
533 // plain import or absolute path in 2015: crate-relative with
534 // fallback to extern prelude (with the simplification in
535 // rust-lang/rust#57745)
536 // TODO there must be a nicer way to write this condition
537 PathKind::Plain | PathKind::Abs
538 if self.edition == Edition::Edition2015
539 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
540 {
541 let segment = match segments.next() {
542 Some((_, segment)) => segment,
543 None => return (PerNs::none(), ReachedFixedPoint::Yes),
544 };
545 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
546 self.resolve_name_in_crate_root_or_extern_prelude(
547 db,
548 original_module,
549 &segment.name,
550 )
551 }
499 PathKind::Plain => { 552 PathKind::Plain => {
500 let segment = match segments.next() { 553 let segment = match segments.next() {
501 Some((_, segment)) => segment, 554 Some((_, segment)) => segment,
502 None => return (PerNs::none(), ReachedFixedPoint::Yes), 555 None => return (PerNs::none(), ReachedFixedPoint::Yes),
503 }; 556 };
557 log::debug!("resolving {:?} in module", segment);
504 self.resolve_name_in_module(db, original_module, &segment.name) 558 self.resolve_name_in_module(db, original_module, &segment.name)
505 } 559 }
506 PathKind::Super => { 560 PathKind::Super => {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 68ebe963a..bee475c3a 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -266,6 +266,51 @@ fn glob_across_crates() {
266} 266}
267 267
268#[test] 268#[test]
269fn edition_2015_imports() {
270 use ra_db::{CrateGraph, Edition};
271 let mut db = MockDatabase::with_files(
272 "
273 //- /main.rs
274 mod foo;
275 mod bar;
276
277 //- /bar.rs
278 struct Bar;
279
280 //- /foo.rs
281 use bar::Bar;
282 use other_crate::FromLib;
283
284 //- /lib.rs
285 struct FromLib;
286 ",
287 );
288 let main_id = db.file_id_of("/main.rs");
289 let lib_id = db.file_id_of("/lib.rs");
290 let foo_id = db.file_id_of("/foo.rs");
291
292 let mut crate_graph = CrateGraph::default();
293 let main_crate = crate_graph.add_crate_root(main_id, Edition::Edition2015);
294 let lib_crate = crate_graph.add_crate_root(lib_id, Edition::Edition2018);
295 crate_graph.add_dep(main_crate, "other_crate".into(), lib_crate).unwrap();
296
297 db.set_crate_graph(Arc::new(crate_graph));
298
299 let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap();
300 let krate = module.krate(&db).unwrap();
301 let item_map = db.item_map(krate);
302
303 check_module_item_map(
304 &item_map,
305 module.module_id,
306 "
307 Bar: t v
308 FromLib: t v
309 ",
310 );
311}
312
313#[test]
269fn module_resolution_works_for_non_standard_filenames() { 314fn module_resolution_works_for_non_standard_filenames() {
270 let mut db = MockDatabase::with_files( 315 let mut db = MockDatabase::with_files(
271 " 316 "