switch analysis to vfs

This commit is contained in:
Aleksey Kladov 2018-12-19 12:20:54 +03:00
parent 815a0e5778
commit 85290bc134
8 changed files with 142 additions and 100 deletions

View file

@ -63,8 +63,6 @@ salsa::database_storage! {
fn file_text() for ra_db::FileTextQuery;
fn file_relative_path() for ra_db::FileRelativePathQuery;
fn file_source_root() for ra_db::FileSourceRootQuery;
fn source_root_files() for ra_db::SourceRootFilesQuery;
fn source_root_file_by_path() for ra_db::SourceRootFileByPathQuery;
fn source_root() for ra_db::SourceRootQuery;
fn libraries() for ra_db::LibrariesQuery;
fn crate_graph() for ra_db::CrateGraphQuery;

View file

@ -12,7 +12,6 @@ use ra_syntax::{
};
use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase};
use rayon::prelude::*;
use rustc_hash::FxHashSet;
use salsa::{Database, ParallelDatabase};
use hir::{
self,
@ -25,7 +24,7 @@ use crate::{
completion::{completions, CompletionItem},
db,
symbol_index::{SymbolIndex, SymbolsDatabase},
AnalysisChange, Cancelable, CrateId, Diagnostic, FileId,
AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId,
FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
ReferenceResolution,
};
@ -45,59 +44,22 @@ impl AnalysisHostImpl {
log::info!("apply_change {:?}", change);
// self.gc_syntax_trees();
for (root_id, root_change) in change.roots_changed {
self.apply_root_change(root_id, root_change);
}
for (file_id, text) in change.files_changed {
self.db
.query_mut(ra_db::FileTextQuery)
.set(file_id, Arc::new(text))
}
if !(change.files_added.is_empty() && change.files_removed.is_empty()) {
let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
for (file_id, text) in change.files_added {
self.db
.query_mut(ra_db::FileTextQuery)
.set(file_id, Arc::new(text));
self.db
.query_mut(ra_db::FileSourceRootQuery)
.set(file_id, ra_db::WORKSPACE);
source_root.files.insert(file_id);
}
for file_id in change.files_removed {
self.db
.query_mut(ra_db::FileTextQuery)
.set(file_id, Arc::new(String::new()));
source_root.files.remove(&file_id);
}
self.db
.query_mut(ra_db::SourceRootQuery)
.set(WORKSPACE, Arc::new(source_root))
}
if !change.libraries_added.is_empty() {
let mut libraries = Vec::clone(&self.db.libraries());
for library in change.libraries_added {
let source_root_id = SourceRootId(1 + libraries.len() as u32);
libraries.push(source_root_id);
let mut files = FxHashSet::default();
for (file_id, text) in library.files {
files.insert(file_id);
log::debug!(
"library file: {:?} {:?}",
file_id,
library.file_resolver.debug_path(file_id)
);
self.db
.query_mut(ra_db::FileSourceRootQuery)
.set_constant(file_id, source_root_id);
self.db
.query_mut(ra_db::FileTextQuery)
.set_constant(file_id, Arc::new(text));
}
let source_root = SourceRoot { files };
libraries.push(library.root_id);
self.db
.query_mut(ra_db::SourceRootQuery)
.set(source_root_id, Arc::new(source_root));
self.db
.query_mut(crate::symbol_index::LibrarySymbolsQuery)
.set(source_root_id, Arc::new(library.symbol_index));
.set(library.root_id, Default::default());
self.apply_root_change(library.root_id, library.root_change);
}
self.db
.query_mut(ra_db::LibrariesQuery)
@ -110,6 +72,34 @@ impl AnalysisHostImpl {
}
}
fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
let mut source_root = SourceRoot::clone(&self.db.source_root(root_id));
for add_file in root_change.added {
self.db
.query_mut(ra_db::FileTextQuery)
.set(add_file.file_id, add_file.text);
self.db
.query_mut(ra_db::FileRelativePathQuery)
.set(add_file.file_id, add_file.path.clone());
self.db
.query_mut(ra_db::FileSourceRootQuery)
.set(add_file.file_id, root_id);
source_root.files.insert(add_file.path, add_file.file_id);
}
for remove_file in root_change.removed {
self.db
.query_mut(ra_db::FileTextQuery)
.set(remove_file.file_id, Default::default());
self.db
.query_mut(ra_db::FileRelativePathQuery)
.set(remove_file.file_id, Default::default());
source_root.files.remove(&remove_file.path);
}
self.db
.query_mut(ra_db::SourceRootQuery)
.set(root_id, Arc::new(source_root));
}
#[allow(unused)]
/// Ideally, we should call this function from time to time to collect heavy
/// syntax trees. However, if we actually do that, everything is recomputed
@ -156,7 +146,13 @@ impl AnalysisImpl {
.map(|&lib_id| self.db.library_symbols(lib_id))
.collect()
} else {
let files = &self.db.source_root(WORKSPACE).files;
let files: Vec<FileId> = self
.db
.source_root(WORKSPACE)
.files
.values()
.map(|&it| it)
.collect();
/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
struct Snap(salsa::Snapshot<db::RootDatabase>);

View file

@ -18,9 +18,9 @@ pub mod mock_analysis;
use std::{fmt, sync::Arc};
use rustc_hash::FxHashMap;
use ra_syntax::{SourceFileNode, TextRange, TextUnit};
use ra_text_edit::AtomTextEdit;
use ra_db::FileResolverImp;
use rayon::prelude::*;
use relative_path::RelativePathBuf;
@ -39,28 +39,53 @@ pub use hir::FnSignatureInfo;
pub use ra_db::{
Canceled, Cancelable, FilePosition,
CrateGraph, CrateId, FileId, FileResolver
CrateGraph, CrateId, SourceRootId, FileId, FileResolver,
WORKSPACE
};
#[derive(Default)]
pub struct AnalysisChange {
files_added: Vec<(FileId, String)>,
roots_changed: FxHashMap<SourceRootId, RootChange>,
files_changed: Vec<(FileId, String)>,
files_removed: Vec<(FileId)>,
libraries_added: Vec<LibraryData>,
crate_graph: Option<CrateGraph>,
file_resolver: Option<FileResolverImp>,
}
#[derive(Default)]
struct RootChange {
added: Vec<AddFile>,
removed: Vec<RemoveFile>,
}
#[derive(Debug)]
struct AddFile {
file_id: FileId,
path: RelativePathBuf,
text: Arc<String>,
}
#[derive(Debug)]
struct RemoveFile {
file_id: FileId,
path: RelativePathBuf,
}
impl fmt::Debug for AnalysisChange {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("AnalysisChange")
.field("files_added", &self.files_added.len())
.field("roots_changed", &self.roots_changed)
.field("files_changed", &self.files_changed.len())
.field("files_removed", &self.files_removed.len())
.field("libraries_added", &self.libraries_added.len())
.field("crate_graph", &self.crate_graph)
.field("file_resolver", &self.file_resolver)
.finish()
}
}
impl fmt::Debug for RootChange {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("AnalysisChange")
.field("added", &self.added.len())
.field("removed", &self.removed.len())
.finish()
}
}
@ -69,14 +94,34 @@ impl AnalysisChange {
pub fn new() -> AnalysisChange {
AnalysisChange::default()
}
pub fn add_file(&mut self, file_id: FileId, text: String) {
self.files_added.push((file_id, text))
pub fn add_file(
&mut self,
root_id: SourceRootId,
file_id: FileId,
path: RelativePathBuf,
text: Arc<String>,
) {
let file = AddFile {
file_id,
path,
text,
};
self.roots_changed
.entry(root_id)
.or_default()
.added
.push(file);
}
pub fn change_file(&mut self, file_id: FileId, new_text: String) {
self.files_changed.push((file_id, new_text))
}
pub fn remove_file(&mut self, file_id: FileId) {
self.files_removed.push(file_id)
pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
let file = RemoveFile { file_id, path };
self.roots_changed
.entry(root_id)
.or_default()
.removed
.push(file);
}
pub fn add_library(&mut self, data: LibraryData) {
self.libraries_added.push(data)
@ -84,9 +129,6 @@ impl AnalysisChange {
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
self.crate_graph = Some(graph);
}
pub fn set_file_resolver(&mut self, file_resolver: Arc<FileResolver>) {
self.file_resolver = Some(FileResolverImp::new(file_resolver));
}
}
/// `AnalysisHost` stores the current state of the world.
@ -313,20 +355,32 @@ impl Analysis {
#[derive(Debug)]
pub struct LibraryData {
files: Vec<(FileId, String)>,
file_resolver: FileResolverImp,
root_id: SourceRootId,
root_change: RootChange,
symbol_index: SymbolIndex,
}
impl LibraryData {
pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData {
let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| {
pub fn prepare(
root_id: SourceRootId,
files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
) -> LibraryData {
let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
let file = SourceFileNode::parse(text);
(*file_id, file)
}));
let mut root_change = RootChange::default();
root_change.added = files
.into_iter()
.map(|(file_id, path, text)| AddFile {
file_id,
path,
text,
})
.collect();
LibraryData {
files,
file_resolver: FileResolverImp::new(file_resolver),
root_id,
root_change,
symbol_index,
}
}

View file

@ -4,7 +4,7 @@ use relative_path::{RelativePathBuf};
use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
use ra_db::mock::FileMap;
use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition};
use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, WORKSPACE};
/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
/// from a set of in-memory files.
@ -82,10 +82,10 @@ impl MockAnalysis {
for (path, contents) in self.files.into_iter() {
assert!(path.starts_with('/'));
let path = RelativePathBuf::from_path(&path[1..]).unwrap();
let file_id = file_map.add(path);
change.add_file(file_id, contents);
let file_id = file_map.add(path.clone());
change.add_file(WORKSPACE, file_id, path, Arc::new(contents));
}
change.set_file_resolver(Arc::new(file_map));
// change.set_file_resolver(Arc::new(file_map));
host.apply_change(change);
host
}

View file

@ -1,10 +1,15 @@
use std::sync::Arc;
use rustc_hash::{FxHashSet, FxHashMap};
use rustc_hash::{FxHashMap};
use relative_path::RelativePathBuf;
use ra_syntax::SmolStr;
use salsa;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SourceRootId(pub u32);
pub const WORKSPACE: SourceRootId = SourceRootId(0);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);
@ -93,14 +98,6 @@ salsa::query_group! {
type FileSourceRootQuery;
storage input;
}
fn source_root_files(id: SourceRootId) -> Arc<FxHashSet<FileId>> {
type SourceRootFilesQuery;
storage input;
}
fn source_root_file_by_path(id: SourceRootId, path: RelativePathBuf) -> Option<FileId> {
type SourceRootFileByPathQuery;
storage input;
}
fn source_root(id: SourceRootId) -> Arc<SourceRoot> {
type SourceRootQuery;
storage input;
@ -116,12 +113,7 @@ salsa::query_group! {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SourceRootId(pub u32);
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct SourceRoot {
pub files: FxHashSet<FileId>,
pub files: FxHashMap<RelativePathBuf, FileId>,
}
pub const WORKSPACE: SourceRootId = SourceRootId(0);

View file

@ -28,7 +28,7 @@ pub use crate::{
input::{
FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, WORKSPACE,
FileTextQuery, FileSourceRootQuery, SourceRootQuery, LibrariesQuery, CrateGraphQuery,
FileRelativePathQuery, SourceRootFilesQuery, SourceRootFileByPathQuery,
FileRelativePathQuery
},
loc2id::{LocationIntener, NumericId},
};

View file

@ -1,7 +1,7 @@
use rustc_hash::FxHashSet;
use relative_path::{RelativePath, RelativePathBuf};
use crate::{FileId, FileResolver, SourceRoot};
use crate::{FileId, FileResolver};
#[derive(Default, Debug, Clone)]
pub struct FileMap(Vec<(FileId, RelativePathBuf)>);
@ -13,11 +13,6 @@ impl FileMap {
file_id
}
pub fn into_source_root(self) -> SourceRoot {
let files = self.files();
SourceRoot { files }
}
pub fn files(&self) -> FxHashSet<FileId> {
self.iter().map(|(id, _)| id).collect()
}

View file

@ -4,6 +4,7 @@ use ra_syntax::{
ast::{self, NameOwner},
SmolStr,
};
use relative_path::{RelativePathBuf, RelativePath};
use rustc_hash::{FxHashMap, FxHashSet};
use arrayvec::ArrayVec;
use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
@ -65,7 +66,7 @@ fn create_module_tree<'a>(
let mut visited = FxHashSet::default();
let source_root = db.source_root(source_root);
for &file_id in source_root.files.iter() {
for &file_id in source_root.files.values() {
let source = ModuleSource::new_file(file_id);
if visited.contains(&source) {
continue; // TODO: use explicit crate_roots here
@ -160,7 +161,8 @@ fn resolve_submodule(
let file_id = source.file_id();
let source_root_id = db.file_source_root(file_id);
let path = db.file_relative_path(file_id);
let dir_path = path.parent().unwrap();
let root = RelativePathBuf::default();
let dir_path = path.parent().unwrap_or(&root);
let mod_name = path.file_stem().unwrap_or("unknown");
let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
@ -174,14 +176,19 @@ fn resolve_submodule(
} else {
candidates.push(file_dir_mod.clone());
};
let sr = db.source_root(source_root_id);
let points_to = candidates
.into_iter()
.filter_map(|path| db.source_root_file_by_path(source_root_id, path))
.filter_map(|path| sr.files.get(&path))
.map(|&it| it)
.collect::<Vec<_>>();
let problem = if points_to.is_empty() {
Some(Problem::UnresolvedModule {
candidate: if is_dir_owner { file_mod } else { file_dir_mod },
candidate: RelativePath::new("../").join(&if is_dir_owner {
file_mod
} else {
file_dir_mod
}),
})
} else {
None