move db basics to ra_db

This should allow to move hir to a separate crate
This commit is contained in:
Aleksey Kladov 2018-11-28 03:25:20 +03:00
parent b2de95879a
commit 11168c464c
22 changed files with 352 additions and 293 deletions

16
Cargo.lock generated
View file

@ -607,6 +607,7 @@ dependencies = [
"id-arena 1.0.2 (git+https://github.com/fitzgen/id-arena/?rev=43ecd67)", "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)", "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)", "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_editor 0.1.0",
"ra_syntax 0.1.0", "ra_syntax 0.1.0",
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -628,6 +629,21 @@ dependencies = [
"tools 0.1.0", "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]] [[package]]
name = "ra_editor" name = "ra_editor"
version = "0.1.0" version = "0.1.0"

View file

@ -15,4 +15,5 @@ parking_lot = "0.6.4"
id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" }
ra_syntax = { path = "../ra_syntax" } ra_syntax = { path = "../ra_syntax" }
ra_editor = { path = "../ra_editor" } ra_editor = { path = "../ra_editor" }
ra_db = { path = "../ra_db" }
test_utils = { path = "../test_utils" } test_utils = { path = "../test_utils" }

View file

@ -7,10 +7,11 @@ use ra_syntax::{
AstNode, AtomEdit, AstNode, AtomEdit,
SyntaxNodeRef, SyntaxNodeRef,
}; };
use ra_db::SyntaxDatabase;
use rustc_hash::{FxHashMap}; use rustc_hash::{FxHashMap};
use crate::{ use crate::{
db::{self, SyntaxDatabase}, db,
hir, hir,
Cancelable, FilePosition Cancelable, FilePosition
}; };

View file

@ -1,15 +1,13 @@
use std::sync::Arc; use std::sync::Arc;
#[cfg(test)] #[cfg(test)]
use parking_lot::Mutex; use parking_lot::Mutex;
use ra_editor::LineIndex;
use ra_syntax::{SourceFileNode};
use salsa::{self, Database}; use salsa::{self, Database};
use ra_db::{LocationIntener, BaseDatabase};
use crate::{ use crate::{
hir, hir,
symbol_index, symbol_index,
loc2id::{IdMaps, LocationIntener, DefId, DefLoc, FnId}, loc2id::{IdMaps, DefId, DefLoc, FnId},
Cancelable, Canceled, FileId,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -47,11 +45,11 @@ impl Default for RootDatabase {
runtime: salsa::Runtime::default(), runtime: salsa::Runtime::default(),
id_maps: Default::default(), id_maps: Default::default(),
}; };
db.query_mut(crate::input::SourceRootQuery) db.query_mut(ra_db::SourceRootQuery)
.set(crate::input::WORKSPACE, Default::default()); .set(ra_db::WORKSPACE, Default::default());
db.query_mut(crate::input::CrateGraphQuery) db.query_mut(ra_db::CrateGraphQuery)
.set((), Default::default()); .set((), Default::default());
db.query_mut(crate::input::LibrariesQuery) db.query_mut(ra_db::LibrariesQuery)
.set((), Default::default()); .set((), Default::default());
db db
} }
@ -67,22 +65,7 @@ impl salsa::ParallelDatabase for RootDatabase {
} }
} }
pub(crate) trait BaseDatabase: salsa::Database { impl BaseDatabase for RootDatabase {}
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 AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase { impl AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase {
fn as_ref(&self) -> &LocationIntener<DefLoc, DefId> { fn as_ref(&self) -> &LocationIntener<DefLoc, DefId> {
@ -121,16 +104,16 @@ impl RootDatabase {
salsa::database_storage! { salsa::database_storage! {
pub(crate) struct RootDatabaseStorage for RootDatabase { pub(crate) struct RootDatabaseStorage for RootDatabase {
impl crate::input::FilesDatabase { impl ra_db::FilesDatabase {
fn file_text() for crate::input::FileTextQuery; fn file_text() for ra_db::FileTextQuery;
fn file_source_root() for crate::input::FileSourceRootQuery; fn file_source_root() for ra_db::FileSourceRootQuery;
fn source_root() for crate::input::SourceRootQuery; fn source_root() for ra_db::SourceRootQuery;
fn libraries() for crate::input::LibrariesQuery; fn libraries() for ra_db::LibrariesQuery;
fn crate_graph() for crate::input::CrateGraphQuery; fn crate_graph() for ra_db::CrateGraphQuery;
} }
impl SyntaxDatabase { impl ra_db::SyntaxDatabase {
fn source_file() for SourceFileQuery; fn source_file() for ra_db::SourceFileQuery;
fn file_lines() for FileLinesQuery; fn file_lines() for ra_db::FileLinesQuery;
} }
impl symbol_index::SymbolsDatabase { impl symbol_index::SymbolsDatabase {
fn file_symbols() for symbol_index::FileSymbolsQuery; 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<LineIndex> {
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<LineIndex> {
let text = db.file_text(file_id);
Arc::new(LineIndex::new(&*text))
}

View file

@ -4,10 +4,10 @@ use ra_syntax::{
SyntaxNode, SyntaxNode,
ast::FnDefNode, ast::FnDefNode,
}; };
use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase};
use crate::{ use crate::{
FileId, FileId,
db::SyntaxDatabase,
hir::{ hir::{
SourceFileItems, SourceItemId, SourceFileItems, SourceItemId,
query_definitions, query_definitions,
@ -15,8 +15,7 @@ use crate::{
module::{ModuleId, ModuleTree, ModuleSource, module::{ModuleId, ModuleTree, ModuleSource,
nameres::{ItemMap, InputModuleItems}}, nameres::{ItemMap, InputModuleItems}},
}, },
input::SourceRootId, loc2id::{DefLoc, DefId, FnId},
loc2id::{DefLoc, DefId, FnId, LocationIntener},
Cancelable, Cancelable,
}; };

View file

@ -5,9 +5,10 @@ use ra_syntax::{
algo::generate, algo::generate,
ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
}; };
use ra_db::LocalSyntaxPtr;
use crate::{ use crate::{
syntax_ptr::LocalSyntaxPtr,
arena::{Arena, Id}, arena::{Arena, Id},
}; };

View file

@ -6,11 +6,11 @@ use ra_syntax::{
}; };
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use ra_db::{SourceRoot, SourceRootId, FileResolverImp};
use crate::{ use crate::{
hir::HirDatabase, hir::HirDatabase,
input::{SourceRoot, SourceRootId}, Cancelable, FileId,
Cancelable, FileId, FileResolverImp,
}; };
use super::{ use super::{

View file

@ -10,12 +10,12 @@ use ra_syntax::{
ast::{self, AstNode, NameOwner}, ast::{self, AstNode, NameOwner},
SmolStr, SyntaxNode, SmolStr, SyntaxNode,
}; };
use ra_db::SourceRootId;
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
use crate::{ use crate::{
FileId, FilePosition, Cancelable, FileId, FilePosition, Cancelable,
hir::{Path, PathKind, HirDatabase, SourceItemId}, hir::{Path, PathKind, HirDatabase, SourceItemId},
input::SourceRootId,
arena::{Arena, Id}, arena::{Arena, Id},
loc2id::{DefLoc, DefId}, loc2id::{DefLoc, DefId},
}; };

View file

@ -19,12 +19,12 @@ use std::{
}; };
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use ra_syntax::{ use ra_syntax::{
TextRange, TextRange,
SmolStr, SyntaxKind::{self, *}, SmolStr, SyntaxKind::{self, *},
ast::{self, AstNode} ast::{self, AstNode}
}; };
use ra_db::SourceRootId;
use crate::{ use crate::{
Cancelable, FileId, Cancelable, FileId,
@ -35,7 +35,6 @@ use crate::{
HirDatabase, HirDatabase,
module::{ModuleId, ModuleTree}, module::{ModuleId, ModuleTree},
}, },
input::SourceRootId,
}; };
/// Item map is the result of the name resolution. Item map contains, for each /// Item map is the result of the name resolution. Item map contains, for each
@ -342,11 +341,11 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ra_db::FilesDatabase;
use crate::{ use crate::{
AnalysisChange, AnalysisChange,
mock_analysis::{MockAnalysis, analysis_and_position}, mock_analysis::{MockAnalysis, analysis_and_position},
hir::{self, HirDatabase}, hir::{self, HirDatabase},
input::FilesDatabase,
}; };
use super::*; use super::*;

View file

@ -8,6 +8,7 @@ use ra_syntax::{
AstNode, SyntaxNode, SmolStr, AstNode, SyntaxNode, SmolStr,
ast::{self, FnDef, FnDefNode, NameOwner, ModuleItemOwner} ast::{self, FnDef, FnDefNode, NameOwner, ModuleItemOwner}
}; };
use ra_db::SourceRootId;
use crate::{ use crate::{
FileId, Cancelable, FileId, Cancelable,
@ -21,7 +22,6 @@ use crate::{
nameres::{InputModuleItems, ItemMap, Resolver}, nameres::{InputModuleItems, ItemMap, Resolver},
}, },
}, },
input::SourceRootId,
}; };
/// Resolve `FnId` to the corresponding `SyntaxNode` /// Resolve `FnId` to the corresponding `SyntaxNode`

View file

@ -1,6 +1,5 @@
use std::{ use std::{
fmt, fmt,
hash::{Hash, Hasher},
sync::Arc, sync::Arc,
}; };
@ -11,84 +10,24 @@ use ra_syntax::{
SyntaxKind::*, SyntaxKind::*,
SyntaxNodeRef, TextRange, TextUnit, SyntaxNodeRef, TextRange, TextUnit,
}; };
use ra_db::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE, SyntaxDatabase, SourceFileQuery};
use rayon::prelude::*; use rayon::prelude::*;
use relative_path::RelativePath;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use salsa::{Database, ParallelDatabase}; use salsa::{Database, ParallelDatabase};
use crate::{ use crate::{
completion::{completions, CompletionItem}, completion::{completions, CompletionItem},
db::{self, SourceFileQuery, SyntaxDatabase}, db,
hir::{ hir::{
self, self,
FnSignatureInfo, FnSignatureInfo,
Problem, Problem,
}, },
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
symbol_index::{SymbolIndex, SymbolsDatabase}, symbol_index::{SymbolIndex, SymbolsDatabase},
AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver, AnalysisChange, Cancelable, CrateId, Diagnostic, FileId,
FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
}; };
#[derive(Clone, Debug)]
pub(crate) struct FileResolverImp {
inner: Arc<FileResolver>,
}
impl PartialEq for FileResolverImp {
fn eq(&self, other: &FileResolverImp) -> bool {
self.inner() == other.inner()
}
}
impl Eq for FileResolverImp {}
impl Hash for FileResolverImp {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.inner().hash(hasher);
}
}
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)
}
pub(crate) fn debug_path(&self, file_id: FileId) -> Option<std::path::PathBuf> {
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<FileId> {
panic!("file resolver not set")
}
}
FileResolverImp {
inner: Arc::new(DummyResolver),
}
}
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(crate) struct AnalysisHostImpl { pub(crate) struct AnalysisHostImpl {
db: db::RootDatabase, db: db::RootDatabase,
@ -105,7 +44,7 @@ impl AnalysisHostImpl {
for (file_id, text) in change.files_changed { for (file_id, text) in change.files_changed {
self.db self.db
.query_mut(crate::input::FileTextQuery) .query_mut(ra_db::FileTextQuery)
.set(file_id, Arc::new(text)) .set(file_id, Arc::new(text))
} }
if !(change.files_added.is_empty() && change.files_removed.is_empty()) { 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)); let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
for (file_id, text) in change.files_added { for (file_id, text) in change.files_added {
self.db self.db
.query_mut(crate::input::FileTextQuery) .query_mut(ra_db::FileTextQuery)
.set(file_id, Arc::new(text)); .set(file_id, Arc::new(text));
self.db self.db
.query_mut(crate::input::FileSourceRootQuery) .query_mut(ra_db::FileSourceRootQuery)
.set(file_id, crate::input::WORKSPACE); .set(file_id, ra_db::WORKSPACE);
source_root.files.insert(file_id); source_root.files.insert(file_id);
} }
for file_id in change.files_removed { for file_id in change.files_removed {
self.db self.db
.query_mut(crate::input::FileTextQuery) .query_mut(ra_db::FileTextQuery)
.set(file_id, Arc::new(String::new())); .set(file_id, Arc::new(String::new()));
source_root.files.remove(&file_id); source_root.files.remove(&file_id);
} }
source_root.file_resolver = file_resolver; source_root.file_resolver = file_resolver;
self.db self.db
.query_mut(crate::input::SourceRootQuery) .query_mut(ra_db::SourceRootQuery)
.set(WORKSPACE, Arc::new(source_root)) .set(WORKSPACE, Arc::new(source_root))
} }
if !change.libraries_added.is_empty() { if !change.libraries_added.is_empty() {
@ -147,10 +86,10 @@ impl AnalysisHostImpl {
library.file_resolver.debug_path(file_id) library.file_resolver.debug_path(file_id)
); );
self.db self.db
.query_mut(crate::input::FileSourceRootQuery) .query_mut(ra_db::FileSourceRootQuery)
.set_constant(file_id, source_root_id); .set_constant(file_id, source_root_id);
self.db self.db
.query_mut(crate::input::FileTextQuery) .query_mut(ra_db::FileTextQuery)
.set_constant(file_id, Arc::new(text)); .set_constant(file_id, Arc::new(text));
} }
let source_root = SourceRoot { let source_root = SourceRoot {
@ -158,19 +97,19 @@ impl AnalysisHostImpl {
file_resolver: library.file_resolver, file_resolver: library.file_resolver,
}; };
self.db self.db
.query_mut(crate::input::SourceRootQuery) .query_mut(ra_db::SourceRootQuery)
.set(source_root_id, Arc::new(source_root)); .set(source_root_id, Arc::new(source_root));
self.db self.db
.query_mut(crate::symbol_index::LibrarySymbolsQuery) .query_mut(crate::symbol_index::LibrarySymbolsQuery)
.set(source_root_id, Arc::new(library.symbol_index)); .set(source_root_id, Arc::new(library.symbol_index));
} }
self.db self.db
.query_mut(crate::input::LibrariesQuery) .query_mut(ra_db::LibrariesQuery)
.set((), Arc::new(libraries)); .set((), Arc::new(libraries));
} }
if let Some(crate_graph) = change.crate_graph { if let Some(crate_graph) = change.crate_graph {
self.db self.db
.query_mut(crate::input::CrateGraphQuery) .query_mut(ra_db::CrateGraphQuery)
.set((), Arc::new(crate_graph)) .set((), Arc::new(crate_graph))
} }
} }
@ -261,7 +200,7 @@ impl AnalysisImpl {
Ok(crate_id.into_iter().collect()) Ok(crate_id.into_iter().collect())
} }
pub fn crate_root(&self, crate_id: CrateId) -> FileId { 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<Option<Vec<CompletionItem>>> { pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
completions(&self.db, position) completions(&self.db, position)
@ -546,16 +485,6 @@ impl SourceChange {
} }
} }
impl CrateGraph {
fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
let (&crate_id, _) = self
.crate_roots
.iter()
.find(|(_crate_id, &root_id)| root_id == file_id)?;
Some(crate_id)
}
}
enum FnCallNode<'a> { enum FnCallNode<'a> {
CallExpr(ast::CallExpr<'a>), CallExpr(ast::CallExpr<'a>),
MethodCallExpr(ast::MethodCallExpr<'a>), MethodCallExpr(ast::MethodCallExpr<'a>),

View file

@ -19,8 +19,6 @@ macro_rules! ctry {
} }
mod arena; mod arena;
mod syntax_ptr;
mod input;
mod db; mod db;
mod loc2id; mod loc2id;
mod imp; mod imp;
@ -32,35 +30,27 @@ pub mod mock_analysis;
use std::{fmt, sync::Arc}; use std::{fmt, sync::Arc};
use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit}; use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit};
use ra_db::FileResolverImp;
use rayon::prelude::*; use rayon::prelude::*;
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
use crate::{ use crate::{
imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}, imp::{AnalysisHostImpl, AnalysisImpl},
symbol_index::SymbolIndex, symbol_index::SymbolIndex,
}; };
pub use crate::{ pub use crate::{
completion::CompletionItem, completion::CompletionItem,
hir::FnSignatureInfo, hir::FnSignatureInfo,
input::{CrateGraph, CrateId, FileId, FileResolver},
}; };
pub use ra_editor::{ pub use ra_editor::{
FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode,
}; };
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub use ra_db::{
pub struct Canceled; Canceled, Cancelable,
CrateGraph, CrateId, FileId, FileResolver
pub type Cancelable<T> = Result<T, Canceled>; };
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 {}
#[derive(Default)] #[derive(Default)]
pub struct AnalysisChange { pub struct AnalysisChange {

View file

@ -1,74 +1,10 @@
use parking_lot::Mutex; use ra_db::SourceRootId;
use std::hash::Hash;
use rustc_hash::FxHashMap;
use crate::{ use crate::{
hir::{SourceItemId, ModuleId}, hir::{SourceItemId, ModuleId},
input::SourceRootId,
}; };
/// There are two principle ways to refer to things: use ra_db::{NumericId, LocationIntener};
/// - 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<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
loc2id: FxHashMap<LOC, ID>,
id2loc: FxHashMap<ID, LOC>,
}
impl<LOC, ID> Default for Loc2IdMap<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
fn default() -> Self {
Loc2IdMap {
loc2id: FxHashMap::default(),
id2loc: FxHashMap::default(),
}
}
}
impl<LOC, ID> Loc2IdMap<LOC, ID>
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;
}
macro_rules! impl_numeric_id { macro_rules! impl_numeric_id {
($id:ident) => { ($id:ident) => {
@ -131,37 +67,3 @@ pub(crate) struct IdMaps {
pub(crate) fns: LocationIntener<SourceItemId, FnId>, pub(crate) fns: LocationIntener<SourceItemId, FnId>,
pub(crate) defs: LocationIntener<DefLoc, DefId>, pub(crate) defs: LocationIntener<DefLoc, DefId>,
} }
#[derive(Debug)]
pub(crate) struct LocationIntener<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
map: Mutex<Loc2IdMap<LOC, ID>>,
}
impl<LOC, ID> Default for LocationIntener<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
fn default() -> Self {
LocationIntener {
map: Default::default(),
}
}
}
impl<LOC, ID> LocationIntener<LOC, ID>
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)
}
}

View file

@ -9,13 +9,12 @@ use ra_syntax::{
SourceFileNode, SourceFileNode,
SyntaxKind::{self, *}, SyntaxKind::{self, *},
}; };
use ra_db::{SyntaxDatabase, SourceRootId};
use rayon::prelude::*; use rayon::prelude::*;
use crate::{ use crate::{
Cancelable, Cancelable,
FileId, Query, FileId, Query,
db::SyntaxDatabase,
input::SourceRootId,
}; };
salsa::query_group! { salsa::query_group! {

View file

@ -126,7 +126,7 @@ fn test_resolve_crate_root() {
let mut host = mock.analysis_host(); let mut host = mock.analysis_host();
assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); 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 crate_id = crate_graph.add_crate_root(root_file);
let mut change = AnalysisChange::new(); let mut change = AnalysisChange::new();
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);

16
crates/ra_db/Cargo.toml Normal file
View file

@ -0,0 +1,16 @@
[package]
edition = "2018"
name = "ra_db"
version = "0.1.0"
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
[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" }

View file

@ -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<FileId>;
fn debug_path(&self, _1file_id: FileId) -> Option<std::path::PathBuf> {
None
}
}
#[derive(Clone, Debug)]
pub struct FileResolverImp {
inner: Arc<FileResolver>,
}
impl PartialEq for FileResolverImp {
fn eq(&self, other: &FileResolverImp) -> bool {
self.inner() == other.inner()
}
}
impl Eq for FileResolverImp {}
impl Hash for FileResolverImp {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.inner().hash(hasher);
}
}
impl FileResolverImp {
pub fn new(inner: Arc<FileResolver>) -> 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<FileId> {
self.inner.resolve(file_id, path)
}
pub fn debug_path(&self, file_id: FileId) -> Option<std::path::PathBuf> {
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<FileId> {
panic!("file resolver not set")
}
}
FileResolverImp {
inner: Arc::new(DummyResolver),
}
}
}

View file

@ -1,11 +1,10 @@
use std::{fmt, sync::Arc}; use std::sync::Arc;
use relative_path::RelativePath;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use salsa; use salsa;
use crate::FileResolverImp; use crate::file_resolver::FileResolverImp;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32); pub struct FileId(pub u32);
@ -19,8 +18,8 @@ pub struct CrateGraph {
} }
impl CrateGraph { impl CrateGraph {
pub fn new() -> CrateGraph { pub fn crate_root(&self, crate_id: CrateId) -> FileId {
CrateGraph::default() self.crate_roots[&crate_id]
} }
pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId {
let crate_id = CrateId(self.crate_roots.len() as u32); let crate_id = CrateId(self.crate_roots.len() as u32);
@ -28,18 +27,17 @@ impl CrateGraph {
assert!(prev.is_none()); assert!(prev.is_none());
crate_id crate_id
} }
} pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
let (&crate_id, _) = self
pub trait FileResolver: fmt::Debug + Send + Sync + 'static { .crate_roots
fn file_stem(&self, file_id: FileId) -> String; .iter()
fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>; .find(|(_crate_id, &root_id)| root_id == file_id)?;
fn debug_path(&self, _1file_id: FileId) -> Option<std::path::PathBuf> { Some(crate_id)
None
} }
} }
salsa::query_group! { salsa::query_group! {
pub(crate) trait FilesDatabase: salsa::Database { pub trait FilesDatabase: salsa::Database {
fn file_text(file_id: FileId) -> Arc<String> { fn file_text(file_id: FileId) -> Arc<String> {
type FileTextQuery; type FileTextQuery;
storage input; storage input;
@ -64,12 +62,12 @@ salsa::query_group! {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[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)] #[derive(Default, Clone, Debug, PartialEq, Eq)]
pub(crate) struct SourceRoot { pub struct SourceRoot {
pub(crate) file_resolver: FileResolverImp, pub file_resolver: FileResolverImp,
pub(crate) files: FxHashSet<FileId>, pub files: FxHashSet<FileId>,
} }
pub(crate) const WORKSPACE: SourceRootId = SourceRootId(0); pub const WORKSPACE: SourceRootId = SourceRootId(0);

69
crates/ra_db/src/lib.rs Normal file
View file

@ -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<T> = Result<T, Canceled>;
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<LineIndex> {
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<LineIndex> {
let text = db.file_text(file_id);
Arc::new(LineIndex::new(&*text))
}

100
crates/ra_db/src/loc2id.rs Normal file
View file

@ -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<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
loc2id: FxHashMap<LOC, ID>,
id2loc: FxHashMap<ID, LOC>,
}
impl<LOC, ID> Default for Loc2IdMap<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
fn default() -> Self {
Loc2IdMap {
loc2id: FxHashMap::default(),
id2loc: FxHashMap::default(),
}
}
}
impl<LOC, ID> Loc2IdMap<LOC, ID>
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<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
map: Mutex<Loc2IdMap<LOC, ID>>,
}
impl<LOC, ID> Default for LocationIntener<LOC, ID>
where
ID: NumericId,
LOC: Clone + Eq + Hash,
{
fn default() -> Self {
LocationIntener {
map: Default::default(),
}
}
}
impl<LOC, ID> LocationIntener<LOC, ID>
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)
}
}

View file

@ -2,20 +2,20 @@ use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange
/// A pionter to a syntax node inside a file. /// A pionter to a syntax node inside a file.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct LocalSyntaxPtr { pub struct LocalSyntaxPtr {
range: TextRange, range: TextRange,
kind: SyntaxKind, kind: SyntaxKind,
} }
impl LocalSyntaxPtr { impl LocalSyntaxPtr {
pub(crate) fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { pub fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr {
LocalSyntaxPtr { LocalSyntaxPtr {
range: node.range(), range: node.range(),
kind: node.kind(), kind: node.kind(),
} }
} }
pub(crate) fn resolve(self, file: &SourceFileNode) -> SyntaxNode { pub fn resolve(self, file: &SourceFileNode) -> SyntaxNode {
let mut curr = file.syntax(); let mut curr = file.syntax();
loop { loop {
if curr.range() == self.range && curr.kind() == self.kind { 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 self.range
} }
} }

View file

@ -140,7 +140,7 @@ impl ServerWorldState {
Ok(file_id) Ok(file_id)
} }
pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
let mut crate_graph = CrateGraph::new(); let mut crate_graph = CrateGraph::default();
ws.iter() ws.iter()
.flat_map(|ws| { .flat_map(|ws| {
ws.packages() ws.packages()