From 85290bc1342560d5560f0b2151cff1c0c6dac155 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Dec 2018 12:20:54 +0300 Subject: switch analysis to vfs --- crates/ra_analysis/src/db.rs | 2 - crates/ra_analysis/src/imp.rs | 88 +++++++++++++++--------------- crates/ra_analysis/src/lib.rs | 96 +++++++++++++++++++++++++-------- crates/ra_analysis/src/mock_analysis.rs | 8 +-- crates/ra_db/src/input.rs | 22 +++----- crates/ra_db/src/lib.rs | 2 +- crates/ra_db/src/mock.rs | 7 +-- crates/ra_hir/src/module/imp.rs | 17 ++++-- 8 files changed, 142 insertions(+), 100 deletions(-) (limited to 'crates') diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index 9f39d3a59..b79baf037 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs @@ -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; diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index e2c20b0e3..51bcd5a73 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -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 = 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); diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 22fff71ab..bfc4e0f17 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -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, files_changed: Vec<(FileId, String)>, - files_removed: Vec<(FileId)>, libraries_added: Vec, crate_graph: Option, - file_resolver: Option, +} + +#[derive(Default)] +struct RootChange { + added: Vec, + removed: Vec, +} + +#[derive(Debug)] +struct AddFile { + file_id: FileId, + path: RelativePathBuf, + text: Arc, +} + +#[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, + ) { + 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) { - 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) -> 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)>, + ) -> 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, } } diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs index 0d9a7a147..691af4a48 100644 --- a/crates/ra_analysis/src/mock_analysis.rs +++ b/crates/ra_analysis/src/mock_analysis.rs @@ -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 } diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 65b674da9..51daa8e86 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -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> { - type SourceRootFilesQuery; - storage input; - } - fn source_root_file_by_path(id: SourceRootId, path: RelativePathBuf) -> Option { - type SourceRootFileByPathQuery; - storage input; - } fn source_root(id: SourceRootId) -> Arc { 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, + pub files: FxHashMap, } - -pub const WORKSPACE: SourceRootId = SourceRootId(0); diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 783b7a799..d1db281e6 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -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}, }; diff --git a/crates/ra_db/src/mock.rs b/crates/ra_db/src/mock.rs index 14d9e79b5..efe987bdd 100644 --- a/crates/ra_db/src/mock.rs +++ b/crates/ra_db/src/mock.rs @@ -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 { self.iter().map(|(id, _)| id).collect() } diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs index d04d24a61..f3a346152 100644 --- a/crates/ra_hir/src/module/imp.rs +++ b/crates/ra_hir/src/module/imp.rs @@ -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::>(); 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 -- cgit v1.2.3