1 //! base_db defines basic database traits. The concrete DB is defined by ide.
6 use std::{panic, sync::Arc};
8 use rustc_hash::FxHashSet;
9 use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
14 CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
15 Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
16 ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
19 pub use salsa::{self, Cancelled};
20 pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};
23 macro_rules! impl_intern_key {
25 impl $crate::salsa::InternKey for $name {
26 fn from_intern_id(v: $crate::salsa::InternId) -> Self {
29 fn as_intern_id(&self) -> $crate::salsa::InternId {
36 pub trait Upcast<T: ?Sized> {
37 fn upcast(&self) -> &T;
40 #[derive(Clone, Copy, Debug)]
41 pub struct FilePosition {
46 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
47 pub struct FileRange {
52 pub const DEFAULT_LRU_CAP: usize = 128;
54 pub trait FileLoader {
56 fn file_text(&self, file_id: FileId) -> Arc<String>;
57 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId>;
58 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
61 /// Database which stores all significant input facts: source code and project
62 /// model. Everything else in rust-analyzer is derived from these queries.
63 #[salsa::query_group(SourceDatabaseStorage)]
64 pub trait SourceDatabase: FileLoader + std::fmt::Debug {
65 // Parses the file into the syntax tree.
66 #[salsa::invoke(parse_query)]
67 fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
71 fn crate_graph(&self) -> Arc<CrateGraph>;
74 fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
75 let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id));
76 let text = db.file_text(file_id);
77 SourceFile::parse(&*text)
80 /// We don't want to give HIR knowledge of source roots, hence we extract these
81 /// methods into a separate DB.
82 #[salsa::query_group(SourceDatabaseExtStorage)]
83 pub trait SourceDatabaseExt: SourceDatabase {
85 fn file_text(&self, file_id: FileId) -> Arc<String>;
86 /// Path to a file, relative to the root of its source root.
87 /// Source root of the file.
89 fn file_source_root(&self, file_id: FileId) -> SourceRootId;
90 /// Contents of the source root.
92 fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
94 fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
97 fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
98 let graph = db.crate_graph();
102 let root_file = graph[krate].root_file_id;
103 db.file_source_root(root_file) == id
109 /// Silly workaround for cyclic deps between the traits
110 pub struct FileLoaderDelegate<T>(pub T);
112 impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
113 fn file_text(&self, file_id: FileId) -> Arc<String> {
114 SourceDatabaseExt::file_text(self.0, file_id)
116 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
117 // FIXME: this *somehow* should be platform agnostic...
118 let source_root = self.0.file_source_root(path.anchor);
119 let source_root = self.0.source_root(source_root);
120 source_root.file_set.resolve_path(path)
123 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
124 let _p = profile::span("relevant_crates");
125 let source_root = self.0.file_source_root(file_id);
126 self.0.source_root_crates(source_root)