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)",
"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"

View file

@ -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" }

View file

@ -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
};

View file

@ -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<LocationIntener<DefLoc, DefId>> for RootDatabase {
fn as_ref(&self) -> &LocationIntener<DefLoc, DefId> {
@ -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<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,
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,
};

View file

@ -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},
};

View file

@ -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::{

View file

@ -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},
};

View file

@ -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::*;

View file

@ -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`

View file

@ -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<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)]
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<Option<Vec<CompletionItem>>> {
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> {
CallExpr(ast::CallExpr<'a>),
MethodCallExpr(ast::MethodCallExpr<'a>),

View file

@ -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<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 ra_db::{
Canceled, Cancelable,
CrateGraph, CrateId, FileId, FileResolver
};
#[derive(Default)]
pub struct AnalysisChange {

View file

@ -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<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;
}
use ra_db::{NumericId, LocationIntener};
macro_rules! impl_numeric_id {
($id:ident) => {
@ -131,37 +67,3 @@ pub(crate) struct IdMaps {
pub(crate) fns: LocationIntener<SourceItemId, FnId>,
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,
SyntaxKind::{self, *},
};
use ra_db::{SyntaxDatabase, SourceRootId};
use rayon::prelude::*;
use crate::{
Cancelable,
FileId, Query,
db::SyntaxDatabase,
input::SourceRootId,
};
salsa::query_group! {

View file

@ -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);

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::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<FileId>;
fn debug_path(&self, _1file_id: FileId) -> Option<std::path::PathBuf> {
None
pub 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)
}
}
salsa::query_group! {
pub(crate) trait FilesDatabase: salsa::Database {
pub trait FilesDatabase: salsa::Database {
fn file_text(file_id: FileId) -> Arc<String> {
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<FileId>,
pub struct SourceRoot {
pub file_resolver: FileResolverImp,
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.
#[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
}
}

View file

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