diff options
Diffstat (limited to 'crates/ra_analysis/src/roots.rs')
-rw-r--r-- | crates/ra_analysis/src/roots.rs | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs new file mode 100644 index 000000000..1835a9b25 --- /dev/null +++ b/crates/ra_analysis/src/roots.rs | |||
@@ -0,0 +1,178 @@ | |||
1 | use std::{ | ||
2 | collections::HashMap, | ||
3 | sync::Arc, | ||
4 | panic, | ||
5 | }; | ||
6 | |||
7 | use once_cell::sync::OnceCell; | ||
8 | use rayon::prelude::*; | ||
9 | use ra_editor::LineIndex; | ||
10 | use ra_syntax::File; | ||
11 | |||
12 | use { | ||
13 | FileId, | ||
14 | imp::FileResolverImp, | ||
15 | symbol_index::SymbolIndex, | ||
16 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | ||
17 | db::Db, | ||
18 | }; | ||
19 | |||
20 | pub(crate) trait SourceRoot { | ||
21 | fn contains(&self, file_id: FileId) -> bool; | ||
22 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor>; | ||
23 | fn lines(&self, file_id: FileId) -> Arc<LineIndex>; | ||
24 | fn syntax(&self, file_id: FileId) -> File; | ||
25 | fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>); | ||
26 | } | ||
27 | |||
28 | #[derive(Default, Debug)] | ||
29 | pub(crate) struct WritableSourceRoot { | ||
30 | db: Db, | ||
31 | } | ||
32 | |||
33 | impl WritableSourceRoot { | ||
34 | pub fn apply_changes( | ||
35 | &self, | ||
36 | changes: &mut dyn Iterator<Item=(FileId, Option<String>)>, | ||
37 | file_resolver: Option<FileResolverImp>, | ||
38 | ) -> WritableSourceRoot { | ||
39 | let resolver_changed = file_resolver.is_some(); | ||
40 | let mut changed_files = Vec::new(); | ||
41 | let mut new_state = self.db.state().clone(); | ||
42 | |||
43 | for (file_id, text) in changes { | ||
44 | changed_files.push(file_id); | ||
45 | match text { | ||
46 | Some(text) => { | ||
47 | new_state.file_map.insert(file_id, Arc::new(text)); | ||
48 | }, | ||
49 | None => { | ||
50 | new_state.file_map.remove(&file_id); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | if let Some(file_resolver) = file_resolver { | ||
55 | new_state.file_resolver = file_resolver | ||
56 | } | ||
57 | WritableSourceRoot { | ||
58 | db: self.db.with_changes(new_state, &changed_files, resolver_changed) | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | impl SourceRoot for WritableSourceRoot { | ||
64 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { | ||
65 | self.db.make_query(::module_map::module_tree) | ||
66 | } | ||
67 | |||
68 | fn contains(&self, file_id: FileId) -> bool { | ||
69 | self.db.state().file_map.contains_key(&file_id) | ||
70 | } | ||
71 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { | ||
72 | self.db.make_query(|ctx| ::queries::file_lines(ctx, file_id)) | ||
73 | } | ||
74 | fn syntax(&self, file_id: FileId) -> File { | ||
75 | self.db.make_query(|ctx| ::queries::file_syntax(ctx, file_id)) | ||
76 | } | ||
77 | fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { | ||
78 | self.db.make_query(|ctx| { | ||
79 | let file_set = ::queries::file_set(ctx); | ||
80 | let syms = file_set.0.iter() | ||
81 | .map(|file_id| ::queries::file_symbols(ctx, *file_id)); | ||
82 | acc.extend(syms); | ||
83 | }); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | #[derive(Debug)] | ||
88 | struct FileData { | ||
89 | text: String, | ||
90 | lines: OnceCell<Arc<LineIndex>>, | ||
91 | syntax: OnceCell<File>, | ||
92 | } | ||
93 | |||
94 | impl FileData { | ||
95 | fn new(text: String) -> FileData { | ||
96 | FileData { | ||
97 | text, | ||
98 | syntax: OnceCell::new(), | ||
99 | lines: OnceCell::new(), | ||
100 | } | ||
101 | } | ||
102 | fn lines(&self) -> &Arc<LineIndex> { | ||
103 | self.lines.get_or_init(|| Arc::new(LineIndex::new(&self.text))) | ||
104 | } | ||
105 | fn syntax(&self) -> &File { | ||
106 | let text = &self.text; | ||
107 | let syntax = &self.syntax; | ||
108 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | ||
109 | Ok(file) => file, | ||
110 | Err(err) => { | ||
111 | error!("Parser paniced on:\n------\n{}\n------\n", text); | ||
112 | panic::resume_unwind(err) | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | #[derive(Debug)] | ||
119 | pub(crate) struct ReadonlySourceRoot { | ||
120 | symbol_index: Arc<SymbolIndex>, | ||
121 | file_map: HashMap<FileId, FileData>, | ||
122 | module_tree: Arc<ModuleTreeDescriptor>, | ||
123 | } | ||
124 | |||
125 | impl ReadonlySourceRoot { | ||
126 | pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot { | ||
127 | let modules = files.par_iter() | ||
128 | .map(|(file_id, text)| { | ||
129 | let syntax = File::parse(text); | ||
130 | let mod_descr = ModuleDescriptor::new(syntax.ast()); | ||
131 | (*file_id, syntax, mod_descr) | ||
132 | }) | ||
133 | .collect::<Vec<_>>(); | ||
134 | let module_tree = ModuleTreeDescriptor::new( | ||
135 | modules.iter().map(|it| (it.0, &it.2)), | ||
136 | &file_resolver, | ||
137 | ); | ||
138 | |||
139 | let symbol_index = SymbolIndex::for_files( | ||
140 | modules.par_iter().map(|it| (it.0, it.1.clone())) | ||
141 | ); | ||
142 | let file_map: HashMap<FileId, FileData> = files | ||
143 | .into_iter() | ||
144 | .map(|(id, text)| (id, FileData::new(text))) | ||
145 | .collect(); | ||
146 | |||
147 | ReadonlySourceRoot { | ||
148 | symbol_index: Arc::new(symbol_index), | ||
149 | file_map, | ||
150 | module_tree: Arc::new(module_tree), | ||
151 | } | ||
152 | } | ||
153 | |||
154 | fn data(&self, file_id: FileId) -> &FileData { | ||
155 | match self.file_map.get(&file_id) { | ||
156 | Some(data) => data, | ||
157 | None => panic!("unknown file: {:?}", file_id), | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | impl SourceRoot for ReadonlySourceRoot { | ||
163 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { | ||
164 | Arc::clone(&self.module_tree) | ||
165 | } | ||
166 | fn contains(&self, file_id: FileId) -> bool { | ||
167 | self.file_map.contains_key(&file_id) | ||
168 | } | ||
169 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { | ||
170 | Arc::clone(self.data(file_id).lines()) | ||
171 | } | ||
172 | fn syntax(&self, file_id: FileId) -> File { | ||
173 | self.data(file_id).syntax().clone() | ||
174 | } | ||
175 | fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>) { | ||
176 | acc.push(Arc::clone(&self.symbol_index)) | ||
177 | } | ||
178 | } | ||