From ed20a857f485a471369cd99b843af19a4d875ad0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 16:25:38 +0200 Subject: Rename ra_db -> base_db --- crates/base_db/src/lib.rs | 167 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 crates/base_db/src/lib.rs (limited to 'crates/base_db/src/lib.rs') diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs new file mode 100644 index 000000000..811057251 --- /dev/null +++ b/crates/base_db/src/lib.rs @@ -0,0 +1,167 @@ +//! base_db defines basic database traits. The concrete DB is defined by ra_ide. +mod cancellation; +mod input; +pub mod fixture; + +use std::{panic, sync::Arc}; + +use rustc_hash::FxHashSet; +use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; + +pub use crate::{ + cancellation::Canceled, + input::{ + CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId, + SourceRoot, SourceRootId, + }, +}; +pub use salsa; +pub use vfs::{file_set::FileSet, VfsPath}; + +#[macro_export] +macro_rules! impl_intern_key { + ($name:ident) => { + impl $crate::salsa::InternKey for $name { + fn from_intern_id(v: $crate::salsa::InternId) -> Self { + $name(v) + } + fn as_intern_id(&self) -> $crate::salsa::InternId { + self.0 + } + } + }; +} + +pub trait Upcast { + fn upcast(&self) -> &T; +} + +pub trait CheckCanceled { + /// Aborts current query if there are pending changes. + /// + /// rust-analyzer needs to be able to answer semantic questions about the + /// code while the code is being modified. A common problem is that a + /// long-running query is being calculated when a new change arrives. + /// + /// We can't just apply the change immediately: this will cause the pending + /// query to see inconsistent state (it will observe an absence of + /// repeatable read). So what we do is we **cancel** all pending queries + /// before applying the change. + /// + /// We implement cancellation by panicking with a special value and catching + /// it on the API boundary. Salsa explicitly supports this use-case. + fn check_canceled(&self); + + fn catch_canceled(&self, f: F) -> Result + where + Self: Sized + panic::RefUnwindSafe, + F: FnOnce(&Self) -> T + panic::UnwindSafe, + { + panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::() { + Ok(canceled) => *canceled, + Err(payload) => panic::resume_unwind(payload), + }) + } +} + +impl CheckCanceled for T { + fn check_canceled(&self) { + if self.salsa_runtime().is_current_revision_canceled() { + Canceled::throw() + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct FilePosition { + pub file_id: FileId, + pub offset: TextSize, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct FileRange { + pub file_id: FileId, + pub range: TextRange, +} + +pub const DEFAULT_LRU_CAP: usize = 128; + +pub trait FileLoader { + /// Text of the file. + fn file_text(&self, file_id: FileId) -> Arc; + /// Note that we intentionally accept a `&str` and not a `&Path` here. This + /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such, + /// so the input is guaranteed to be utf-8 string. One might be tempted to + /// introduce some kind of "utf-8 path with / separators", but that's a bad idea. Behold + /// `#[path = "C://no/way"]` + fn resolve_path(&self, anchor: FileId, path: &str) -> Option; + fn relevant_crates(&self, file_id: FileId) -> Arc>; +} + +/// Database which stores all significant input facts: source code and project +/// model. Everything else in rust-analyzer is derived from these queries. +#[salsa::query_group(SourceDatabaseStorage)] +pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { + // Parses the file into the syntax tree. + #[salsa::invoke(parse_query)] + fn parse(&self, file_id: FileId) -> Parse; + + /// The crate graph. + #[salsa::input] + fn crate_graph(&self) -> Arc; +} + +fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse { + let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id)); + let text = db.file_text(file_id); + SourceFile::parse(&*text) +} + +/// We don't want to give HIR knowledge of source roots, hence we extract these +/// methods into a separate DB. +#[salsa::query_group(SourceDatabaseExtStorage)] +pub trait SourceDatabaseExt: SourceDatabase { + #[salsa::input] + fn file_text(&self, file_id: FileId) -> Arc; + /// Path to a file, relative to the root of its source root. + /// Source root of the file. + #[salsa::input] + fn file_source_root(&self, file_id: FileId) -> SourceRootId; + /// Contents of the source root. + #[salsa::input] + fn source_root(&self, id: SourceRootId) -> Arc; + + fn source_root_crates(&self, id: SourceRootId) -> Arc>; +} + +fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { + let graph = db.crate_graph(); + let res = graph + .iter() + .filter(|&krate| { + let root_file = graph[krate].root_file_id; + db.file_source_root(root_file) == id + }) + .collect::>(); + Arc::new(res) +} + +/// Silly workaround for cyclic deps between the traits +pub struct FileLoaderDelegate(pub T); + +impl FileLoader for FileLoaderDelegate<&'_ T> { + fn file_text(&self, file_id: FileId) -> Arc { + SourceDatabaseExt::file_text(self.0, file_id) + } + fn resolve_path(&self, anchor: FileId, path: &str) -> Option { + // FIXME: this *somehow* should be platform agnostic... + let source_root = self.0.file_source_root(anchor); + let source_root = self.0.source_root(source_root); + source_root.file_set.resolve_path(anchor, path) + } + + fn relevant_crates(&self, file_id: FileId) -> Arc> { + let source_root = self.0.file_source_root(file_id); + self.0.source_root_crates(source_root) + } +} -- cgit v1.2.3 From 1b0c7701cc97cd7bef8bb9729011d4cf291a60c5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 17:42:52 +0200 Subject: Rename ra_ide -> ide --- crates/base_db/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/base_db/src/lib.rs') diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 811057251..ee3415850 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs @@ -1,4 +1,4 @@ -//! base_db defines basic database traits. The concrete DB is defined by ra_ide. +//! base_db defines basic database traits. The concrete DB is defined by ide. mod cancellation; mod input; pub mod fixture; -- cgit v1.2.3