diff --git a/Cargo.lock b/Cargo.lock index b4d466fb63..5113317b02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -607,6 +607,7 @@ dependencies = [ "id-arena 1.0.2 (git+https://github.com/fitzgen/id-arena/?rev=43ecd67)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ra_db 0.1.0", "ra_editor 0.1.0", "ra_syntax 0.1.0", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -628,6 +629,21 @@ dependencies = [ "tools 0.1.0", ] +[[package]] +name = "ra_db" +version = "0.1.0" +dependencies = [ + "id-arena 1.0.2 (git+https://github.com/fitzgen/id-arena/?rev=43ecd67)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ra_editor 0.1.0", + "ra_syntax 0.1.0", + "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "salsa 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "test_utils 0.1.0", +] + [[package]] name = "ra_editor" version = "0.1.0" diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml index 5dae458575..48d8e56e37 100644 --- a/crates/ra_analysis/Cargo.toml +++ b/crates/ra_analysis/Cargo.toml @@ -15,4 +15,5 @@ parking_lot = "0.6.4" id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } ra_syntax = { path = "../ra_syntax" } ra_editor = { path = "../ra_editor" } +ra_db = { path = "../ra_db" } test_utils = { path = "../test_utils" } diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index 844dabb192..538b51633f 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs @@ -7,10 +7,11 @@ use ra_syntax::{ AstNode, AtomEdit, SyntaxNodeRef, }; +use ra_db::SyntaxDatabase; use rustc_hash::{FxHashMap}; use crate::{ - db::{self, SyntaxDatabase}, + db, hir, Cancelable, FilePosition }; diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index e0b7afac55..1b2dd4b3da 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs @@ -1,15 +1,13 @@ use std::sync::Arc; #[cfg(test)] use parking_lot::Mutex; -use ra_editor::LineIndex; -use ra_syntax::{SourceFileNode}; use salsa::{self, Database}; +use ra_db::{LocationIntener, BaseDatabase}; use crate::{ hir, symbol_index, - loc2id::{IdMaps, LocationIntener, DefId, DefLoc, FnId}, - Cancelable, Canceled, FileId, + loc2id::{IdMaps, DefId, DefLoc, FnId}, }; #[derive(Debug)] @@ -47,11 +45,11 @@ impl Default for RootDatabase { runtime: salsa::Runtime::default(), id_maps: Default::default(), }; - db.query_mut(crate::input::SourceRootQuery) - .set(crate::input::WORKSPACE, Default::default()); - db.query_mut(crate::input::CrateGraphQuery) + db.query_mut(ra_db::SourceRootQuery) + .set(ra_db::WORKSPACE, Default::default()); + db.query_mut(ra_db::CrateGraphQuery) .set((), Default::default()); - db.query_mut(crate::input::LibrariesQuery) + db.query_mut(ra_db::LibrariesQuery) .set((), Default::default()); db } @@ -67,22 +65,7 @@ impl salsa::ParallelDatabase for RootDatabase { } } -pub(crate) trait BaseDatabase: salsa::Database { - fn id_maps(&self) -> &IdMaps; - fn check_canceled(&self) -> Cancelable<()> { - if self.salsa_runtime().is_current_revision_canceled() { - Err(Canceled) - } else { - Ok(()) - } - } -} - -impl BaseDatabase for RootDatabase { - fn id_maps(&self) -> &IdMaps { - &self.id_maps - } -} +impl BaseDatabase for RootDatabase {} impl AsRef> for RootDatabase { fn as_ref(&self) -> &LocationIntener { @@ -121,16 +104,16 @@ impl RootDatabase { salsa::database_storage! { pub(crate) struct RootDatabaseStorage for RootDatabase { - impl crate::input::FilesDatabase { - fn file_text() for crate::input::FileTextQuery; - fn file_source_root() for crate::input::FileSourceRootQuery; - fn source_root() for crate::input::SourceRootQuery; - fn libraries() for crate::input::LibrariesQuery; - fn crate_graph() for crate::input::CrateGraphQuery; + impl ra_db::FilesDatabase { + fn file_text() for ra_db::FileTextQuery; + fn file_source_root() for ra_db::FileSourceRootQuery; + fn source_root() for ra_db::SourceRootQuery; + fn libraries() for ra_db::LibrariesQuery; + fn crate_graph() for ra_db::CrateGraphQuery; } - impl SyntaxDatabase { - fn source_file() for SourceFileQuery; - fn file_lines() for FileLinesQuery; + impl ra_db::SyntaxDatabase { + fn source_file() for ra_db::SourceFileQuery; + fn file_lines() for ra_db::FileLinesQuery; } impl symbol_index::SymbolsDatabase { fn file_symbols() for symbol_index::FileSymbolsQuery; @@ -148,23 +131,3 @@ salsa::database_storage! { } } } - -salsa::query_group! { - pub(crate) trait SyntaxDatabase: crate::input::FilesDatabase + BaseDatabase { - fn source_file(file_id: FileId) -> SourceFileNode { - type SourceFileQuery; - } - fn file_lines(file_id: FileId) -> Arc { - type FileLinesQuery; - } - } -} - -fn source_file(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode { - let text = db.file_text(file_id); - SourceFileNode::parse(&*text) -} -fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc { - let text = db.file_text(file_id); - Arc::new(LineIndex::new(&*text)) -} diff --git a/crates/ra_analysis/src/hir/db.rs b/crates/ra_analysis/src/hir/db.rs index bf0dc393ab..0ae2086ff6 100644 --- a/crates/ra_analysis/src/hir/db.rs +++ b/crates/ra_analysis/src/hir/db.rs @@ -4,10 +4,10 @@ use ra_syntax::{ SyntaxNode, ast::FnDefNode, }; +use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase}; use crate::{ FileId, - db::SyntaxDatabase, hir::{ SourceFileItems, SourceItemId, query_definitions, @@ -15,8 +15,7 @@ use crate::{ module::{ModuleId, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems}}, }, - input::SourceRootId, - loc2id::{DefLoc, DefId, FnId, LocationIntener}, + loc2id::{DefLoc, DefId, FnId}, Cancelable, }; diff --git a/crates/ra_analysis/src/hir/function/scope.rs b/crates/ra_analysis/src/hir/function/scope.rs index 76b2fea68b..ed789fede2 100644 --- a/crates/ra_analysis/src/hir/function/scope.rs +++ b/crates/ra_analysis/src/hir/function/scope.rs @@ -5,9 +5,10 @@ use ra_syntax::{ algo::generate, ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, }; +use ra_db::LocalSyntaxPtr; use crate::{ - syntax_ptr::LocalSyntaxPtr, + arena::{Arena, Id}, }; diff --git a/crates/ra_analysis/src/hir/module/imp.rs b/crates/ra_analysis/src/hir/module/imp.rs index d51ca2d59a..c8f7ed58d1 100644 --- a/crates/ra_analysis/src/hir/module/imp.rs +++ b/crates/ra_analysis/src/hir/module/imp.rs @@ -6,11 +6,11 @@ use ra_syntax::{ }; use relative_path::RelativePathBuf; use rustc_hash::{FxHashMap, FxHashSet}; +use ra_db::{SourceRoot, SourceRootId, FileResolverImp}; use crate::{ hir::HirDatabase, - input::{SourceRoot, SourceRootId}, - Cancelable, FileId, FileResolverImp, + Cancelable, FileId, }; use super::{ diff --git a/crates/ra_analysis/src/hir/module/mod.rs b/crates/ra_analysis/src/hir/module/mod.rs index 893ec3a104..683cb5d4c0 100644 --- a/crates/ra_analysis/src/hir/module/mod.rs +++ b/crates/ra_analysis/src/hir/module/mod.rs @@ -10,12 +10,12 @@ use ra_syntax::{ ast::{self, AstNode, NameOwner}, SmolStr, SyntaxNode, }; +use ra_db::SourceRootId; use relative_path::RelativePathBuf; use crate::{ FileId, FilePosition, Cancelable, hir::{Path, PathKind, HirDatabase, SourceItemId}, - input::SourceRootId, arena::{Arena, Id}, loc2id::{DefLoc, DefId}, }; diff --git a/crates/ra_analysis/src/hir/module/nameres.rs b/crates/ra_analysis/src/hir/module/nameres.rs index f48f51c8df..5c87e7af20 100644 --- a/crates/ra_analysis/src/hir/module/nameres.rs +++ b/crates/ra_analysis/src/hir/module/nameres.rs @@ -19,12 +19,12 @@ use std::{ }; use rustc_hash::FxHashMap; - use ra_syntax::{ TextRange, SmolStr, SyntaxKind::{self, *}, ast::{self, AstNode} }; +use ra_db::SourceRootId; use crate::{ Cancelable, FileId, @@ -35,7 +35,6 @@ use crate::{ HirDatabase, module::{ModuleId, ModuleTree}, }, - input::SourceRootId, }; /// Item map is the result of the name resolution. Item map contains, for each @@ -342,11 +341,11 @@ where #[cfg(test)] mod tests { + use ra_db::FilesDatabase; use crate::{ AnalysisChange, mock_analysis::{MockAnalysis, analysis_and_position}, hir::{self, HirDatabase}, - input::FilesDatabase, }; use super::*; diff --git a/crates/ra_analysis/src/hir/query_definitions.rs b/crates/ra_analysis/src/hir/query_definitions.rs index 6570ca994b..fbdf8eb678 100644 --- a/crates/ra_analysis/src/hir/query_definitions.rs +++ b/crates/ra_analysis/src/hir/query_definitions.rs @@ -8,6 +8,7 @@ use ra_syntax::{ AstNode, SyntaxNode, SmolStr, ast::{self, FnDef, FnDefNode, NameOwner, ModuleItemOwner} }; +use ra_db::SourceRootId; use crate::{ FileId, Cancelable, @@ -21,7 +22,6 @@ use crate::{ nameres::{InputModuleItems, ItemMap, Resolver}, }, }, - input::SourceRootId, }; /// Resolve `FnId` to the corresponding `SyntaxNode` diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index c86bc111a5..9a86942214 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -1,6 +1,5 @@ use std::{ fmt, - hash::{Hash, Hasher}, sync::Arc, }; @@ -11,84 +10,24 @@ use ra_syntax::{ SyntaxKind::*, SyntaxNodeRef, TextRange, TextUnit, }; +use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase, SourceFileQuery}; use rayon::prelude::*; -use relative_path::RelativePath; use rustc_hash::FxHashSet; use salsa::{Database, ParallelDatabase}; use crate::{ completion::{completions, CompletionItem}, - db::{self, SourceFileQuery, SyntaxDatabase}, + db, hir::{ self, FnSignatureInfo, Problem, }, - input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, symbol_index::{SymbolIndex, SymbolsDatabase}, - AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver, + AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, }; -#[derive(Clone, Debug)] -pub(crate) struct FileResolverImp { - inner: Arc, -} - -impl PartialEq for FileResolverImp { - fn eq(&self, other: &FileResolverImp) -> bool { - self.inner() == other.inner() - } -} - -impl Eq for FileResolverImp {} - -impl Hash for FileResolverImp { - fn hash(&self, hasher: &mut H) { - self.inner().hash(hasher); - } -} - -impl FileResolverImp { - pub(crate) fn new(inner: Arc) -> 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 { - self.inner.resolve(file_id, path) - } - pub(crate) fn debug_path(&self, file_id: FileId) -> Option { - self.inner.debug_path(file_id) - } - fn inner(&self) -> *const FileResolver { - &*self.inner - } -} - -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 { - panic!("file resolver not set") - } - } - FileResolverImp { - inner: Arc::new(DummyResolver), - } - } -} - #[derive(Debug, Default)] pub(crate) struct AnalysisHostImpl { db: db::RootDatabase, @@ -105,7 +44,7 @@ impl AnalysisHostImpl { for (file_id, text) in change.files_changed { self.db - .query_mut(crate::input::FileTextQuery) + .query_mut(ra_db::FileTextQuery) .set(file_id, Arc::new(text)) } if !(change.files_added.is_empty() && change.files_removed.is_empty()) { @@ -115,22 +54,22 @@ impl AnalysisHostImpl { let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE)); for (file_id, text) in change.files_added { self.db - .query_mut(crate::input::FileTextQuery) + .query_mut(ra_db::FileTextQuery) .set(file_id, Arc::new(text)); self.db - .query_mut(crate::input::FileSourceRootQuery) - .set(file_id, crate::input::WORKSPACE); + .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(crate::input::FileTextQuery) + .query_mut(ra_db::FileTextQuery) .set(file_id, Arc::new(String::new())); source_root.files.remove(&file_id); } source_root.file_resolver = file_resolver; self.db - .query_mut(crate::input::SourceRootQuery) + .query_mut(ra_db::SourceRootQuery) .set(WORKSPACE, Arc::new(source_root)) } if !change.libraries_added.is_empty() { @@ -147,10 +86,10 @@ impl AnalysisHostImpl { library.file_resolver.debug_path(file_id) ); self.db - .query_mut(crate::input::FileSourceRootQuery) + .query_mut(ra_db::FileSourceRootQuery) .set_constant(file_id, source_root_id); self.db - .query_mut(crate::input::FileTextQuery) + .query_mut(ra_db::FileTextQuery) .set_constant(file_id, Arc::new(text)); } let source_root = SourceRoot { @@ -158,19 +97,19 @@ impl AnalysisHostImpl { file_resolver: library.file_resolver, }; self.db - .query_mut(crate::input::SourceRootQuery) + .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)); } self.db - .query_mut(crate::input::LibrariesQuery) + .query_mut(ra_db::LibrariesQuery) .set((), Arc::new(libraries)); } if let Some(crate_graph) = change.crate_graph { self.db - .query_mut(crate::input::CrateGraphQuery) + .query_mut(ra_db::CrateGraphQuery) .set((), Arc::new(crate_graph)) } } @@ -261,7 +200,7 @@ impl AnalysisImpl { Ok(crate_id.into_iter().collect()) } pub fn crate_root(&self, crate_id: CrateId) -> FileId { - self.db.crate_graph().crate_roots[&crate_id] + self.db.crate_graph().crate_root(crate_id) } pub fn completions(&self, position: FilePosition) -> Cancelable>> { completions(&self.db, position) @@ -546,16 +485,6 @@ impl SourceChange { } } -impl CrateGraph { - fn crate_id_for_crate_root(&self, file_id: FileId) -> Option { - let (&crate_id, _) = self - .crate_roots - .iter() - .find(|(_crate_id, &root_id)| root_id == file_id)?; - Some(crate_id) - } -} - enum FnCallNode<'a> { CallExpr(ast::CallExpr<'a>), MethodCallExpr(ast::MethodCallExpr<'a>), diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index c0e43544ea..012d36b8ed 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -19,8 +19,6 @@ macro_rules! ctry { } mod arena; -mod syntax_ptr; -mod input; mod db; mod loc2id; mod imp; @@ -32,35 +30,27 @@ pub mod mock_analysis; use std::{fmt, sync::Arc}; use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit}; +use ra_db::FileResolverImp; use rayon::prelude::*; use relative_path::RelativePathBuf; use crate::{ - imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}, + imp::{AnalysisHostImpl, AnalysisImpl}, symbol_index::SymbolIndex, }; pub use crate::{ completion::CompletionItem, hir::FnSignatureInfo, - input::{CrateGraph, CrateId, FileId, FileResolver}, }; pub use ra_editor::{ FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode, }; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Canceled; - -pub type Cancelable = Result; - -impl std::fmt::Display for Canceled { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt.write_str("Canceled") - } -} - -impl std::error::Error for Canceled {} +pub use ra_db::{ + Canceled, Cancelable, + CrateGraph, CrateId, FileId, FileResolver +}; #[derive(Default)] pub struct AnalysisChange { diff --git a/crates/ra_analysis/src/loc2id.rs b/crates/ra_analysis/src/loc2id.rs index 2aa1411301..7956431ab0 100644 --- a/crates/ra_analysis/src/loc2id.rs +++ b/crates/ra_analysis/src/loc2id.rs @@ -1,74 +1,10 @@ -use parking_lot::Mutex; - -use std::hash::Hash; - -use rustc_hash::FxHashMap; +use ra_db::SourceRootId; use crate::{ hir::{SourceItemId, ModuleId}, - input::SourceRootId, }; -/// There are two principle ways to refer to things: -/// - by their locatinon (module in foo/bar/baz.rs at line 42) -/// - by their numeric id (module `ModuleId(42)`) -/// -/// The first one is more powerful (you can actually find the thing in question -/// by id), but the second one is so much more compact. -/// -/// `Loc2IdMap` allows us to have a cake an eat it as well: by maintaining a -/// bidirectional mapping between positional and numeric ids, we can use compact -/// representation wich still allows us to get the actual item -#[derive(Debug)] -struct Loc2IdMap -where - ID: NumericId, - LOC: Clone + Eq + Hash, -{ - loc2id: FxHashMap, - id2loc: FxHashMap, -} - -impl Default for Loc2IdMap -where - ID: NumericId, - LOC: Clone + Eq + Hash, -{ - fn default() -> Self { - Loc2IdMap { - loc2id: FxHashMap::default(), - id2loc: FxHashMap::default(), - } - } -} - -impl Loc2IdMap -where - ID: NumericId, - LOC: Clone + Eq + Hash, -{ - pub fn loc2id(&mut self, loc: &LOC) -> ID { - match self.loc2id.get(loc) { - Some(id) => return id.clone(), - None => (), - } - let id = self.loc2id.len(); - assert!(id < u32::max_value() as usize); - let id = ID::from_u32(id as u32); - self.loc2id.insert(loc.clone(), id.clone()); - self.id2loc.insert(id.clone(), loc.clone()); - id - } - - pub fn id2loc(&self, id: ID) -> LOC { - self.id2loc[&id].clone() - } -} - -pub(crate) trait NumericId: Clone + Eq + Hash { - fn from_u32(id: u32) -> Self; - fn to_u32(self) -> u32; -} +use ra_db::{NumericId, LocationIntener}; macro_rules! impl_numeric_id { ($id:ident) => { @@ -131,37 +67,3 @@ pub(crate) struct IdMaps { pub(crate) fns: LocationIntener, pub(crate) defs: LocationIntener, } - -#[derive(Debug)] -pub(crate) struct LocationIntener -where - ID: NumericId, - LOC: Clone + Eq + Hash, -{ - map: Mutex>, -} - -impl Default for LocationIntener -where - ID: NumericId, - LOC: Clone + Eq + Hash, -{ - fn default() -> Self { - LocationIntener { - map: Default::default(), - } - } -} - -impl LocationIntener -where - ID: NumericId, - LOC: Clone + Eq + Hash, -{ - fn loc2id(&self, loc: &LOC) -> ID { - self.map.lock().loc2id(loc) - } - fn id2loc(&self, id: ID) -> LOC { - self.map.lock().id2loc(id) - } -} diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 747b34e387..b48a372298 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs @@ -9,13 +9,12 @@ use ra_syntax::{ SourceFileNode, SyntaxKind::{self, *}, }; +use ra_db::{SyntaxDatabase, SourceRootId}; use rayon::prelude::*; use crate::{ Cancelable, FileId, Query, - db::SyntaxDatabase, - input::SourceRootId, }; salsa::query_group! { diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 8e78560277..fbe89f4448 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs @@ -126,7 +126,7 @@ fn test_resolve_crate_root() { let mut host = mock.analysis_host(); assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); - let mut crate_graph = CrateGraph::new(); + let mut crate_graph = CrateGraph::default(); let crate_id = crate_graph.add_crate_root(root_file); let mut change = AnalysisChange::new(); change.set_crate_graph(crate_graph); diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml new file mode 100644 index 0000000000..3bf2f635e7 --- /dev/null +++ b/crates/ra_db/Cargo.toml @@ -0,0 +1,16 @@ +[package] +edition = "2018" +name = "ra_db" +version = "0.1.0" +authors = ["Aleksey Kladov "] + +[dependencies] +log = "0.4.5" +relative-path = "0.4.0" +salsa = "0.8.0" +rustc-hash = "1.0" +parking_lot = "0.6.4" +id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } +ra_syntax = { path = "../ra_syntax" } +ra_editor = { path = "../ra_editor" } +test_utils = { path = "../test_utils" } diff --git a/crates/ra_db/src/file_resolver.rs b/crates/ra_db/src/file_resolver.rs new file mode 100644 index 0000000000..f849ac7521 --- /dev/null +++ b/crates/ra_db/src/file_resolver.rs @@ -0,0 +1,76 @@ +use std::{ + sync::Arc, + hash::{Hash, Hasher}, + fmt, +}; + +use relative_path::RelativePath; + +use crate::input::FileId; + +pub trait FileResolver: fmt::Debug + Send + Sync + 'static { + fn file_stem(&self, file_id: FileId) -> String; + fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option; + fn debug_path(&self, _1file_id: FileId) -> Option { + None + } +} + +#[derive(Clone, Debug)] +pub struct FileResolverImp { + inner: Arc, +} + +impl PartialEq for FileResolverImp { + fn eq(&self, other: &FileResolverImp) -> bool { + self.inner() == other.inner() + } +} + +impl Eq for FileResolverImp {} + +impl Hash for FileResolverImp { + fn hash(&self, hasher: &mut H) { + self.inner().hash(hasher); + } +} + +impl FileResolverImp { + pub fn new(inner: Arc) -> FileResolverImp { + FileResolverImp { inner } + } + pub fn file_stem(&self, file_id: FileId) -> String { + self.inner.file_stem(file_id) + } + pub fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option { + self.inner.resolve(file_id, path) + } + pub fn debug_path(&self, file_id: FileId) -> Option { + self.inner.debug_path(file_id) + } + fn inner(&self) -> *const FileResolver { + &*self.inner + } +} + +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 { + panic!("file resolver not set") + } + } + FileResolverImp { + inner: Arc::new(DummyResolver), + } + } +} diff --git a/crates/ra_analysis/src/input.rs b/crates/ra_db/src/input.rs similarity index 67% rename from crates/ra_analysis/src/input.rs rename to crates/ra_db/src/input.rs index e601cd58a7..9101ac7a8a 100644 --- a/crates/ra_analysis/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -1,11 +1,10 @@ -use std::{fmt, sync::Arc}; +use std::sync::Arc; -use relative_path::RelativePath; use rustc_hash::FxHashMap; use rustc_hash::FxHashSet; use salsa; -use crate::FileResolverImp; +use crate::file_resolver::FileResolverImp; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FileId(pub u32); @@ -19,8 +18,8 @@ pub struct CrateGraph { } impl CrateGraph { - pub fn new() -> CrateGraph { - CrateGraph::default() + pub fn crate_root(&self, crate_id: CrateId) -> FileId { + self.crate_roots[&crate_id] } pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { let crate_id = CrateId(self.crate_roots.len() as u32); @@ -28,18 +27,17 @@ impl CrateGraph { assert!(prev.is_none()); crate_id } -} - -pub trait FileResolver: fmt::Debug + Send + Sync + 'static { - fn file_stem(&self, file_id: FileId) -> String; - fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option; - fn debug_path(&self, _1file_id: FileId) -> Option { - None + pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option { + let (&crate_id, _) = self + .crate_roots + .iter() + .find(|(_crate_id, &root_id)| root_id == file_id)?; + Some(crate_id) } } salsa::query_group! { - pub(crate) trait FilesDatabase: salsa::Database { + pub trait FilesDatabase: salsa::Database { fn file_text(file_id: FileId) -> Arc { type FileTextQuery; storage input; @@ -64,12 +62,12 @@ salsa::query_group! { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub(crate) struct SourceRootId(pub(crate) u32); +pub struct SourceRootId(pub u32); #[derive(Default, Clone, Debug, PartialEq, Eq)] -pub(crate) struct SourceRoot { - pub(crate) file_resolver: FileResolverImp, - pub(crate) files: FxHashSet, +pub struct SourceRoot { + pub file_resolver: FileResolverImp, + pub files: FxHashSet, } -pub(crate) const WORKSPACE: SourceRootId = SourceRootId(0); +pub const WORKSPACE: SourceRootId = SourceRootId(0); diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs new file mode 100644 index 0000000000..833f95eeb0 --- /dev/null +++ b/crates/ra_db/src/lib.rs @@ -0,0 +1,69 @@ +//! ra_db defines basic database traits. Concrete DB is defined by ra_analysis. + +extern crate ra_editor; +extern crate ra_syntax; +extern crate relative_path; +extern crate rustc_hash; +extern crate salsa; + +mod syntax_ptr; +mod file_resolver; +mod input; +mod loc2id; + +use std::sync::Arc; +use ra_editor::LineIndex; +use ra_syntax::SourceFileNode; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Canceled; + +pub type Cancelable = Result; + +impl std::fmt::Display for Canceled { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fmt.write_str("Canceled") + } +} + +impl std::error::Error for Canceled {} + +pub use crate::{ + syntax_ptr::LocalSyntaxPtr, + file_resolver::{FileResolver, FileResolverImp}, + input::{ + FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, WORKSPACE, + FileTextQuery, FileSourceRootQuery, SourceRootQuery, LibrariesQuery, CrateGraphQuery, + }, + loc2id::{LocationIntener, NumericId}, +}; + +pub trait BaseDatabase: salsa::Database { + fn check_canceled(&self) -> Cancelable<()> { + if self.salsa_runtime().is_current_revision_canceled() { + Err(Canceled) + } else { + Ok(()) + } + } +} + +salsa::query_group! { + pub trait SyntaxDatabase: crate::input::FilesDatabase + BaseDatabase { + fn source_file(file_id: FileId) -> SourceFileNode { + type SourceFileQuery; + } + fn file_lines(file_id: FileId) -> Arc { + type FileLinesQuery; + } + } +} + +fn source_file(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode { + let text = db.file_text(file_id); + SourceFileNode::parse(&*text) +} +fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc { + let text = db.file_text(file_id); + Arc::new(LineIndex::new(&*text)) +} diff --git a/crates/ra_db/src/loc2id.rs b/crates/ra_db/src/loc2id.rs new file mode 100644 index 0000000000..69ba43d0f7 --- /dev/null +++ b/crates/ra_db/src/loc2id.rs @@ -0,0 +1,100 @@ +use parking_lot::Mutex; + +use std::hash::Hash; + +use rustc_hash::FxHashMap; + +/// There are two principle ways to refer to things: +/// - by their locatinon (module in foo/bar/baz.rs at line 42) +/// - by their numeric id (module `ModuleId(42)`) +/// +/// The first one is more powerful (you can actually find the thing in question +/// by id), but the second one is so much more compact. +/// +/// `Loc2IdMap` allows us to have a cake an eat it as well: by maintaining a +/// bidirectional mapping between positional and numeric ids, we can use compact +/// representation wich still allows us to get the actual item +#[derive(Debug)] +struct Loc2IdMap +where + ID: NumericId, + LOC: Clone + Eq + Hash, +{ + loc2id: FxHashMap, + id2loc: FxHashMap, +} + +impl Default for Loc2IdMap +where + ID: NumericId, + LOC: Clone + Eq + Hash, +{ + fn default() -> Self { + Loc2IdMap { + loc2id: FxHashMap::default(), + id2loc: FxHashMap::default(), + } + } +} + +impl Loc2IdMap +where + ID: NumericId, + LOC: Clone + Eq + Hash, +{ + pub fn loc2id(&mut self, loc: &LOC) -> ID { + match self.loc2id.get(loc) { + Some(id) => return id.clone(), + None => (), + } + let id = self.loc2id.len(); + assert!(id < u32::max_value() as usize); + let id = ID::from_u32(id as u32); + self.loc2id.insert(loc.clone(), id.clone()); + self.id2loc.insert(id.clone(), loc.clone()); + id + } + + pub fn id2loc(&self, id: ID) -> LOC { + self.id2loc[&id].clone() + } +} + +pub trait NumericId: Clone + Eq + Hash { + fn from_u32(id: u32) -> Self; + fn to_u32(self) -> u32; +} + +#[derive(Debug)] +pub struct LocationIntener +where + ID: NumericId, + LOC: Clone + Eq + Hash, +{ + map: Mutex>, +} + +impl Default for LocationIntener +where + ID: NumericId, + LOC: Clone + Eq + Hash, +{ + fn default() -> Self { + LocationIntener { + map: Default::default(), + } + } +} + +impl LocationIntener +where + ID: NumericId, + LOC: Clone + Eq + Hash, +{ + pub fn loc2id(&self, loc: &LOC) -> ID { + self.map.lock().loc2id(loc) + } + pub fn id2loc(&self, id: ID) -> LOC { + self.map.lock().id2loc(id) + } +} diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs similarity index 84% rename from crates/ra_analysis/src/syntax_ptr.rs rename to crates/ra_db/src/syntax_ptr.rs index f4b05fc19b..dac94dd36d 100644 --- a/crates/ra_analysis/src/syntax_ptr.rs +++ b/crates/ra_db/src/syntax_ptr.rs @@ -2,20 +2,20 @@ use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange /// A pionter to a syntax node inside a file. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct LocalSyntaxPtr { +pub struct LocalSyntaxPtr { range: TextRange, kind: SyntaxKind, } impl LocalSyntaxPtr { - pub(crate) fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { + pub fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { LocalSyntaxPtr { range: node.range(), kind: node.kind(), } } - pub(crate) fn resolve(self, file: &SourceFileNode) -> SyntaxNode { + pub fn resolve(self, file: &SourceFileNode) -> SyntaxNode { let mut curr = file.syntax(); loop { if curr.range() == self.range && curr.kind() == self.kind { @@ -28,7 +28,7 @@ impl LocalSyntaxPtr { } } - pub(crate) fn range(self) -> TextRange { + pub fn range(self) -> TextRange { self.range } } diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 3e7670fcce..12faeb93af 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -140,7 +140,7 @@ impl ServerWorldState { Ok(file_id) } pub fn set_workspaces(&mut self, ws: Vec) { - let mut crate_graph = CrateGraph::new(); + let mut crate_graph = CrateGraph::default(); ws.iter() .flat_map(|ws| { ws.packages()