aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-12-19 09:20:54 +0000
committerAleksey Kladov <[email protected]>2018-12-20 09:15:38 +0000
commit85290bc1342560d5560f0b2151cff1c0c6dac155 (patch)
treee7817987dc9dba9485659b8c2585e3c6315496c9 /crates
parent815a0e577821a3876aa4c79c13200607acadcd2f (diff)
switch analysis to vfs
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/db.rs2
-rw-r--r--crates/ra_analysis/src/imp.rs88
-rw-r--r--crates/ra_analysis/src/lib.rs96
-rw-r--r--crates/ra_analysis/src/mock_analysis.rs8
-rw-r--r--crates/ra_db/src/input.rs22
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_db/src/mock.rs7
-rw-r--r--crates/ra_hir/src/module/imp.rs17
8 files changed, 142 insertions, 100 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 9f39d3a59..b79baf037 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -63,8 +63,6 @@ salsa::database_storage! {
63 fn file_text() for ra_db::FileTextQuery; 63 fn file_text() for ra_db::FileTextQuery;
64 fn file_relative_path() for ra_db::FileRelativePathQuery; 64 fn file_relative_path() for ra_db::FileRelativePathQuery;
65 fn file_source_root() for ra_db::FileSourceRootQuery; 65 fn file_source_root() for ra_db::FileSourceRootQuery;
66 fn source_root_files() for ra_db::SourceRootFilesQuery;
67 fn source_root_file_by_path() for ra_db::SourceRootFileByPathQuery;
68 fn source_root() for ra_db::SourceRootQuery; 66 fn source_root() for ra_db::SourceRootQuery;
69 fn libraries() for ra_db::LibrariesQuery; 67 fn libraries() for ra_db::LibrariesQuery;
70 fn crate_graph() for ra_db::CrateGraphQuery; 68 fn crate_graph() for ra_db::CrateGraphQuery;
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index e2c20b0e3..51bcd5a73 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -12,7 +12,6 @@ use ra_syntax::{
12}; 12};
13use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase}; 13use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase};
14use rayon::prelude::*; 14use rayon::prelude::*;
15use rustc_hash::FxHashSet;
16use salsa::{Database, ParallelDatabase}; 15use salsa::{Database, ParallelDatabase};
17use hir::{ 16use hir::{
18 self, 17 self,
@@ -25,7 +24,7 @@ use crate::{
25 completion::{completions, CompletionItem}, 24 completion::{completions, CompletionItem},
26 db, 25 db,
27 symbol_index::{SymbolIndex, SymbolsDatabase}, 26 symbol_index::{SymbolIndex, SymbolsDatabase},
28 AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, 27 AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId,
29 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, 28 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
30 ReferenceResolution, 29 ReferenceResolution,
31}; 30};
@@ -45,59 +44,22 @@ impl AnalysisHostImpl {
45 log::info!("apply_change {:?}", change); 44 log::info!("apply_change {:?}", change);
46 // self.gc_syntax_trees(); 45 // self.gc_syntax_trees();
47 46
47 for (root_id, root_change) in change.roots_changed {
48 self.apply_root_change(root_id, root_change);
49 }
48 for (file_id, text) in change.files_changed { 50 for (file_id, text) in change.files_changed {
49 self.db 51 self.db
50 .query_mut(ra_db::FileTextQuery) 52 .query_mut(ra_db::FileTextQuery)
51 .set(file_id, Arc::new(text)) 53 .set(file_id, Arc::new(text))
52 } 54 }
53 if !(change.files_added.is_empty() && change.files_removed.is_empty()) {
54 let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
55 for (file_id, text) in change.files_added {
56 self.db
57 .query_mut(ra_db::FileTextQuery)
58 .set(file_id, Arc::new(text));
59 self.db
60 .query_mut(ra_db::FileSourceRootQuery)
61 .set(file_id, ra_db::WORKSPACE);
62 source_root.files.insert(file_id);
63 }
64 for file_id in change.files_removed {
65 self.db
66 .query_mut(ra_db::FileTextQuery)
67 .set(file_id, Arc::new(String::new()));
68 source_root.files.remove(&file_id);
69 }
70 self.db
71 .query_mut(ra_db::SourceRootQuery)
72 .set(WORKSPACE, Arc::new(source_root))
73 }
74 if !change.libraries_added.is_empty() { 55 if !change.libraries_added.is_empty() {
75 let mut libraries = Vec::clone(&self.db.libraries()); 56 let mut libraries = Vec::clone(&self.db.libraries());
76 for library in change.libraries_added { 57 for library in change.libraries_added {
77 let source_root_id = SourceRootId(1 + libraries.len() as u32); 58 libraries.push(library.root_id);
78 libraries.push(source_root_id);
79 let mut files = FxHashSet::default();
80 for (file_id, text) in library.files {
81 files.insert(file_id);
82 log::debug!(
83 "library file: {:?} {:?}",
84 file_id,
85 library.file_resolver.debug_path(file_id)
86 );
87 self.db
88 .query_mut(ra_db::FileSourceRootQuery)
89 .set_constant(file_id, source_root_id);
90 self.db
91 .query_mut(ra_db::FileTextQuery)
92 .set_constant(file_id, Arc::new(text));
93 }
94 let source_root = SourceRoot { files };
95 self.db 59 self.db
96 .query_mut(ra_db::SourceRootQuery) 60 .query_mut(ra_db::SourceRootQuery)
97 .set(source_root_id, Arc::new(source_root)); 61 .set(library.root_id, Default::default());
98 self.db 62 self.apply_root_change(library.root_id, library.root_change);
99 .query_mut(crate::symbol_index::LibrarySymbolsQuery)
100 .set(source_root_id, Arc::new(library.symbol_index));
101 } 63 }
102 self.db 64 self.db
103 .query_mut(ra_db::LibrariesQuery) 65 .query_mut(ra_db::LibrariesQuery)
@@ -110,6 +72,34 @@ impl AnalysisHostImpl {
110 } 72 }
111 } 73 }
112 74
75 fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
76 let mut source_root = SourceRoot::clone(&self.db.source_root(root_id));
77 for add_file in root_change.added {
78 self.db
79 .query_mut(ra_db::FileTextQuery)
80 .set(add_file.file_id, add_file.text);
81 self.db
82 .query_mut(ra_db::FileRelativePathQuery)
83 .set(add_file.file_id, add_file.path.clone());
84 self.db
85 .query_mut(ra_db::FileSourceRootQuery)
86 .set(add_file.file_id, root_id);
87 source_root.files.insert(add_file.path, add_file.file_id);
88 }
89 for remove_file in root_change.removed {
90 self.db
91 .query_mut(ra_db::FileTextQuery)
92 .set(remove_file.file_id, Default::default());
93 self.db
94 .query_mut(ra_db::FileRelativePathQuery)
95 .set(remove_file.file_id, Default::default());
96 source_root.files.remove(&remove_file.path);
97 }
98 self.db
99 .query_mut(ra_db::SourceRootQuery)
100 .set(root_id, Arc::new(source_root));
101 }
102
113 #[allow(unused)] 103 #[allow(unused)]
114 /// Ideally, we should call this function from time to time to collect heavy 104 /// Ideally, we should call this function from time to time to collect heavy
115 /// syntax trees. However, if we actually do that, everything is recomputed 105 /// syntax trees. However, if we actually do that, everything is recomputed
@@ -156,7 +146,13 @@ impl AnalysisImpl {
156 .map(|&lib_id| self.db.library_symbols(lib_id)) 146 .map(|&lib_id| self.db.library_symbols(lib_id))
157 .collect() 147 .collect()
158 } else { 148 } else {
159 let files = &self.db.source_root(WORKSPACE).files; 149 let files: Vec<FileId> = self
150 .db
151 .source_root(WORKSPACE)
152 .files
153 .values()
154 .map(|&it| it)
155 .collect();
160 156
161 /// Need to wrap Snapshot to provide `Clone` impl for `map_with` 157 /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
162 struct Snap(salsa::Snapshot<db::RootDatabase>); 158 struct Snap(salsa::Snapshot<db::RootDatabase>);
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 22fff71ab..bfc4e0f17 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -18,9 +18,9 @@ pub mod mock_analysis;
18 18
19use std::{fmt, sync::Arc}; 19use std::{fmt, sync::Arc};
20 20
21use rustc_hash::FxHashMap;
21use ra_syntax::{SourceFileNode, TextRange, TextUnit}; 22use ra_syntax::{SourceFileNode, TextRange, TextUnit};
22use ra_text_edit::AtomTextEdit; 23use ra_text_edit::AtomTextEdit;
23use ra_db::FileResolverImp;
24use rayon::prelude::*; 24use rayon::prelude::*;
25use relative_path::RelativePathBuf; 25use relative_path::RelativePathBuf;
26 26
@@ -39,28 +39,53 @@ pub use hir::FnSignatureInfo;
39 39
40pub use ra_db::{ 40pub use ra_db::{
41 Canceled, Cancelable, FilePosition, 41 Canceled, Cancelable, FilePosition,
42 CrateGraph, CrateId, FileId, FileResolver 42 CrateGraph, CrateId, SourceRootId, FileId, FileResolver,
43 WORKSPACE
43}; 44};
44 45
45#[derive(Default)] 46#[derive(Default)]
46pub struct AnalysisChange { 47pub struct AnalysisChange {
47 files_added: Vec<(FileId, String)>, 48 roots_changed: FxHashMap<SourceRootId, RootChange>,
48 files_changed: Vec<(FileId, String)>, 49 files_changed: Vec<(FileId, String)>,
49 files_removed: Vec<(FileId)>,
50 libraries_added: Vec<LibraryData>, 50 libraries_added: Vec<LibraryData>,
51 crate_graph: Option<CrateGraph>, 51 crate_graph: Option<CrateGraph>,
52 file_resolver: Option<FileResolverImp>, 52}
53
54#[derive(Default)]
55struct RootChange {
56 added: Vec<AddFile>,
57 removed: Vec<RemoveFile>,
58}
59
60#[derive(Debug)]
61struct AddFile {
62 file_id: FileId,
63 path: RelativePathBuf,
64 text: Arc<String>,
65}
66
67#[derive(Debug)]
68struct RemoveFile {
69 file_id: FileId,
70 path: RelativePathBuf,
53} 71}
54 72
55impl fmt::Debug for AnalysisChange { 73impl fmt::Debug for AnalysisChange {
56 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 74 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
57 fmt.debug_struct("AnalysisChange") 75 fmt.debug_struct("AnalysisChange")
58 .field("files_added", &self.files_added.len()) 76 .field("roots_changed", &self.roots_changed)
59 .field("files_changed", &self.files_changed.len()) 77 .field("files_changed", &self.files_changed.len())
60 .field("files_removed", &self.files_removed.len())
61 .field("libraries_added", &self.libraries_added.len()) 78 .field("libraries_added", &self.libraries_added.len())
62 .field("crate_graph", &self.crate_graph) 79 .field("crate_graph", &self.crate_graph)
63 .field("file_resolver", &self.file_resolver) 80 .finish()
81 }
82}
83
84impl fmt::Debug for RootChange {
85 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
86 fmt.debug_struct("AnalysisChange")
87 .field("added", &self.added.len())
88 .field("removed", &self.removed.len())
64 .finish() 89 .finish()
65 } 90 }
66} 91}
@@ -69,14 +94,34 @@ impl AnalysisChange {
69 pub fn new() -> AnalysisChange { 94 pub fn new() -> AnalysisChange {
70 AnalysisChange::default() 95 AnalysisChange::default()
71 } 96 }
72 pub fn add_file(&mut self, file_id: FileId, text: String) { 97 pub fn add_file(
73 self.files_added.push((file_id, text)) 98 &mut self,
99 root_id: SourceRootId,
100 file_id: FileId,
101 path: RelativePathBuf,
102 text: Arc<String>,
103 ) {
104 let file = AddFile {
105 file_id,
106 path,
107 text,
108 };
109 self.roots_changed
110 .entry(root_id)
111 .or_default()
112 .added
113 .push(file);
74 } 114 }
75 pub fn change_file(&mut self, file_id: FileId, new_text: String) { 115 pub fn change_file(&mut self, file_id: FileId, new_text: String) {
76 self.files_changed.push((file_id, new_text)) 116 self.files_changed.push((file_id, new_text))
77 } 117 }
78 pub fn remove_file(&mut self, file_id: FileId) { 118 pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
79 self.files_removed.push(file_id) 119 let file = RemoveFile { file_id, path };
120 self.roots_changed
121 .entry(root_id)
122 .or_default()
123 .removed
124 .push(file);
80 } 125 }
81 pub fn add_library(&mut self, data: LibraryData) { 126 pub fn add_library(&mut self, data: LibraryData) {
82 self.libraries_added.push(data) 127 self.libraries_added.push(data)
@@ -84,9 +129,6 @@ impl AnalysisChange {
84 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 129 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
85 self.crate_graph = Some(graph); 130 self.crate_graph = Some(graph);
86 } 131 }
87 pub fn set_file_resolver(&mut self, file_resolver: Arc<FileResolver>) {
88 self.file_resolver = Some(FileResolverImp::new(file_resolver));
89 }
90} 132}
91 133
92/// `AnalysisHost` stores the current state of the world. 134/// `AnalysisHost` stores the current state of the world.
@@ -313,20 +355,32 @@ impl Analysis {
313 355
314#[derive(Debug)] 356#[derive(Debug)]
315pub struct LibraryData { 357pub struct LibraryData {
316 files: Vec<(FileId, String)>, 358 root_id: SourceRootId,
317 file_resolver: FileResolverImp, 359 root_change: RootChange,
318 symbol_index: SymbolIndex, 360 symbol_index: SymbolIndex,
319} 361}
320 362
321impl LibraryData { 363impl LibraryData {
322 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData { 364 pub fn prepare(
323 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| { 365 root_id: SourceRootId,
366 files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
367 ) -> LibraryData {
368 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
324 let file = SourceFileNode::parse(text); 369 let file = SourceFileNode::parse(text);
325 (*file_id, file) 370 (*file_id, file)
326 })); 371 }));
372 let mut root_change = RootChange::default();
373 root_change.added = files
374 .into_iter()
375 .map(|(file_id, path, text)| AddFile {
376 file_id,
377 path,
378 text,
379 })
380 .collect();
327 LibraryData { 381 LibraryData {
328 files, 382 root_id,
329 file_resolver: FileResolverImp::new(file_resolver), 383 root_change,
330 symbol_index, 384 symbol_index,
331 } 385 }
332 } 386 }
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs
index 0d9a7a147..691af4a48 100644
--- a/crates/ra_analysis/src/mock_analysis.rs
+++ b/crates/ra_analysis/src/mock_analysis.rs
@@ -4,7 +4,7 @@ use relative_path::{RelativePathBuf};
4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
5use ra_db::mock::FileMap; 5use ra_db::mock::FileMap;
6 6
7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition}; 7use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, WORKSPACE};
8 8
9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 9/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
10/// from a set of in-memory files. 10/// from a set of in-memory files.
@@ -82,10 +82,10 @@ impl MockAnalysis {
82 for (path, contents) in self.files.into_iter() { 82 for (path, contents) in self.files.into_iter() {
83 assert!(path.starts_with('/')); 83 assert!(path.starts_with('/'));
84 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 84 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
85 let file_id = file_map.add(path); 85 let file_id = file_map.add(path.clone());
86 change.add_file(file_id, contents); 86 change.add_file(WORKSPACE, file_id, path, Arc::new(contents));
87 } 87 }
88 change.set_file_resolver(Arc::new(file_map)); 88 // change.set_file_resolver(Arc::new(file_map));
89 host.apply_change(change); 89 host.apply_change(change);
90 host 90 host
91 } 91 }
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 65b674da9..51daa8e86 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -1,10 +1,15 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use rustc_hash::{FxHashSet, FxHashMap}; 3use rustc_hash::{FxHashMap};
4use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
5use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
6use salsa; 6use salsa;
7 7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub struct SourceRootId(pub u32);
10
11pub const WORKSPACE: SourceRootId = SourceRootId(0);
12
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct FileId(pub u32); 14pub struct FileId(pub u32);
10 15
@@ -93,14 +98,6 @@ salsa::query_group! {
93 type FileSourceRootQuery; 98 type FileSourceRootQuery;
94 storage input; 99 storage input;
95 } 100 }
96 fn source_root_files(id: SourceRootId) -> Arc<FxHashSet<FileId>> {
97 type SourceRootFilesQuery;
98 storage input;
99 }
100 fn source_root_file_by_path(id: SourceRootId, path: RelativePathBuf) -> Option<FileId> {
101 type SourceRootFileByPathQuery;
102 storage input;
103 }
104 fn source_root(id: SourceRootId) -> Arc<SourceRoot> { 101 fn source_root(id: SourceRootId) -> Arc<SourceRoot> {
105 type SourceRootQuery; 102 type SourceRootQuery;
106 storage input; 103 storage input;
@@ -116,12 +113,7 @@ salsa::query_group! {
116 } 113 }
117} 114}
118 115
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
120pub struct SourceRootId(pub u32);
121
122#[derive(Default, Clone, Debug, PartialEq, Eq)] 116#[derive(Default, Clone, Debug, PartialEq, Eq)]
123pub struct SourceRoot { 117pub struct SourceRoot {
124 pub files: FxHashSet<FileId>, 118 pub files: FxHashMap<RelativePathBuf, FileId>,
125} 119}
126
127pub const WORKSPACE: SourceRootId = SourceRootId(0);
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 783b7a799..d1db281e6 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -28,7 +28,7 @@ pub use crate::{
28 input::{ 28 input::{
29 FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, WORKSPACE, 29 FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, WORKSPACE,
30 FileTextQuery, FileSourceRootQuery, SourceRootQuery, LibrariesQuery, CrateGraphQuery, 30 FileTextQuery, FileSourceRootQuery, SourceRootQuery, LibrariesQuery, CrateGraphQuery,
31 FileRelativePathQuery, SourceRootFilesQuery, SourceRootFileByPathQuery, 31 FileRelativePathQuery
32 }, 32 },
33 loc2id::{LocationIntener, NumericId}, 33 loc2id::{LocationIntener, NumericId},
34}; 34};
diff --git a/crates/ra_db/src/mock.rs b/crates/ra_db/src/mock.rs
index 14d9e79b5..efe987bdd 100644
--- a/crates/ra_db/src/mock.rs
+++ b/crates/ra_db/src/mock.rs
@@ -1,7 +1,7 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2use relative_path::{RelativePath, RelativePathBuf}; 2use relative_path::{RelativePath, RelativePathBuf};
3 3
4use crate::{FileId, FileResolver, SourceRoot}; 4use crate::{FileId, FileResolver};
5 5
6#[derive(Default, Debug, Clone)] 6#[derive(Default, Debug, Clone)]
7pub struct FileMap(Vec<(FileId, RelativePathBuf)>); 7pub struct FileMap(Vec<(FileId, RelativePathBuf)>);
@@ -13,11 +13,6 @@ impl FileMap {
13 file_id 13 file_id
14 } 14 }
15 15
16 pub fn into_source_root(self) -> SourceRoot {
17 let files = self.files();
18 SourceRoot { files }
19 }
20
21 pub fn files(&self) -> FxHashSet<FileId> { 16 pub fn files(&self) -> FxHashSet<FileId> {
22 self.iter().map(|(id, _)| id).collect() 17 self.iter().map(|(id, _)| id).collect()
23 } 18 }
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
index d04d24a61..f3a346152 100644
--- a/crates/ra_hir/src/module/imp.rs
+++ b/crates/ra_hir/src/module/imp.rs
@@ -4,6 +4,7 @@ use ra_syntax::{
4 ast::{self, NameOwner}, 4 ast::{self, NameOwner},
5 SmolStr, 5 SmolStr,
6}; 6};
7use relative_path::{RelativePathBuf, RelativePath};
7use rustc_hash::{FxHashMap, FxHashSet}; 8use rustc_hash::{FxHashMap, FxHashSet};
8use arrayvec::ArrayVec; 9use arrayvec::ArrayVec;
9use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; 10use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
@@ -65,7 +66,7 @@ fn create_module_tree<'a>(
65 let mut visited = FxHashSet::default(); 66 let mut visited = FxHashSet::default();
66 67
67 let source_root = db.source_root(source_root); 68 let source_root = db.source_root(source_root);
68 for &file_id in source_root.files.iter() { 69 for &file_id in source_root.files.values() {
69 let source = ModuleSource::new_file(file_id); 70 let source = ModuleSource::new_file(file_id);
70 if visited.contains(&source) { 71 if visited.contains(&source) {
71 continue; // TODO: use explicit crate_roots here 72 continue; // TODO: use explicit crate_roots here
@@ -160,7 +161,8 @@ fn resolve_submodule(
160 let file_id = source.file_id(); 161 let file_id = source.file_id();
161 let source_root_id = db.file_source_root(file_id); 162 let source_root_id = db.file_source_root(file_id);
162 let path = db.file_relative_path(file_id); 163 let path = db.file_relative_path(file_id);
163 let dir_path = path.parent().unwrap(); 164 let root = RelativePathBuf::default();
165 let dir_path = path.parent().unwrap_or(&root);
164 let mod_name = path.file_stem().unwrap_or("unknown"); 166 let mod_name = path.file_stem().unwrap_or("unknown");
165 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; 167 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
166 168
@@ -174,14 +176,19 @@ fn resolve_submodule(
174 } else { 176 } else {
175 candidates.push(file_dir_mod.clone()); 177 candidates.push(file_dir_mod.clone());
176 }; 178 };
177 179 let sr = db.source_root(source_root_id);
178 let points_to = candidates 180 let points_to = candidates
179 .into_iter() 181 .into_iter()
180 .filter_map(|path| db.source_root_file_by_path(source_root_id, path)) 182 .filter_map(|path| sr.files.get(&path))
183 .map(|&it| it)
181 .collect::<Vec<_>>(); 184 .collect::<Vec<_>>();
182 let problem = if points_to.is_empty() { 185 let problem = if points_to.is_empty() {
183 Some(Problem::UnresolvedModule { 186 Some(Problem::UnresolvedModule {
184 candidate: if is_dir_owner { file_mod } else { file_dir_mod }, 187 candidate: RelativePath::new("../").join(&if is_dir_owner {
188 file_mod
189 } else {
190 file_dir_mod
191 }),
185 }) 192 })
186 } else { 193 } else {
187 None 194 None