1 //! base_db defines basic database traits. The concrete DB is defined by ide.
3 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
9 use std
::{panic, sync::Arc}
;
11 use stdx
::hash
::NoHashHashSet
;
12 use syntax
::{ast, Parse, SourceFile, TextRange, TextSize}
;
17 CrateData
, CrateDisplayName
, CrateGraph
, CrateId
, CrateName
, CrateOrigin
, Dependency
,
18 Edition
, Env
, LangCrateOrigin
, ProcMacro
, ProcMacroExpander
, ProcMacroExpansionError
,
19 ProcMacroId
, ProcMacroKind
, ProcMacroLoadResult
, SourceRoot
, SourceRootId
,
20 TargetLayoutLoadResult
,
23 pub use salsa
::{self, Cancelled}
;
24 pub use vfs
::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath}
;
27 macro_rules
! impl_intern_key
{
29 impl $
crate::salsa
::InternKey
for $name
{
30 fn from_intern_id(v
: $
crate::salsa
::InternId
) -> Self {
33 fn as_intern_id(&self) -> $
crate::salsa
::InternId
{
40 pub trait Upcast
<T
: ?Sized
> {
41 fn upcast(&self) -> &T
;
44 #[derive(Clone, Copy, Debug)]
45 pub struct FilePosition
{
50 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
51 pub struct FileRange
{
56 pub const DEFAULT_LRU_CAP
: usize = 128;
58 pub trait FileLoader
{
60 fn file_text(&self, file_id
: FileId
) -> Arc
<String
>;
61 fn resolve_path(&self, path
: AnchoredPath
<'_
>) -> Option
<FileId
>;
62 fn relevant_crates(&self, file_id
: FileId
) -> Arc
<NoHashHashSet
<CrateId
>>;
65 /// Database which stores all significant input facts: source code and project
66 /// model. Everything else in rust-analyzer is derived from these queries.
67 #[salsa::query_group(SourceDatabaseStorage)]
68 pub trait SourceDatabase
: FileLoader
+ std
::fmt
::Debug
{
69 // Parses the file into the syntax tree.
70 #[salsa::invoke(parse_query)]
71 fn parse(&self, file_id
: FileId
) -> Parse
<ast
::SourceFile
>;
75 fn crate_graph(&self) -> Arc
<CrateGraph
>;
78 fn parse_query(db
: &dyn SourceDatabase
, file_id
: FileId
) -> Parse
<ast
::SourceFile
> {
79 let _p
= profile
::span("parse_query").detail(|| format
!("{file_id:?}"));
80 let text
= db
.file_text(file_id
);
81 SourceFile
::parse(&text
)
84 /// We don't want to give HIR knowledge of source roots, hence we extract these
85 /// methods into a separate DB.
86 #[salsa::query_group(SourceDatabaseExtStorage)]
87 pub trait SourceDatabaseExt
: SourceDatabase
{
89 fn file_text(&self, file_id
: FileId
) -> Arc
<String
>;
90 /// Path to a file, relative to the root of its source root.
91 /// Source root of the file.
93 fn file_source_root(&self, file_id
: FileId
) -> SourceRootId
;
94 /// Contents of the source root.
96 fn source_root(&self, id
: SourceRootId
) -> Arc
<SourceRoot
>;
98 fn source_root_crates(&self, id
: SourceRootId
) -> Arc
<NoHashHashSet
<CrateId
>>;
101 fn source_root_crates(db
: &dyn SourceDatabaseExt
, id
: SourceRootId
) -> Arc
<NoHashHashSet
<CrateId
>> {
102 let graph
= db
.crate_graph();
106 let root_file
= graph
[krate
].root_file_id
;
107 db
.file_source_root(root_file
) == id
113 /// Silly workaround for cyclic deps between the traits
114 pub struct FileLoaderDelegate
<T
>(pub T
);
116 impl<T
: SourceDatabaseExt
> FileLoader
for FileLoaderDelegate
<&'_ T
> {
117 fn file_text(&self, file_id
: FileId
) -> Arc
<String
> {
118 SourceDatabaseExt
::file_text(self.0, file_id
)
120 fn resolve_path(&self, path
: AnchoredPath
<'_
>) -> Option
<FileId
> {
121 // FIXME: this *somehow* should be platform agnostic...
122 let source_root
= self.0.file_source_root
(path
.anchor
);
123 let source_root
= self.0.source_root(source_root
);
124 source_root
.resolve_path(path
)
127 fn relevant_crates(&self, file_id
: FileId
) -> Arc
<NoHashHashSet
<CrateId
>> {
128 let _p
= profile
::span("relevant_crates");
129 let source_root
= self.0.file_source_root
(file_id
);
130 self.0.source_root_crates(source_root
)