aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis')
-rw-r--r--crates/libanalysis/src/lib.rs70
-rw-r--r--crates/libanalysis/src/module_map.rs148
2 files changed, 147 insertions, 71 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index d01144627..fee0d10d6 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -17,7 +17,6 @@ use rayon::prelude::*;
17 17
18use std::{ 18use std::{
19 fmt, 19 fmt,
20 mem,
21 path::{Path}, 20 path::{Path},
22 sync::{ 21 sync::{
23 Arc, 22 Arc,
@@ -36,18 +35,16 @@ use libeditor::{LineIndex, FileSymbol, find_node};
36 35
37use self::{ 36use self::{
38 symbol_index::FileSymbols, 37 symbol_index::FileSymbols,
39 module_map::ModuleMap, 38 module_map::{ModuleMap, ChangeKind},
40}; 39};
41pub use self::symbol_index::Query; 40pub use self::symbol_index::Query;
42 41
43pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 42pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
44const INDEXING_THRESHOLD: usize = 128;
45 43
46pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync; 44pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync;
47 45
48#[derive(Debug)] 46#[derive(Debug)]
49pub struct WorldState { 47pub struct WorldState {
50 updates: Vec<FileId>,
51 data: Arc<WorldData> 48 data: Arc<WorldData>
52} 49}
53 50
@@ -79,32 +76,16 @@ pub struct FileId(pub u32);
79impl WorldState { 76impl WorldState {
80 pub fn new() -> WorldState { 77 pub fn new() -> WorldState {
81 WorldState { 78 WorldState {
82 updates: Vec::new(),
83 data: Arc::new(WorldData::default()), 79 data: Arc::new(WorldData::default()),
84 } 80 }
85 } 81 }
86 82
87 pub fn snapshot( 83 pub fn snapshot(
88 &mut self, 84 &self,
89 file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync, 85 file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync,
90 ) -> World { 86 ) -> World {
91 let needs_reindex = self.updates.len() >= INDEXING_THRESHOLD;
92 if !self.updates.is_empty() {
93 let updates = mem::replace(&mut self.updates, Vec::new());
94 let data = self.data_mut();
95 for file_id in updates {
96 let syntax = data.file_map
97 .get(&file_id)
98 .map(|it| it.syntax());
99 data.module_map.update_file(
100 file_id,
101 syntax,
102 &file_resolver,
103 );
104 }
105 }
106 World { 87 World {
107 needs_reindex: AtomicBool::new(needs_reindex), 88 needs_reindex: AtomicBool::new(false),
108 file_resolver: Arc::new(file_resolver), 89 file_resolver: Arc::new(file_resolver),
109 data: self.data.clone() 90 data: self.data.clone()
110 } 91 }
@@ -115,21 +96,26 @@ impl WorldState {
115 } 96 }
116 97
117 pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { 98 pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
118 let mut updates = Vec::new(); 99 let data = self.data_mut();
119 { 100 for (file_id, text) in changes {
120 let data = self.data_mut(); 101 let change_kind = if data.file_map.remove(&file_id).is_some() {
121 for (file_id, text) in changes { 102 if text.is_some() {
122 data.file_map.remove(&file_id); 103 ChangeKind::Update
123 if let Some(text) = text {
124 let file_data = FileData::new(text);
125 data.file_map.insert(file_id, Arc::new(file_data));
126 } else { 104 } else {
127 data.file_map.remove(&file_id); 105 ChangeKind::Delete
128 } 106 }
129 updates.push(file_id); 107 } else {
108 ChangeKind::Insert
109 };
110 data.module_map.update_file(file_id, change_kind);
111 data.file_map.remove(&file_id);
112 if let Some(text) = text {
113 let file_data = FileData::new(text);
114 data.file_map.insert(file_id, Arc::new(file_data));
115 } else {
116 data.file_map.remove(&file_id);
130 } 117 }
131 } 118 }
132 self.updates.extend(updates)
133 } 119 }
134 120
135 fn data_mut(&mut self) -> &mut WorldData { 121 fn data_mut(&mut self) -> &mut WorldData {
@@ -171,13 +157,17 @@ impl World {
171 let module_map = &self.data.module_map; 157 let module_map = &self.data.module_map;
172 let id = module_map.file2module(id); 158 let id = module_map.file2module(id);
173 module_map 159 module_map
174 .parent_modules(id) 160 .parent_modules(
161 id,
162 &*self.file_resolver,
163 &|file_id| self.file_syntax(file_id).unwrap(),
164 )
175 .into_iter() 165 .into_iter()
176 .map(|(id, m)| { 166 .map(|(id, name, node)| {
177 let id = module_map.module2file(id); 167 let id = module_map.module2file(id);
178 let sym = FileSymbol { 168 let sym = FileSymbol {
179 name: m.name().unwrap().text(), 169 name,
180 node_range: m.syntax().range(), 170 node_range: node.range(),
181 kind: MODULE, 171 kind: MODULE,
182 }; 172 };
183 (id, sym) 173 (id, sym)
@@ -235,7 +225,11 @@ impl World {
235 let module_map = &self.data.module_map; 225 let module_map = &self.data.module_map;
236 let id = module_map.file2module(id); 226 let id = module_map.file2module(id);
237 module_map 227 module_map
238 .child_module_by_name(id, name.as_str()) 228 .child_module_by_name(
229 id, name.as_str(),
230 &*self.file_resolver,
231 &|file_id| self.file_syntax(file_id).unwrap(),
232 )
239 .into_iter() 233 .into_iter()
240 .map(|id| module_map.module2file(id)) 234 .map(|id| module_map.module2file(id))
241 .collect() 235 .collect()
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs
index 9b4c778b6..83e6e57f7 100644
--- a/crates/libanalysis/src/module_map.rs
+++ b/crates/libanalysis/src/module_map.rs
@@ -2,17 +2,38 @@ use std::{
2 path::{PathBuf}, 2 path::{PathBuf},
3}; 3};
4 4
5use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
5use libsyntax2::{ 6use libsyntax2::{
6 ast::{self, AstNode, NameOwner}, 7 ast::{self, AstNode, NameOwner, ParsedFile},
7 SyntaxNode, ParsedFile, SmolStr, 8 SyntaxNode, SmolStr,
8}; 9};
9use {FileId, FileResolver}; 10use {FileId, FileResolver};
10 11
12type SyntaxProvider<'a> = dyn Fn(FileId) -> ParsedFile + 'a;
13
11#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 14#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
12pub struct ModuleId(FileId); 15pub struct ModuleId(FileId);
13 16
14#[derive(Clone, Debug, Default)] 17#[derive(Debug, Default)]
15pub struct ModuleMap { 18pub struct ModuleMap {
19 state: RwLock<State>,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum ChangeKind {
24 Delete, Insert, Update
25}
26
27impl Clone for ModuleMap {
28 fn clone(&self) -> ModuleMap {
29 let state = self.state.read().clone();
30 ModuleMap { state: RwLock::new(state) }
31 }
32}
33
34#[derive(Clone, Debug, Default)]
35struct State {
36 changes: Vec<(FileId, ChangeKind)>,
16 links: Vec<Link>, 37 links: Vec<Link>,
17} 38}
18 39
@@ -24,31 +45,8 @@ struct Link {
24} 45}
25 46
26impl ModuleMap { 47impl ModuleMap {
27 pub fn update_file( 48 pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) {
28 &mut self, 49 self.state.get_mut().changes.push((file, change_kind));
29 file_id: FileId,
30 syntax: Option<&ParsedFile>,
31 file_resolver: &FileResolver,
32 ) {
33 let mod_id = ModuleId(file_id);
34 self.links.retain(|link| link.owner != mod_id);
35 match syntax {
36 None => {
37 for link in self.links.iter_mut() {
38 link.points_to.retain(|&x| x != mod_id);
39 }
40 }
41 Some(syntax) => {
42 self.links.extend(
43 syntax.ast().modules().filter_map(|it| {
44 Link::new(mod_id, it)
45 })
46 )
47 }
48 }
49 self.links.iter_mut().for_each(|link| {
50 link.resolve(file_resolver)
51 })
52 } 50 }
53 51
54 pub fn module2file(&self, m: ModuleId) -> FileId { 52 pub fn module2file(&self, m: ModuleId) -> FileId {
@@ -59,8 +57,15 @@ impl ModuleMap {
59 ModuleId(file_id) 57 ModuleId(file_id)
60 } 58 }
61 59
62 pub fn child_module_by_name(&self, parent_mod: ModuleId, child_mod: &str) -> Vec<ModuleId> { 60 pub fn child_module_by_name<'a>(
63 self.links 61 &self,
62 parent_mod: ModuleId,
63 child_mod: &str,
64 file_resolver: &FileResolver,
65 syntax_provider: &SyntaxProvider,
66 ) -> Vec<ModuleId> {
67 self.links(file_resolver, syntax_provider)
68 .links
64 .iter() 69 .iter()
65 .filter(|link| link.owner == parent_mod) 70 .filter(|link| link.owner == parent_mod)
66 .filter(|link| link.name() == child_mod) 71 .filter(|link| link.name() == child_mod)
@@ -69,13 +74,90 @@ impl ModuleMap {
69 .collect() 74 .collect()
70 } 75 }
71 76
72 pub fn parent_modules<'a>(&'a self, m: ModuleId) -> impl Iterator<Item=(ModuleId, ast::Module<'a>)> + 'a { 77 pub fn parent_modules(
73 self.links 78 &self,
79 m: ModuleId,
80 file_resolver: &FileResolver,
81 syntax_provider: &SyntaxProvider,
82 ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
83 let links = self.links(file_resolver, syntax_provider);
84 let res = links
85 .links
74 .iter() 86 .iter()
75 .filter(move |link| link.points_to.iter().any(|&it| it == m)) 87 .filter(move |link| link.points_to.iter().any(|&it| it == m))
76 .map(|link| { 88 .map(|link| {
77 (link.owner, link.ast()) 89 (link.owner, link.name().clone(), link.syntax.clone())
78 }) 90 })
91 .collect();
92 res
93 }
94
95 fn links(
96 &self,
97 file_resolver: &FileResolver,
98 syntax_provider: &SyntaxProvider,
99 ) -> RwLockReadGuard<State> {
100 {
101 let guard = self.state.read();
102 if guard.changes.is_empty() {
103 return guard;
104 }
105 }
106 let mut guard = self.state.write();
107 if !guard.changes.is_empty() {
108 guard.apply_changes(file_resolver, syntax_provider);
109 }
110 assert!(guard.changes.is_empty());
111 RwLockWriteGuard::downgrade(guard)
112 }
113}
114
115impl State {
116 pub fn apply_changes(
117 &mut self,
118 file_resolver: &FileResolver,
119 syntax_provider: &SyntaxProvider,
120 ) {
121 let mut reresolve = false;
122 for (file_id, kind) in self.changes.drain(..) {
123 let mod_id = ModuleId(file_id);
124 self.links.retain(|link| link.owner != mod_id);
125 match kind {
126 ChangeKind::Delete => {
127 for link in self.links.iter_mut() {
128 link.points_to.retain(|&x| x != mod_id);
129 }
130 }
131 ChangeKind::Insert => {
132 let file = syntax_provider(file_id);
133 self.links.extend(
134 file
135 .ast()
136 .modules()
137 .filter_map(|it| Link::new(mod_id, it))
138 );
139 reresolve = true;
140 }
141 ChangeKind::Update => {
142 let file = syntax_provider(file_id);
143 self.links.extend(
144 file
145 .ast()
146 .modules()
147 .filter_map(|it| Link::new(mod_id, it))
148 .map(|mut link| {
149 link.resolve(file_resolver);
150 link
151 })
152 );
153 }
154 }
155 }
156 if reresolve {
157 for link in self.links.iter_mut() {
158 link.resolve(file_resolver)
159 }
160 }
79 } 161 }
80} 162}
81 163