store file rsovler
This commit is contained in:
parent
4f64709666
commit
505895a25f
@ -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>>,
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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))
|
||||||
|
@ -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)],
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user