mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
simpler update
This commit is contained in:
parent
b937262c9b
commit
ecc9df5f00
4 changed files with 149 additions and 73 deletions
|
@ -17,7 +17,6 @@ use rayon::prelude::*;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
mem,
|
|
||||||
path::{Path},
|
path::{Path},
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc,
|
||||||
|
@ -36,18 +35,16 @@ use libeditor::{LineIndex, FileSymbol, find_node};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
symbol_index::FileSymbols,
|
symbol_index::FileSymbols,
|
||||||
module_map::ModuleMap,
|
module_map::{ModuleMap, ChangeKind},
|
||||||
};
|
};
|
||||||
pub use self::symbol_index::Query;
|
pub use self::symbol_index::Query;
|
||||||
|
|
||||||
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
||||||
const INDEXING_THRESHOLD: usize = 128;
|
|
||||||
|
|
||||||
pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync;
|
pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WorldState {
|
pub struct WorldState {
|
||||||
updates: Vec<FileId>,
|
|
||||||
data: Arc<WorldData>
|
data: Arc<WorldData>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,32 +76,16 @@ pub struct FileId(pub u32);
|
||||||
impl WorldState {
|
impl WorldState {
|
||||||
pub fn new() -> WorldState {
|
pub fn new() -> WorldState {
|
||||||
WorldState {
|
WorldState {
|
||||||
updates: Vec::new(),
|
|
||||||
data: Arc::new(WorldData::default()),
|
data: Arc::new(WorldData::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot(
|
pub fn snapshot(
|
||||||
&mut self,
|
&self,
|
||||||
file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync,
|
file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync,
|
||||||
) -> World {
|
) -> World {
|
||||||
let needs_reindex = self.updates.len() >= INDEXING_THRESHOLD;
|
|
||||||
if !self.updates.is_empty() {
|
|
||||||
let updates = mem::replace(&mut self.updates, Vec::new());
|
|
||||||
let data = self.data_mut();
|
|
||||||
for file_id in updates {
|
|
||||||
let syntax = data.file_map
|
|
||||||
.get(&file_id)
|
|
||||||
.map(|it| it.syntax());
|
|
||||||
data.module_map.update_file(
|
|
||||||
file_id,
|
|
||||||
syntax,
|
|
||||||
&file_resolver,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
World {
|
World {
|
||||||
needs_reindex: AtomicBool::new(needs_reindex),
|
needs_reindex: AtomicBool::new(false),
|
||||||
file_resolver: Arc::new(file_resolver),
|
file_resolver: Arc::new(file_resolver),
|
||||||
data: self.data.clone()
|
data: self.data.clone()
|
||||||
}
|
}
|
||||||
|
@ -115,21 +96,26 @@ impl WorldState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
|
pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) {
|
||||||
let mut updates = Vec::new();
|
let data = self.data_mut();
|
||||||
{
|
for (file_id, text) in changes {
|
||||||
let data = self.data_mut();
|
let change_kind = if data.file_map.remove(&file_id).is_some() {
|
||||||
for (file_id, text) in changes {
|
if text.is_some() {
|
||||||
data.file_map.remove(&file_id);
|
ChangeKind::Update
|
||||||
if let Some(text) = text {
|
|
||||||
let file_data = FileData::new(text);
|
|
||||||
data.file_map.insert(file_id, Arc::new(file_data));
|
|
||||||
} else {
|
} else {
|
||||||
data.file_map.remove(&file_id);
|
ChangeKind::Delete
|
||||||
}
|
}
|
||||||
updates.push(file_id);
|
} else {
|
||||||
|
ChangeKind::Insert
|
||||||
|
};
|
||||||
|
data.module_map.update_file(file_id, change_kind);
|
||||||
|
data.file_map.remove(&file_id);
|
||||||
|
if let Some(text) = text {
|
||||||
|
let file_data = FileData::new(text);
|
||||||
|
data.file_map.insert(file_id, Arc::new(file_data));
|
||||||
|
} else {
|
||||||
|
data.file_map.remove(&file_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.updates.extend(updates)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_mut(&mut self) -> &mut WorldData {
|
fn data_mut(&mut self) -> &mut WorldData {
|
||||||
|
@ -171,13 +157,17 @@ impl World {
|
||||||
let module_map = &self.data.module_map;
|
let module_map = &self.data.module_map;
|
||||||
let id = module_map.file2module(id);
|
let id = module_map.file2module(id);
|
||||||
module_map
|
module_map
|
||||||
.parent_modules(id)
|
.parent_modules(
|
||||||
|
id,
|
||||||
|
&*self.file_resolver,
|
||||||
|
&|file_id| self.file_syntax(file_id).unwrap(),
|
||||||
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, m)| {
|
.map(|(id, name, node)| {
|
||||||
let id = module_map.module2file(id);
|
let id = module_map.module2file(id);
|
||||||
let sym = FileSymbol {
|
let sym = FileSymbol {
|
||||||
name: m.name().unwrap().text(),
|
name,
|
||||||
node_range: m.syntax().range(),
|
node_range: node.range(),
|
||||||
kind: MODULE,
|
kind: MODULE,
|
||||||
};
|
};
|
||||||
(id, sym)
|
(id, sym)
|
||||||
|
@ -235,7 +225,11 @@ impl World {
|
||||||
let module_map = &self.data.module_map;
|
let module_map = &self.data.module_map;
|
||||||
let id = module_map.file2module(id);
|
let id = module_map.file2module(id);
|
||||||
module_map
|
module_map
|
||||||
.child_module_by_name(id, name.as_str())
|
.child_module_by_name(
|
||||||
|
id, name.as_str(),
|
||||||
|
&*self.file_resolver,
|
||||||
|
&|file_id| self.file_syntax(file_id).unwrap(),
|
||||||
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|id| module_map.module2file(id))
|
.map(|id| module_map.module2file(id))
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -2,17 +2,38 @@ use std::{
|
||||||
path::{PathBuf},
|
path::{PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
ast::{self, AstNode, NameOwner},
|
ast::{self, AstNode, NameOwner, ParsedFile},
|
||||||
SyntaxNode, ParsedFile, SmolStr,
|
SyntaxNode, SmolStr,
|
||||||
};
|
};
|
||||||
use {FileId, FileResolver};
|
use {FileId, FileResolver};
|
||||||
|
|
||||||
|
type SyntaxProvider<'a> = dyn Fn(FileId) -> ParsedFile + 'a;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct ModuleId(FileId);
|
pub struct ModuleId(FileId);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ModuleMap {
|
pub struct ModuleMap {
|
||||||
|
state: RwLock<State>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ChangeKind {
|
||||||
|
Delete, Insert, Update
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ModuleMap {
|
||||||
|
fn clone(&self) -> ModuleMap {
|
||||||
|
let state = self.state.read().clone();
|
||||||
|
ModuleMap { state: RwLock::new(state) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
struct State {
|
||||||
|
changes: Vec<(FileId, ChangeKind)>,
|
||||||
links: Vec<Link>,
|
links: Vec<Link>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,31 +45,8 @@ struct Link {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleMap {
|
impl ModuleMap {
|
||||||
pub fn update_file(
|
pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) {
|
||||||
&mut self,
|
self.state.get_mut().changes.push((file, change_kind));
|
||||||
file_id: FileId,
|
|
||||||
syntax: Option<&ParsedFile>,
|
|
||||||
file_resolver: &FileResolver,
|
|
||||||
) {
|
|
||||||
let mod_id = ModuleId(file_id);
|
|
||||||
self.links.retain(|link| link.owner != mod_id);
|
|
||||||
match syntax {
|
|
||||||
None => {
|
|
||||||
for link in self.links.iter_mut() {
|
|
||||||
link.points_to.retain(|&x| x != mod_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(syntax) => {
|
|
||||||
self.links.extend(
|
|
||||||
syntax.ast().modules().filter_map(|it| {
|
|
||||||
Link::new(mod_id, it)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.links.iter_mut().for_each(|link| {
|
|
||||||
link.resolve(file_resolver)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module2file(&self, m: ModuleId) -> FileId {
|
pub fn module2file(&self, m: ModuleId) -> FileId {
|
||||||
|
@ -59,8 +57,15 @@ impl ModuleMap {
|
||||||
ModuleId(file_id)
|
ModuleId(file_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child_module_by_name(&self, parent_mod: ModuleId, child_mod: &str) -> Vec<ModuleId> {
|
pub fn child_module_by_name<'a>(
|
||||||
self.links
|
&self,
|
||||||
|
parent_mod: ModuleId,
|
||||||
|
child_mod: &str,
|
||||||
|
file_resolver: &FileResolver,
|
||||||
|
syntax_provider: &SyntaxProvider,
|
||||||
|
) -> Vec<ModuleId> {
|
||||||
|
self.links(file_resolver, syntax_provider)
|
||||||
|
.links
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|link| link.owner == parent_mod)
|
.filter(|link| link.owner == parent_mod)
|
||||||
.filter(|link| link.name() == child_mod)
|
.filter(|link| link.name() == child_mod)
|
||||||
|
@ -69,13 +74,90 @@ impl ModuleMap {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent_modules<'a>(&'a self, m: ModuleId) -> impl Iterator<Item=(ModuleId, ast::Module<'a>)> + 'a {
|
pub fn parent_modules(
|
||||||
self.links
|
&self,
|
||||||
|
m: ModuleId,
|
||||||
|
file_resolver: &FileResolver,
|
||||||
|
syntax_provider: &SyntaxProvider,
|
||||||
|
) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
|
||||||
|
let links = self.links(file_resolver, syntax_provider);
|
||||||
|
let res = links
|
||||||
|
.links
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |link| link.points_to.iter().any(|&it| it == m))
|
.filter(move |link| link.points_to.iter().any(|&it| it == m))
|
||||||
.map(|link| {
|
.map(|link| {
|
||||||
(link.owner, link.ast())
|
(link.owner, link.name().clone(), link.syntax.clone())
|
||||||
})
|
})
|
||||||
|
.collect();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn links(
|
||||||
|
&self,
|
||||||
|
file_resolver: &FileResolver,
|
||||||
|
syntax_provider: &SyntaxProvider,
|
||||||
|
) -> RwLockReadGuard<State> {
|
||||||
|
{
|
||||||
|
let guard = self.state.read();
|
||||||
|
if guard.changes.is_empty() {
|
||||||
|
return guard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut guard = self.state.write();
|
||||||
|
if !guard.changes.is_empty() {
|
||||||
|
guard.apply_changes(file_resolver, syntax_provider);
|
||||||
|
}
|
||||||
|
assert!(guard.changes.is_empty());
|
||||||
|
RwLockWriteGuard::downgrade(guard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn apply_changes(
|
||||||
|
&mut self,
|
||||||
|
file_resolver: &FileResolver,
|
||||||
|
syntax_provider: &SyntaxProvider,
|
||||||
|
) {
|
||||||
|
let mut reresolve = false;
|
||||||
|
for (file_id, kind) in self.changes.drain(..) {
|
||||||
|
let mod_id = ModuleId(file_id);
|
||||||
|
self.links.retain(|link| link.owner != mod_id);
|
||||||
|
match kind {
|
||||||
|
ChangeKind::Delete => {
|
||||||
|
for link in self.links.iter_mut() {
|
||||||
|
link.points_to.retain(|&x| x != mod_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChangeKind::Insert => {
|
||||||
|
let file = syntax_provider(file_id);
|
||||||
|
self.links.extend(
|
||||||
|
file
|
||||||
|
.ast()
|
||||||
|
.modules()
|
||||||
|
.filter_map(|it| Link::new(mod_id, it))
|
||||||
|
);
|
||||||
|
reresolve = true;
|
||||||
|
}
|
||||||
|
ChangeKind::Update => {
|
||||||
|
let file = syntax_provider(file_id);
|
||||||
|
self.links.extend(
|
||||||
|
file
|
||||||
|
.ast()
|
||||||
|
.modules()
|
||||||
|
.filter_map(|it| Link::new(mod_id, it))
|
||||||
|
.map(|mut link| {
|
||||||
|
link.resolve(file_resolver);
|
||||||
|
link
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reresolve {
|
||||||
|
for link in self.links.iter_mut() {
|
||||||
|
link.resolve(file_resolver)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ fn on_notification(
|
||||||
fn handle_request_on_threadpool<R: req::ClientRequest>(
|
fn handle_request_on_threadpool<R: req::ClientRequest>(
|
||||||
req: &mut Option<RawRequest>,
|
req: &mut Option<RawRequest>,
|
||||||
pool: &ThreadPool,
|
pool: &ThreadPool,
|
||||||
world: &mut ServerWorldState,
|
world: &ServerWorldState,
|
||||||
sender: &Sender<Task>,
|
sender: &Sender<Task>,
|
||||||
f: fn(ServerWorld, R::Params) -> Result<R::Result>,
|
f: fn(ServerWorld, R::Params) -> Result<R::Result>,
|
||||||
) -> Result<()>
|
) -> Result<()>
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl ServerWorldState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot(&mut self) -> ServerWorld {
|
pub fn snapshot(&self) -> ServerWorld {
|
||||||
let pm = self.path_map.clone();
|
let pm = self.path_map.clone();
|
||||||
ServerWorld {
|
ServerWorld {
|
||||||
analysis: self.analysis.snapshot(move |id, path| {
|
analysis: self.analysis.snapshot(move |id, path| {
|
||||||
|
|
Loading…
Reference in a new issue