switch analysis to vfs
This commit is contained in:
parent
815a0e5778
commit
85290bc134
@ -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;
|
||||
|
@ -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>);
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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},
|
||||
};
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user