store file rsovler

This commit is contained in:
Aleksey Kladov 2018-09-10 12:57:40 +03:00
parent 4f64709666
commit 505895a25f
7 changed files with 146 additions and 116 deletions

View File

@ -7,6 +7,7 @@
collections::{HashSet, VecDeque}, collections::{HashSet, VecDeque},
}; };
use relative_path::RelativePath;
use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit};
use libsyntax2::{ use libsyntax2::{
TextUnit, TextRange, SmolStr, File, AstNode, TextUnit, TextRange, SmolStr, File, AstNode,
@ -21,6 +22,40 @@
roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
}; };
#[derive(Clone, Debug)]
pub(crate) struct FileResolverImp {
inner: Arc<FileResolver>
}
impl FileResolverImp {
pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp {
FileResolverImp { inner }
}
pub(crate) fn file_stem(&self, file_id: FileId) -> String {
self.inner.file_stem(file_id)
}
pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> {
self.inner.resolve(file_id, path)
}
}
impl Default for FileResolverImp {
fn default() -> FileResolverImp {
#[derive(Debug)]
struct DummyResolver;
impl FileResolver for DummyResolver {
fn file_stem(&self, _file_: FileId) -> String {
panic!("file resolver not set")
}
fn resolve(&self, _file_id: FileId, _path: &::relative_path::RelativePath) -> Option<FileId> {
panic!("file resolver not set")
}
}
FileResolverImp { inner: Arc::new(DummyResolver) }
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct AnalysisHostImpl { pub(crate) struct AnalysisHostImpl {
data: Arc<WorldData> data: Arc<WorldData>
@ -32,13 +67,9 @@ pub fn new() -> AnalysisHostImpl {
data: Arc::new(WorldData::default()), data: Arc::new(WorldData::default()),
} }
} }
pub fn analysis( pub fn analysis(&self) -> AnalysisImpl {
&self,
file_resolver: Arc<dyn FileResolver>,
) -> AnalysisImpl {
AnalysisImpl { AnalysisImpl {
needs_reindex: AtomicBool::new(false), needs_reindex: AtomicBool::new(false),
file_resolver,
data: self.data.clone(), data: self.data.clone(),
} }
} }
@ -48,6 +79,11 @@ pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<S
data.root.update(file_id, text); data.root.update(file_id, text);
} }
} }
pub fn set_file_resolver(&mut self, resolver: FileResolverImp) {
let data = self.data_mut();
data.file_resolver = resolver.clone();
data.root.set_file_resolver(resolver);
}
pub fn set_crate_graph(&mut self, graph: CrateGraph) { pub fn set_crate_graph(&mut self, graph: CrateGraph) {
let mut visited = HashSet::new(); let mut visited = HashSet::new();
for &file_id in graph.crate_roots.values() { for &file_id in graph.crate_roots.values() {
@ -67,7 +103,6 @@ fn data_mut(&mut self) -> &mut WorldData {
pub(crate) struct AnalysisImpl { pub(crate) struct AnalysisImpl {
needs_reindex: AtomicBool, needs_reindex: AtomicBool,
file_resolver: Arc<dyn FileResolver>,
data: Arc<WorldData>, data: Arc<WorldData>,
} }
@ -81,7 +116,6 @@ impl Clone for AnalysisImpl {
fn clone(&self) -> AnalysisImpl { fn clone(&self) -> AnalysisImpl {
AnalysisImpl { AnalysisImpl {
needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)), needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
file_resolver: Arc::clone(&self.file_resolver),
data: Arc::clone(&self.data), data: Arc::clone(&self.data),
} }
} }
@ -117,11 +151,7 @@ pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
let module_map = root.module_map(); let module_map = root.module_map();
let id = module_map.file2module(file_id); let id = module_map.file2module(file_id);
module_map module_map
.parent_modules( .parent_modules(id, &|file_id| root.syntax(file_id))
id,
&*self.file_resolver,
&|file_id| root.syntax(file_id),
)
.into_iter() .into_iter()
.map(|(id, name, node)| { .map(|(id, name, node)| {
let id = module_map.module2file(id); let id = module_map.module2file(id);
@ -149,11 +179,7 @@ pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
} }
let mid = module_map.file2module(id); let mid = module_map.file2module(id);
let parents = module_map let parents = module_map
.parent_module_ids( .parent_module_ids(mid, &|file_id| self.file_syntax(file_id))
mid,
&*self.file_resolver,
&|file_id| self.file_syntax(file_id),
)
.into_iter() .into_iter()
.map(|id| module_map.module2file(id)) .map(|id| module_map.module2file(id))
.filter(|&id| visited.insert(id)); .filter(|&id| visited.insert(id));
@ -213,7 +239,6 @@ pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
module_map.problems( module_map.problems(
file_id, file_id,
&*self.file_resolver,
&|file_id| self.file_syntax(file_id), &|file_id| self.file_syntax(file_id),
|name_node, problem| { |name_node, problem| {
let diag = match problem { let diag = match problem {
@ -291,7 +316,6 @@ fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::M
module_map module_map
.child_module_by_name( .child_module_by_name(
id, name.as_str(), id, name.as_str(),
&*self.file_resolver,
&|file_id| self.file_syntax(file_id), &|file_id| self.file_syntax(file_id),
) )
.into_iter() .into_iter()
@ -306,8 +330,9 @@ fn reindex(&self) {
} }
} }
#[derive(Clone, Default, Debug)] #[derive(Default, Clone, Debug)]
struct WorldData { struct WorldData {
file_resolver: FileResolverImp,
crate_graph: CrateGraph, crate_graph: CrateGraph,
root: WritableSourceRoot, root: WritableSourceRoot,
libs: Vec<Arc<ReadonlySourceRoot>>, libs: Vec<Arc<ReadonlySourceRoot>>,

View File

@ -19,11 +19,12 @@
use std::{ use std::{
sync::Arc, sync::Arc,
collections::HashMap, collections::HashMap,
fmt::Debug,
}; };
use relative_path::{RelativePath, RelativePathBuf}; use relative_path::{RelativePath, RelativePathBuf};
use libsyntax2::{File, TextRange, TextUnit, AtomEdit}; use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
use imp::{AnalysisImpl, AnalysisHostImpl}; use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
pub use libeditor::{ pub use libeditor::{
StructureNode, LineIndex, FileSymbol, StructureNode, LineIndex, FileSymbol,
@ -42,9 +43,9 @@ pub struct CrateGraph {
pub crate_roots: HashMap<CrateId, FileId>, pub crate_roots: HashMap<CrateId, FileId>,
} }
pub trait FileResolver: Send + Sync + 'static { pub trait FileResolver: Debug + Send + Sync + 'static {
fn file_stem(&self, id: FileId) -> String; fn file_stem(&self, file_id: FileId) -> String;
fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>; fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>;
} }
#[derive(Debug)] #[derive(Debug)]
@ -56,8 +57,8 @@ impl AnalysisHost {
pub fn new() -> AnalysisHost { pub fn new() -> AnalysisHost {
AnalysisHost { imp: AnalysisHostImpl::new() } AnalysisHost { imp: AnalysisHostImpl::new() }
} }
pub fn analysis(&self, file_resolver: impl FileResolver) -> Analysis { pub fn analysis(&self) -> Analysis {
Analysis { imp: self.imp.analysis(Arc::new(file_resolver)) } Analysis { imp: self.imp.analysis() }
} }
pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
self.change_files(::std::iter::once((file_id, text))); self.change_files(::std::iter::once((file_id, text)));
@ -65,6 +66,9 @@ pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) {
self.imp.change_files(&mut changes) self.imp.change_files(&mut changes)
} }
pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) {
self.imp.set_file_resolver(FileResolverImp::new(resolver));
}
pub fn set_crate_graph(&mut self, graph: CrateGraph) { pub fn set_crate_graph(&mut self, graph: CrateGraph) {
self.imp.set_crate_graph(graph) self.imp.set_crate_graph(graph)
} }
@ -223,8 +227,9 @@ pub struct LibraryData {
} }
impl LibraryData { impl LibraryData {
pub fn prepare(files: Vec<(FileId, String)>) -> LibraryData { pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData {
let root = roots::ReadonlySourceRoot::new(files); let file_resolver = FileResolverImp::new(file_resolver);
let root = roots::ReadonlySourceRoot::new(files, file_resolver);
LibraryData { root } LibraryData { root }
} }
} }

View File

@ -1,12 +1,11 @@
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use libsyntax2::{ use libsyntax2::{
File, File,
ast::{self, AstNode, NameOwner}, ast::{self, AstNode, NameOwner},
SyntaxNode, SmolStr, SyntaxNode, SmolStr,
}; };
use {FileId, FileResolver}; use {FileId, imp::FileResolverImp};
type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a; type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a;
@ -32,6 +31,7 @@ fn clone(&self) -> ModuleMap {
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct State { struct State {
file_resolver: FileResolverImp,
changes: Vec<(FileId, ChangeKind)>, changes: Vec<(FileId, ChangeKind)>,
links: Vec<Link>, links: Vec<Link>,
} }
@ -59,27 +59,25 @@ impl ModuleMap {
pub fn new() -> ModuleMap { pub fn new() -> ModuleMap {
Default::default() Default::default()
} }
pub fn update_file(&mut self, file_id: FileId, change_kind: ChangeKind) {
pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) { self.state.get_mut().changes.push((file_id, change_kind));
self.state.get_mut().changes.push((file, change_kind)); }
pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) {
self.state.get_mut().file_resolver = file_resolver;
} }
pub fn module2file(&self, m: ModuleId) -> FileId { pub fn module2file(&self, m: ModuleId) -> FileId {
m.0 m.0
} }
pub fn file2module(&self, file_id: FileId) -> ModuleId { pub fn file2module(&self, file_id: FileId) -> ModuleId {
ModuleId(file_id) ModuleId(file_id)
} }
pub fn child_module_by_name<'a>( pub fn child_module_by_name<'a>(
&self, &self,
parent_mod: ModuleId, parent_mod: ModuleId,
child_mod: &str, child_mod: &str,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
) -> Vec<ModuleId> { ) -> Vec<ModuleId> {
self.links(file_resolver, syntax_provider) self.links(syntax_provider)
.links .links
.iter() .iter()
.filter(|link| link.owner == parent_mod) .filter(|link| link.owner == parent_mod)
@ -92,11 +90,10 @@ pub fn child_module_by_name<'a>(
pub fn parent_modules( pub fn parent_modules(
&self, &self,
m: ModuleId, m: ModuleId,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
let mut res = Vec::new(); let mut res = Vec::new();
self.for_each_parent_link(m, file_resolver, syntax_provider, |link| { self.for_each_parent_link(m, syntax_provider, |link| {
res.push( res.push(
(link.owner, link.name().clone(), link.syntax.clone()) (link.owner, link.name().clone(), link.syntax.clone())
) )
@ -107,22 +104,20 @@ pub fn parent_modules(
pub fn parent_module_ids( pub fn parent_module_ids(
&self, &self,
m: ModuleId, m: ModuleId,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
) -> Vec<ModuleId> { ) -> Vec<ModuleId> {
let mut res = Vec::new(); let mut res = Vec::new();
self.for_each_parent_link(m, file_resolver, syntax_provider, |link| res.push(link.owner)); self.for_each_parent_link(m, syntax_provider, |link| res.push(link.owner));
res res
} }
fn for_each_parent_link( fn for_each_parent_link(
&self, &self,
m: ModuleId, m: ModuleId,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
f: impl FnMut(&Link) f: impl FnMut(&Link)
) { ) {
self.links(file_resolver, syntax_provider) self.links(syntax_provider)
.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))
@ -132,12 +127,11 @@ fn for_each_parent_link(
pub fn problems( pub fn problems(
&self, &self,
file: FileId, file: FileId,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
mut cb: impl FnMut(ast::Name, &Problem), mut cb: impl FnMut(ast::Name, &Problem),
) { ) {
let module = self.file2module(file); let module = self.file2module(file);
let links = self.links(file_resolver, syntax_provider); let links = self.links(syntax_provider);
links links
.links .links
.iter() .iter()
@ -151,7 +145,6 @@ pub fn problems(
fn links( fn links(
&self, &self,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
) -> RwLockReadGuard<State> { ) -> RwLockReadGuard<State> {
{ {
@ -162,7 +155,7 @@ fn links(
} }
let mut guard = self.state.write(); let mut guard = self.state.write();
if !guard.changes.is_empty() { if !guard.changes.is_empty() {
guard.apply_changes(file_resolver, syntax_provider); guard.apply_changes(syntax_provider);
} }
assert!(guard.changes.is_empty()); assert!(guard.changes.is_empty());
RwLockWriteGuard::downgrade(guard) RwLockWriteGuard::downgrade(guard)
@ -172,7 +165,6 @@ fn links(
impl State { impl State {
pub fn apply_changes( pub fn apply_changes(
&mut self, &mut self,
file_resolver: &FileResolver,
syntax_provider: &SyntaxProvider, syntax_provider: &SyntaxProvider,
) { ) {
let mut reresolve = false; let mut reresolve = false;
@ -197,13 +189,14 @@ pub fn apply_changes(
} }
ChangeKind::Update => { ChangeKind::Update => {
let file = syntax_provider(file_id); let file = syntax_provider(file_id);
let resolver = &self.file_resolver;
self.links.extend( self.links.extend(
file file
.ast() .ast()
.modules() .modules()
.filter_map(|it| Link::new(mod_id, it)) .filter_map(|it| Link::new(mod_id, it))
.map(|mut link| { .map(|mut link| {
link.resolve(file_resolver); link.resolve(resolver);
link link
}) })
); );
@ -212,7 +205,7 @@ pub fn apply_changes(
} }
if reresolve { if reresolve {
for link in self.links.iter_mut() { for link in self.links.iter_mut() {
link.resolve(file_resolver) link.resolve(&self.file_resolver)
} }
} }
} }
@ -245,7 +238,7 @@ fn ast(&self) -> ast::Module {
.unwrap() .unwrap()
} }
fn resolve(&mut self, file_resolver: &FileResolver) { fn resolve(&mut self, file_resolver: &FileResolverImp) {
if !self.ast().has_semi() { if !self.ast().has_semi() {
self.problem = None; self.problem = None;
self.points_to = Vec::new(); self.points_to = Vec::new();

View File

@ -12,6 +12,7 @@
use { use {
FileId, FileId,
imp::FileResolverImp,
module_map::{ModuleMap, ChangeKind}, module_map::{ModuleMap, ChangeKind},
symbol_index::SymbolIndex, symbol_index::SymbolIndex,
}; };
@ -48,6 +49,9 @@ pub fn update(&mut self, file_id: FileId, text: Option<String>) {
self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); self.file_map.insert(file_id, Arc::new((file_data, Default::default())));
} }
} }
pub fn set_file_resolver(&mut self, file_resolver: FileResolverImp) {
self.module_map.set_file_resolver(file_resolver)
}
pub fn reindex(&self) { pub fn reindex(&self) {
let now = Instant::now(); let now = Instant::now();
self.file_map self.file_map
@ -136,8 +140,9 @@ pub(crate) struct ReadonlySourceRoot {
} }
impl ReadonlySourceRoot { impl ReadonlySourceRoot {
pub fn new(files: Vec<(FileId, String)>) -> ReadonlySourceRoot { pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot {
let mut module_map = ModuleMap::new(); let mut module_map = ModuleMap::new();
module_map.set_file_resolver(file_resolver);
let symbol_index = SymbolIndex::for_files( let symbol_index = SymbolIndex::for_files(
files.par_iter().map(|(file_id, text)| { files.par_iter().map(|(file_id, text)| {
(*file_id, File::parse(text)) (*file_id, File::parse(text))

View File

@ -3,21 +3,38 @@
extern crate test_utils; extern crate test_utils;
use std::{ use std::{
sync::Arc,
collections::HashMap, collections::HashMap,
}; };
use relative_path::{RelativePath}; use relative_path::{RelativePath, RelativePathBuf};
use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId}; use libanalysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId};
use test_utils::assert_eq_dbg; use test_utils::assert_eq_dbg;
struct FileMap(&'static [(u32, &'static str)]); #[derive(Debug)]
struct FileMap(Vec<(FileId, RelativePathBuf)>);
fn analysis_host(files: &'static [(&'static str, &'static str)]) -> AnalysisHost {
let mut host = AnalysisHost::new();
let mut file_map = Vec::new();
for (id, &(path, contents)) in files.iter().enumerate() {
let file_id = FileId((id + 1) as u32);
assert!(path.starts_with('/'));
let path = RelativePathBuf::from_path(&path[1..]).unwrap();
host.change_file(file_id, Some(contents.to_string()));
file_map.push((file_id, path));
}
host.set_file_resolver(Arc::new(FileMap(file_map)));
host
}
fn analysis(files: &'static [(&'static str, &'static str)]) -> Analysis {
analysis_host(files).analysis()
}
impl FileMap { impl FileMap {
fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a { fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a {
self.0.iter().map(|&(id, path)| { self.0.iter().map(|(id, path)| (*id, path.as_relative_path()))
assert!(path.starts_with('/'));
(FileId(id), RelativePath::new(&path[1..]))
})
} }
fn path(&self, id: FileId) -> &RelativePath { fn path(&self, id: FileId) -> &RelativePath {
@ -42,14 +59,10 @@ fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> {
#[test] #[test]
fn test_resolve_module() { fn test_resolve_module() {
let mut world = AnalysisHost::new(); let snap = analysis(&[
world.change_file(FileId(1), Some("mod foo;".to_string())); ("/lib.rs", "mod foo;"),
world.change_file(FileId(2), Some("".to_string())); ("/foo.rs", "")
]);
let snap = world.analysis(FileMap(&[
(1, "/lib.rs"),
(2, "/foo.rs"),
]));
let (_handle, token) = JobHandle::new(); let (_handle, token) = JobHandle::new();
let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
assert_eq_dbg( assert_eq_dbg(
@ -57,10 +70,10 @@ fn test_resolve_module() {
&symbols, &symbols,
); );
let snap = world.analysis(FileMap(&[ let snap = analysis(&[
(1, "/lib.rs"), ("/lib.rs", "mod foo;"),
(2, "/foo/mod.rs") ("/foo/mod.rs", "")
])); ]);
let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
assert_eq_dbg( assert_eq_dbg(
r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
@ -70,10 +83,7 @@ fn test_resolve_module() {
#[test] #[test]
fn test_unresolved_module_diagnostic() { fn test_unresolved_module_diagnostic() {
let mut world = AnalysisHost::new(); let snap = analysis(&[("/lib.rs", "mod foo;")]);
world.change_file(FileId(1), Some("mod foo;".to_string()));
let snap = world.analysis(FileMap(&[(1, "/lib.rs")]));
let diagnostics = snap.diagnostics(FileId(1)); let diagnostics = snap.diagnostics(FileId(1));
assert_eq_dbg( assert_eq_dbg(
r#"[Diagnostic { r#"[Diagnostic {
@ -90,10 +100,7 @@ fn test_unresolved_module_diagnostic() {
#[test] #[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
let mut world = AnalysisHost::new(); let snap = analysis(&[("/lib.rs", "mod foo {}")]);
world.change_file(FileId(1), Some("mod foo {}".to_string()));
let snap = world.analysis(FileMap(&[(1, "/lib.rs")]));
let diagnostics = snap.diagnostics(FileId(1)); let diagnostics = snap.diagnostics(FileId(1));
assert_eq_dbg( assert_eq_dbg(
r#"[]"#, r#"[]"#,
@ -103,14 +110,10 @@ fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
#[test] #[test]
fn test_resolve_parent_module() { fn test_resolve_parent_module() {
let mut world = AnalysisHost::new(); let snap = analysis(&[
world.change_file(FileId(1), Some("mod foo;".to_string())); ("/lib.rs", "mod foo;"),
world.change_file(FileId(2), Some("".to_string())); ("/foo.rs", ""),
]);
let snap = world.analysis(FileMap(&[
(1, "/lib.rs"),
(2, "/foo.rs"),
]));
let symbols = snap.parent_module(FileId(2)); let symbols = snap.parent_module(FileId(2));
assert_eq_dbg( assert_eq_dbg(
r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
@ -120,14 +123,11 @@ fn test_resolve_parent_module() {
#[test] #[test]
fn test_resolve_crate_root() { fn test_resolve_crate_root() {
let mut world = AnalysisHost::new(); let mut host = analysis_host(&[
world.change_file(FileId(1), Some("mod foo;".to_string())); ("/lib.rs", "mod foo;"),
world.change_file(FileId(2), Some("".to_string())); ("/foo.rs", ""),
]);
let snap = world.analysis(FileMap(&[ let snap = host.analysis();
(1, "/lib.rs"),
(2, "/foo.rs"),
]));
assert!(snap.crate_for(FileId(2)).is_empty()); assert!(snap.crate_for(FileId(2)).is_empty());
let crate_graph = CrateGraph { let crate_graph = CrateGraph {
@ -137,12 +137,9 @@ fn test_resolve_crate_root() {
m m
}, },
}; };
world.set_crate_graph(crate_graph); host.set_crate_graph(crate_graph);
let snap = host.analysis();
let snap = world.analysis(FileMap(&[
(1, "/lib.rs"),
(2, "/foo.rs"),
]));
assert_eq!( assert_eq!(
snap.crate_for(FileId(2)), snap.crate_for(FileId(2)),
vec![CrateId(1)], vec![CrateId(1)],

View File

@ -135,12 +135,12 @@ enum Event {
if root == ws_root { if root == ws_root {
state.apply_fs_changes(events); state.apply_fs_changes(events);
} else { } else {
let files = state.events_to_files(events); let (files, resolver) = state.events_to_files(events);
let sender = libdata_sender.clone(); let sender = libdata_sender.clone();
pool.spawn(move || { pool.spawn(move || {
let start = ::std::time::Instant::now(); let start = ::std::time::Instant::now();
info!("indexing {} ... ", root.display()); info!("indexing {} ... ", root.display());
let data = LibraryData::prepare(files); let data = LibraryData::prepare(files, resolver);
info!("indexed {:?} {}", start.elapsed(), root.display()); info!("indexed {:?} {}", start.elapsed(), root.display());
sender.send(data); sender.send(data);
}); });

View File

@ -6,7 +6,7 @@
}; };
use languageserver_types::Url; use languageserver_types::Url;
use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData}; use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver};
use { use {
Result, Result,
@ -64,17 +64,21 @@ pub fn apply_fs_changes(&mut self, events: Vec<FileEvent>) {
self.analysis_host.change_files(changes); self.analysis_host.change_files(changes);
} }
pub fn events_to_files(&mut self, events: Vec<FileEvent>) -> Vec<(FileId, String)> { pub fn events_to_files(&mut self, events: Vec<FileEvent>) -> (Vec<(FileId, String)>, Arc<FileResolver>) {
let pm = &mut self.path_map; let files = {
events.into_iter() let pm = &mut self.path_map;
.map(|event| { events.into_iter()
let text = match event.kind { .map(|event| {
FileEventKind::Add(text) => text, let text = match event.kind {
}; FileEventKind::Add(text) => text,
(event.path, text) };
}) (event.path, text)
.map(|(path, text)| (pm.get_or_insert(path, Root::Lib), text)) })
.collect() .map(|(path, text)| (pm.get_or_insert(path, Root::Lib), text))
.collect()
};
let resolver = Arc::new(self.path_map.clone());
(files, resolver)
} }
pub fn add_lib(&mut self, data: LibraryData) { pub fn add_lib(&mut self, data: LibraryData) {
self.analysis_host.add_library(data); self.analysis_host.add_library(data);
@ -82,6 +86,7 @@ pub fn add_lib(&mut self, data: LibraryData) {
pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId {
let file_id = self.path_map.get_or_insert(path, Root::Workspace); let file_id = self.path_map.get_or_insert(path, Root::Workspace);
self.analysis_host.set_file_resolver(Arc::new(self.path_map.clone()));
self.mem_map.insert(file_id, None); self.mem_map.insert(file_id, None);
if self.path_map.get_root(file_id) != Root::Lib { if self.path_map.get_root(file_id) != Root::Lib {
self.analysis_host.change_file(file_id, Some(text)); self.analysis_host.change_file(file_id, Some(text));
@ -135,7 +140,7 @@ pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
pub fn snapshot(&self) -> ServerWorld { pub fn snapshot(&self) -> ServerWorld {
ServerWorld { ServerWorld {
workspaces: Arc::clone(&self.workspaces), workspaces: Arc::clone(&self.workspaces),
analysis: self.analysis_host.analysis(self.path_map.clone()), analysis: self.analysis_host.analysis(),
path_map: self.path_map.clone() path_map: self.path_map.clone()
} }
} }