diff options
Diffstat (limited to 'crates/libanalysis/src/roots.rs')
-rw-r--r-- | crates/libanalysis/src/roots.rs | 143 |
1 files changed, 103 insertions, 40 deletions
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs index 01de3e128..a65668c9b 100644 --- a/crates/libanalysis/src/roots.rs +++ b/crates/libanalysis/src/roots.rs | |||
@@ -13,16 +13,24 @@ use libsyntax2::File; | |||
13 | use { | 13 | use { |
14 | FileId, | 14 | FileId, |
15 | module_map::{ModuleMap, ChangeKind}, | 15 | module_map::{ModuleMap, ChangeKind}, |
16 | symbol_index::FileSymbols, | 16 | symbol_index::SymbolIndex, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | pub(crate) trait SourceRoot { | ||
20 | fn contains(&self, file_id: FileId) -> bool; | ||
21 | fn module_map(&self) -> &ModuleMap; | ||
22 | fn lines(&self, file_id: FileId) -> &LineIndex; | ||
23 | fn syntax(&self, file_id: FileId) -> &File; | ||
24 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>); | ||
25 | } | ||
26 | |||
19 | #[derive(Clone, Default, Debug)] | 27 | #[derive(Clone, Default, Debug)] |
20 | pub(crate) struct SourceRoot { | 28 | pub(crate) struct WritableSourceRoot { |
21 | file_map: HashMap<FileId, Arc<(FileData, OnceCell<FileSymbols>)>>, | 29 | file_map: HashMap<FileId, Arc<(FileData, OnceCell<SymbolIndex>)>>, |
22 | module_map: ModuleMap, | 30 | module_map: ModuleMap, |
23 | } | 31 | } |
24 | 32 | ||
25 | impl SourceRoot { | 33 | impl WritableSourceRoot { |
26 | pub fn update(&mut self, file_id: FileId, text: Option<String>) { | 34 | pub fn update(&mut self, file_id: FileId, text: Option<String>) { |
27 | let change_kind = if self.file_map.remove(&file_id).is_some() { | 35 | let change_kind = if self.file_map.remove(&file_id).is_some() { |
28 | if text.is_some() { | 36 | if text.is_some() { |
@@ -40,31 +48,6 @@ impl SourceRoot { | |||
40 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); | 48 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); |
41 | } | 49 | } |
42 | } | 50 | } |
43 | pub fn module_map(&self) -> &ModuleMap { | ||
44 | &self.module_map | ||
45 | } | ||
46 | pub fn lines(&self, file_id: FileId) -> &LineIndex { | ||
47 | let data = self.data(file_id); | ||
48 | data.lines.get_or_init(|| LineIndex::new(&data.text)) | ||
49 | } | ||
50 | pub fn syntax(&self, file_id: FileId) -> &File { | ||
51 | let data = self.data(file_id); | ||
52 | let text = &data.text; | ||
53 | let syntax = &data.syntax; | ||
54 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
55 | Ok(file) => file, | ||
56 | Err(err) => { | ||
57 | error!("Parser paniced on:\n------\n{}\n------\n", &data.text); | ||
58 | panic::resume_unwind(err) | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | pub(crate) fn symbols(&self) -> Vec<&FileSymbols> { | ||
63 | self.file_map | ||
64 | .iter() | ||
65 | .map(|(&file_id, data)| symbols(file_id, data)) | ||
66 | .collect() | ||
67 | } | ||
68 | pub fn reindex(&self) { | 51 | pub fn reindex(&self) { |
69 | let now = Instant::now(); | 52 | let now = Instant::now(); |
70 | self.file_map | 53 | self.file_map |
@@ -83,9 +66,31 @@ impl SourceRoot { | |||
83 | } | 66 | } |
84 | } | 67 | } |
85 | 68 | ||
86 | fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<FileSymbols>)) -> &FileSymbols { | 69 | impl SourceRoot for WritableSourceRoot { |
70 | fn contains(&self, file_id: FileId) -> bool { | ||
71 | self.file_map.contains_key(&file_id) | ||
72 | } | ||
73 | fn module_map(&self) -> &ModuleMap { | ||
74 | &self.module_map | ||
75 | } | ||
76 | fn lines(&self, file_id: FileId) -> &LineIndex { | ||
77 | self.data(file_id).lines() | ||
78 | } | ||
79 | fn syntax(&self, file_id: FileId) -> &File { | ||
80 | self.data(file_id).syntax() | ||
81 | } | ||
82 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { | ||
83 | acc.extend( | ||
84 | self.file_map | ||
85 | .iter() | ||
86 | .map(|(&file_id, data)| symbols(file_id, data)) | ||
87 | ) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<SymbolIndex>)) -> &SymbolIndex { | ||
87 | let syntax = data.syntax_transient(); | 92 | let syntax = data.syntax_transient(); |
88 | symbols.get_or_init(|| FileSymbols::new(file_id, &syntax)) | 93 | symbols.get_or_init(|| SymbolIndex::for_file(file_id, syntax)) |
89 | } | 94 | } |
90 | 95 | ||
91 | #[derive(Debug)] | 96 | #[derive(Debug)] |
@@ -103,19 +108,77 @@ impl FileData { | |||
103 | lines: OnceCell::new(), | 108 | lines: OnceCell::new(), |
104 | } | 109 | } |
105 | } | 110 | } |
111 | fn lines(&self) -> &LineIndex { | ||
112 | self.lines.get_or_init(|| LineIndex::new(&self.text)) | ||
113 | } | ||
114 | fn syntax(&self) -> &File { | ||
115 | let text = &self.text; | ||
116 | let syntax = &self.syntax; | ||
117 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
118 | Ok(file) => file, | ||
119 | Err(err) => { | ||
120 | error!("Parser paniced on:\n------\n{}\n------\n", text); | ||
121 | panic::resume_unwind(err) | ||
122 | } | ||
123 | } | ||
124 | } | ||
106 | fn syntax_transient(&self) -> File { | 125 | fn syntax_transient(&self) -> File { |
107 | self.syntax.get().map(|s| s.clone()) | 126 | self.syntax.get().map(|s| s.clone()) |
108 | .unwrap_or_else(|| File::parse(&self.text)) | 127 | .unwrap_or_else(|| File::parse(&self.text)) |
109 | } | 128 | } |
110 | } | 129 | } |
111 | 130 | ||
112 | // #[derive(Clone, Default, Debug)] | 131 | #[derive(Debug)] |
113 | // pub(crate) struct ReadonlySourceRoot { | 132 | pub(crate) struct ReadonlySourceRoot { |
114 | // data: Arc<ReadonlySourceRoot> | 133 | symbol_index: SymbolIndex, |
115 | // } | 134 | file_map: HashMap<FileId, FileData>, |
135 | module_map: ModuleMap, | ||
136 | } | ||
116 | 137 | ||
117 | // #[derive(Clone, Default, Debug)] | 138 | impl ReadonlySourceRoot { |
118 | // pub(crate) struct ReadonlySourceRootInner { | 139 | pub fn new(files: impl Iterator<Item=(FileId, String)>) -> ReadonlySourceRoot { |
119 | // file_map: HashMap<FileId, FileData>, | 140 | let mut module_map = ModuleMap::new(); |
120 | // module_map: ModuleMap, | 141 | let file_map: HashMap<FileId, FileData> = files |
121 | // } | 142 | .map(|(id, text)| { |
143 | module_map.update_file(id, ChangeKind::Insert); | ||
144 | (id, FileData::new(text)) | ||
145 | }) | ||
146 | .collect(); | ||
147 | let symbol_index = SymbolIndex::for_files( | ||
148 | file_map.par_iter().map(|(&file_id, file_data)| { | ||
149 | (file_id, file_data.syntax_transient()) | ||
150 | }) | ||
151 | ); | ||
152 | |||
153 | ReadonlySourceRoot { | ||
154 | symbol_index, | ||
155 | file_map, | ||
156 | module_map, | ||
157 | } | ||
158 | } | ||
159 | |||
160 | fn data(&self, file_id: FileId) -> &FileData { | ||
161 | match self.file_map.get(&file_id) { | ||
162 | Some(data) => data, | ||
163 | None => panic!("unknown file: {:?}", file_id), | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | impl SourceRoot for ReadonlySourceRoot { | ||
169 | fn contains(&self, file_id: FileId) -> bool { | ||
170 | self.file_map.contains_key(&file_id) | ||
171 | } | ||
172 | fn module_map(&self) -> &ModuleMap { | ||
173 | &self.module_map | ||
174 | } | ||
175 | fn lines(&self, file_id: FileId) -> &LineIndex { | ||
176 | self.data(file_id).lines() | ||
177 | } | ||
178 | fn syntax(&self, file_id: FileId) -> &File { | ||
179 | self.data(file_id).syntax() | ||
180 | } | ||
181 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { | ||
182 | acc.push(&self.symbol_index) | ||
183 | } | ||
184 | } | ||