aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/imp.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-09-16 10:54:24 +0100
committerAleksey Kladov <[email protected]>2018-09-16 11:07:39 +0100
commitb5021411a84822cb3f1e3aeffad9550dd15bdeb6 (patch)
tree9dca564f8e51b298dced01c4ce669c756dce3142 /crates/libanalysis/src/imp.rs
parentba0bfeee12e19da40b5eabc8d0408639af10e96f (diff)
rename all things
Diffstat (limited to 'crates/libanalysis/src/imp.rs')
-rw-r--r--crates/libanalysis/src/imp.rs342
1 files changed, 0 insertions, 342 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs
deleted file mode 100644
index 6f3191fe7..000000000
--- a/crates/libanalysis/src/imp.rs
+++ /dev/null
@@ -1,342 +0,0 @@
1use std::{
2 sync::{
3 Arc,
4 atomic::{AtomicBool, Ordering::SeqCst},
5 },
6 fmt,
7 collections::{HashSet, VecDeque},
8 iter,
9};
10
11use relative_path::RelativePath;
12use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit};
13use libsyntax2::{
14 TextUnit, TextRange, SmolStr, File, AstNode,
15 SyntaxKind::*,
16 ast::{self, NameOwner},
17};
18
19use {
20 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
21 JobToken, CrateGraph, CrateId,
22 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
23 descriptors::{ModuleTreeDescriptor, Problem},
24};
25
26
27#[derive(Clone, Debug)]
28pub(crate) struct FileResolverImp {
29 inner: Arc<FileResolver>
30}
31
32impl FileResolverImp {
33 pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp {
34 FileResolverImp { inner }
35 }
36 pub(crate) fn file_stem(&self, file_id: FileId) -> String {
37 self.inner.file_stem(file_id)
38 }
39 pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> {
40 self.inner.resolve(file_id, path)
41 }
42}
43
44impl Default for FileResolverImp {
45 fn default() -> FileResolverImp {
46 #[derive(Debug)]
47 struct DummyResolver;
48 impl FileResolver for DummyResolver {
49 fn file_stem(&self, _file_: FileId) -> String {
50 panic!("file resolver not set")
51 }
52 fn resolve(&self, _file_id: FileId, _path: &::relative_path::RelativePath) -> Option<FileId> {
53 panic!("file resolver not set")
54 }
55 }
56 FileResolverImp { inner: Arc::new(DummyResolver) }
57 }
58}
59
60#[derive(Debug)]
61pub(crate) struct AnalysisHostImpl {
62 data: Arc<WorldData>
63}
64
65impl AnalysisHostImpl {
66 pub fn new() -> AnalysisHostImpl {
67 AnalysisHostImpl {
68 data: Arc::new(WorldData::default()),
69 }
70 }
71 pub fn analysis(&self) -> AnalysisImpl {
72 AnalysisImpl {
73 needs_reindex: AtomicBool::new(false),
74 data: self.data.clone(),
75 }
76 }
77 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
78 let data = self.data_mut();
79 data.root = Arc::new(data.root.apply_changes(changes, None));
80 }
81 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) {
82 let data = self.data_mut();
83 data.file_resolver = resolver.clone();
84 data.root = Arc::new(data.root.apply_changes(&mut iter::empty(), Some(resolver)));
85 }
86 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
87 let mut visited = HashSet::new();
88 for &file_id in graph.crate_roots.values() {
89 if !visited.insert(file_id) {
90 panic!("duplicate crate root: {:?}", file_id);
91 }
92 }
93 self.data_mut().crate_graph = graph;
94 }
95 pub fn add_library(&mut self, root: ReadonlySourceRoot) {
96 self.data_mut().libs.push(Arc::new(root));
97 }
98 fn data_mut(&mut self) -> &mut WorldData {
99 Arc::make_mut(&mut self.data)
100 }
101}
102
103pub(crate) struct AnalysisImpl {
104 needs_reindex: AtomicBool,
105 data: Arc<WorldData>,
106}
107
108impl fmt::Debug for AnalysisImpl {
109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 (&*self.data).fmt(f)
111 }
112}
113
114impl Clone for AnalysisImpl {
115 fn clone(&self) -> AnalysisImpl {
116 AnalysisImpl {
117 needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
118 data: Arc::clone(&self.data),
119 }
120 }
121}
122
123impl AnalysisImpl {
124 fn root(&self, file_id: FileId) -> &SourceRoot {
125 if self.data.root.contains(file_id) {
126 return &*self.data.root;
127 }
128 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
129 }
130 pub fn file_syntax(&self, file_id: FileId) -> File {
131 self.root(file_id).syntax(file_id)
132 }
133 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
134 self.root(file_id).lines(file_id)
135 }
136 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
137 let mut buf = Vec::new();
138 if query.libs {
139 self.data.libs.iter()
140 .for_each(|it| it.symbols(&mut buf));
141 } else {
142 self.data.root.symbols(&mut buf);
143 }
144 query.search(&buf, token)
145
146 }
147 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
148 let root = self.root(file_id);
149 let module_tree = root.module_tree();
150 module_tree.parent_modules(file_id)
151 .iter()
152 .map(|link| {
153 let file_id = link.owner(&module_tree);
154 let syntax = root.syntax(file_id);
155 let decl = link.bind_source(&module_tree, syntax.ast());
156 let sym = FileSymbol {
157 name: link.name(&module_tree),
158 node_range: decl.syntax().range(),
159 kind: MODULE,
160 };
161 (file_id, sym)
162 })
163 .collect()
164 }
165 pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
166 let module_tree = self.root(file_id).module_tree();
167 let crate_graph = &self.data.crate_graph;
168 let mut res = Vec::new();
169 let mut work = VecDeque::new();
170 work.push_back(file_id);
171 let mut visited = HashSet::new();
172 while let Some(id) = work.pop_front() {
173 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) {
174 res.push(crate_id);
175 continue;
176 }
177 let parents = module_tree
178 .parent_modules(id)
179 .into_iter()
180 .map(|link| link.owner(&module_tree))
181 .filter(|&id| visited.insert(id));
182 work.extend(parents);
183 }
184 res
185 }
186 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
187 self.data.crate_graph.crate_roots[&crate_id]
188 }
189 pub fn approximately_resolve_symbol(
190 &self,
191 file_id: FileId,
192 offset: TextUnit,
193 token: &JobToken,
194 ) -> Vec<(FileId, FileSymbol)> {
195 let root = self.root(file_id);
196 let module_tree = root.module_tree();
197 let file = root.syntax(file_id);
198 let syntax = file.syntax();
199 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
200 return self.index_resolve(name_ref, token);
201 }
202 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
203 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
204 if module.has_semi() {
205 let file_ids = self.resolve_module(&*module_tree, file_id, module);
206
207 let res = file_ids.into_iter().map(|id| {
208 let name = module.name()
209 .map(|n| n.text())
210 .unwrap_or_else(|| SmolStr::new(""));
211 let symbol = FileSymbol {
212 name,
213 node_range: TextRange::offset_len(0.into(), 0.into()),
214 kind: MODULE,
215 };
216 (id, symbol)
217 }).collect();
218
219 return res;
220 }
221 }
222 }
223 vec![]
224 }
225
226 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
227 let root = self.root(file_id);
228 let module_tree = root.module_tree();
229 let syntax = root.syntax(file_id);
230
231 let mut res = libeditor::diagnostics(&syntax)
232 .into_iter()
233 .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None })
234 .collect::<Vec<_>>();
235
236 for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) {
237 let diag = match problem {
238 Problem::UnresolvedModule { candidate } => {
239 let create_file = FileSystemEdit::CreateFile {
240 anchor: file_id,
241 path: candidate.clone(),
242 };
243 let fix = SourceChange {
244 label: "create module".to_string(),
245 source_file_edits: Vec::new(),
246 file_system_edits: vec![create_file],
247 cursor_position: None,
248 };
249 Diagnostic {
250 range: name_node.syntax().range(),
251 message: "unresolved module".to_string(),
252 fix: Some(fix),
253 }
254 }
255 Problem::NotDirOwner { move_to, candidate } => {
256 let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() };
257 let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) };
258 let fix = SourceChange {
259 label: "move file and create module".to_string(),
260 source_file_edits: Vec::new(),
261 file_system_edits: vec![move_file, create_file],
262 cursor_position: None,
263 };
264 Diagnostic {
265 range: name_node.syntax().range(),
266 message: "can't declare module at this location".to_string(),
267 fix: Some(fix),
268 }
269 }
270 };
271 res.push(diag)
272 }
273 res
274 }
275
276 pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> {
277 let file = self.file_syntax(file_id);
278 let offset = range.start();
279 let actions = vec![
280 ("flip comma", libeditor::flip_comma(&file, offset).map(|f| f())),
281 ("add `#[derive]`", libeditor::add_derive(&file, offset).map(|f| f())),
282 ("add impl", libeditor::add_impl(&file, offset).map(|f| f())),
283 ("introduce variable", libeditor::introduce_variable(&file, range).map(|f| f())),
284 ];
285 actions.into_iter()
286 .filter_map(|(name, local_edit)| {
287 Some(SourceChange::from_local_edit(
288 file_id, name, local_edit?,
289 ))
290 })
291 .collect()
292 }
293
294 fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
295 let name = name_ref.text();
296 let mut query = Query::new(name.to_string());
297 query.exact();
298 query.limit(4);
299 self.world_symbols(query, token)
300 }
301
302 fn resolve_module(&self, module_tree: &ModuleTreeDescriptor, file_id: FileId, module: ast::Module) -> Vec<FileId> {
303 let name = match module.name() {
304 Some(name) => name.text(),
305 None => return Vec::new(),
306 };
307 module_tree.child_module_by_name(file_id, name.as_str())
308 }
309}
310
311#[derive(Default, Clone, Debug)]
312struct WorldData {
313 file_resolver: FileResolverImp,
314 crate_graph: CrateGraph,
315 root: Arc<WritableSourceRoot>,
316 libs: Vec<Arc<ReadonlySourceRoot>>,
317}
318
319impl SourceChange {
320 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
321 let file_edit = SourceFileEdit {
322 file_id,
323 edits: edit.edit.into_atoms(),
324 };
325 SourceChange {
326 label: label.to_string(),
327 source_file_edits: vec![file_edit],
328 file_system_edits: vec![],
329 cursor_position: edit.cursor_position
330 .map(|offset| Position { offset, file_id })
331 }
332 }
333}
334
335impl CrateGraph {
336 fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
337 let (&crate_id, _) = self.crate_roots
338 .iter()
339 .find(|(_crate_id, &root_id)| root_id == file_id)?;
340 Some(crate_id)
341 }
342}