aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/libanalysis/src/imp.rs53
-rw-r--r--crates/libanalysis/src/lib.rs19
-rw-r--r--crates/libanalysis/src/module_map.rs36
-rw-r--r--crates/libanalysis/tests/tests.rs38
4 files changed, 131 insertions, 15 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs
index 6a6e1e933..f1d72da15 100644
--- a/crates/libanalysis/src/imp.rs
+++ b/crates/libanalysis/src/imp.rs
@@ -5,7 +5,7 @@ use std::{
5 }, 5 },
6 fmt, 6 fmt,
7 time::Instant, 7 time::Instant,
8 collections::HashMap, 8 collections::{HashMap, HashSet, VecDeque},
9 panic, 9 panic,
10}; 10};
11 11
@@ -23,7 +23,7 @@ use {
23 module_map::Problem, 23 module_map::Problem,
24 symbol_index::FileSymbols, 24 symbol_index::FileSymbols,
25 module_map::{ModuleMap, ChangeKind}, 25 module_map::{ModuleMap, ChangeKind},
26 JobToken, 26 JobToken, CrateGraph, CrateId,
27}; 27};
28 28
29#[derive(Debug)] 29#[derive(Debug)]
@@ -37,7 +37,6 @@ impl AnalysisHostImpl {
37 data: Arc::new(WorldData::default()), 37 data: Arc::new(WorldData::default()),
38 } 38 }
39 } 39 }
40
41 pub fn analysis( 40 pub fn analysis(
42 &self, 41 &self,
43 file_resolver: Arc<dyn FileResolver>, 42 file_resolver: Arc<dyn FileResolver>,
@@ -48,7 +47,6 @@ impl AnalysisHostImpl {
48 data: self.data.clone(), 47 data: self.data.clone(),
49 } 48 }
50 } 49 }
51
52 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { 50 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
53 let data = self.data_mut(); 51 let data = self.data_mut();
54 for (file_id, text) in changes { 52 for (file_id, text) in changes {
@@ -71,7 +69,15 @@ impl AnalysisHostImpl {
71 } 69 }
72 } 70 }
73 } 71 }
74 72 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
73 let mut visited = HashSet::new();
74 for &file_id in graph.crate_roots.values() {
75 if !visited.insert(file_id) {
76 panic!("duplicate crate root: {:?}", file_id);
77 }
78 }
79 self.data_mut().crate_graph = graph;
80 }
75 fn data_mut(&mut self) -> &mut WorldData { 81 fn data_mut(&mut self) -> &mut WorldData {
76 Arc::make_mut(&mut self.data) 82 Arc::make_mut(&mut self.data)
77 } 83 }
@@ -145,6 +151,33 @@ impl AnalysisImpl {
145 .collect() 151 .collect()
146 } 152 }
147 153
154 pub fn crate_root(&self, id: FileId) -> Vec<CrateId> {
155 let module_map = &self.data.module_map;
156 let crate_graph = &self.data.crate_graph;
157 let mut res = Vec::new();
158 let mut work = VecDeque::new();
159 work.push_back(id);
160 let mut visited = HashSet::new();
161 while let Some(id) = work.pop_front() {
162 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) {
163 res.push(crate_id);
164 continue;
165 }
166 let mid = module_map.file2module(id);
167 let parents = module_map
168 .parent_module_ids(
169 mid,
170 &*self.file_resolver,
171 &|file_id| self.file_syntax(file_id),
172 )
173 .into_iter()
174 .map(|id| module_map.module2file(id))
175 .filter(|&id| visited.insert(id));
176 work.extend(parents);
177 }
178 res
179 }
180
148 pub fn approximately_resolve_symbol( 181 pub fn approximately_resolve_symbol(
149 &self, 182 &self,
150 id: FileId, 183 id: FileId,
@@ -295,6 +328,7 @@ impl AnalysisImpl {
295 328
296#[derive(Clone, Default, Debug)] 329#[derive(Clone, Default, Debug)]
297struct WorldData { 330struct WorldData {
331 crate_graph: CrateGraph,
298 file_map: HashMap<FileId, Arc<FileData>>, 332 file_map: HashMap<FileId, Arc<FileData>>,
299 module_map: ModuleMap, 333 module_map: ModuleMap,
300} 334}
@@ -356,3 +390,12 @@ impl SourceChange {
356 } 390 }
357 } 391 }
358} 392}
393
394impl CrateGraph {
395 fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
396 let (&crate_id, _) = self.crate_roots
397 .iter()
398 .find(|(_crate_id, &root_id)| root_id == file_id)?;
399 Some(crate_id)
400 }
401}
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index a59fd1c09..041abbb89 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -15,7 +15,10 @@ mod module_map;
15mod imp; 15mod imp;
16mod job; 16mod job;
17 17
18use std::sync::Arc; 18use std::{
19 sync::Arc,
20 collections::HashMap,
21};
19 22
20use relative_path::{RelativePath, RelativePathBuf}; 23use relative_path::{RelativePath, RelativePathBuf};
21use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; 24use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
@@ -30,6 +33,14 @@ pub use job::{JobToken, JobHandle};
30#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 33#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub struct FileId(pub u32); 34pub struct FileId(pub u32);
32 35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct CrateId(pub u32);
38
39#[derive(Debug, Clone, Default)]
40pub struct CrateGraph {
41 pub crate_roots: HashMap<CrateId, FileId>,
42}
43
33pub trait FileResolver: Send + Sync + 'static { 44pub trait FileResolver: Send + Sync + 'static {
34 fn file_stem(&self, id: FileId) -> String; 45 fn file_stem(&self, id: FileId) -> String;
35 fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; 46 fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
@@ -53,6 +64,9 @@ impl AnalysisHost {
53 pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { 64 pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) {
54 self.imp.change_files(&mut changes) 65 self.imp.change_files(&mut changes)
55 } 66 }
67 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
68 self.imp.set_crate_graph(graph)
69 }
56} 70}
57 71
58#[derive(Debug)] 72#[derive(Debug)]
@@ -168,6 +182,9 @@ impl Analysis {
168 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 182 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
169 self.imp.parent_module(file_id) 183 self.imp.parent_module(file_id)
170 } 184 }
185 pub fn crate_root(&self, file_id: FileId) -> Vec<CrateId> {
186 self.imp.crate_root(file_id)
187 }
171 pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { 188 pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> {
172 let file = self.file_syntax(file_id); 189 let file = self.file_syntax(file_id);
173 libeditor::runnables(&file) 190 libeditor::runnables(&file)
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs
index 47c0018e1..38935807d 100644
--- a/crates/libanalysis/src/module_map.rs
+++ b/crates/libanalysis/src/module_map.rs
@@ -91,16 +91,38 @@ impl ModuleMap {
91 file_resolver: &FileResolver, 91 file_resolver: &FileResolver,
92 syntax_provider: &SyntaxProvider, 92 syntax_provider: &SyntaxProvider,
93 ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { 93 ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
94 let links = self.links(file_resolver, syntax_provider); 94 let mut res = Vec::new();
95 let res = links 95 self.for_each_parent_link(m, file_resolver, syntax_provider, |link| {
96 res.push(
97 (link.owner, link.name().clone(), link.syntax.clone())
98 )
99 });
100 res
101 }
102
103 pub fn parent_module_ids(
104 &self,
105 m: ModuleId,
106 file_resolver: &FileResolver,
107 syntax_provider: &SyntaxProvider,
108 ) -> Vec<ModuleId> {
109 let mut res = Vec::new();
110 self.for_each_parent_link(m, file_resolver, syntax_provider, |link| res.push(link.owner));
111 res
112 }
113
114 fn for_each_parent_link(
115 &self,
116 m: ModuleId,
117 file_resolver: &FileResolver,
118 syntax_provider: &SyntaxProvider,
119 f: impl FnMut(&Link)
120 ) {
121 self.links(file_resolver, syntax_provider)
96 .links 122 .links
97 .iter() 123 .iter()
98 .filter(move |link| link.points_to.iter().any(|&it| it == m)) 124 .filter(move |link| link.points_to.iter().any(|&it| it == m))
99 .map(|link| { 125 .for_each(f)
100 (link.owner, link.name().clone(), link.syntax.clone())
101 })
102 .collect();
103 res
104 } 126 }
105 127
106 pub fn problems( 128 pub fn problems(
diff --git a/crates/libanalysis/tests/tests.rs b/crates/libanalysis/tests/tests.rs
index 887e13fa3..c098c8e8c 100644
--- a/crates/libanalysis/tests/tests.rs
+++ b/crates/libanalysis/tests/tests.rs
@@ -2,10 +2,13 @@ extern crate libanalysis;
2extern crate relative_path; 2extern crate relative_path;
3extern crate test_utils; 3extern crate test_utils;
4 4
5use std::path::{Path}; 5use std::{
6 collections::HashMap,
7 path::{Path},
8};
6 9
7use relative_path::RelativePath; 10use relative_path::RelativePath;
8use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle}; 11use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId};
9use test_utils::assert_eq_dbg; 12use test_utils::assert_eq_dbg;
10 13
11struct FileMap(&'static [(u32, &'static str)]); 14struct FileMap(&'static [(u32, &'static str)]);
@@ -112,3 +115,34 @@ fn test_resolve_parent_module() {
112 &symbols, 115 &symbols,
113 ); 116 );
114} 117}
118
119#[test]
120fn test_resolve_crate_root() {
121 let mut world = AnalysisHost::new();
122 world.change_file(FileId(1), Some("mod foo;".to_string()));
123 world.change_file(FileId(2), Some("".to_string()));
124
125 let snap = world.analysis(FileMap(&[
126 (1, "/lib.rs"),
127 (2, "/foo.rs"),
128 ]));
129 assert!(snap.crate_root(FileId(2)).is_empty());
130
131 let crate_graph = CrateGraph {
132 crate_roots: {
133 let mut m = HashMap::new();
134 m.insert(CrateId(1), FileId(1));
135 m
136 },
137 };
138 world.set_crate_graph(crate_graph);
139
140 let snap = world.analysis(FileMap(&[
141 (1, "/lib.rs"),
142 (2, "/foo.rs"),
143 ]));
144 assert_eq!(
145 snap.crate_root(FileId(2)),
146 vec![CrateId(1)],
147 );
148}