]> git.lizzy.rs Git - rust.git/blob - crates/base_db/src/lib.rs
internal: Refactor FamousDefs builtin crate search
[rust.git] / crates / base_db / src / lib.rs
1 //! base_db defines basic database traits. The concrete DB is defined by ide.
2 mod input;
3 mod change;
4 pub mod fixture;
5
6 use std::{panic, sync::Arc};
7
8 use rustc_hash::FxHashSet;
9 use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
10
11 pub use crate::{
12     change::Change,
13     input::{
14         CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
15         Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
16         ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
17     },
18 };
19 pub use salsa::{self, Cancelled};
20 pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};
21
22 #[macro_export]
23 macro_rules! impl_intern_key {
24     ($name:ident) => {
25         impl $crate::salsa::InternKey for $name {
26             fn from_intern_id(v: $crate::salsa::InternId) -> Self {
27                 $name(v)
28             }
29             fn as_intern_id(&self) -> $crate::salsa::InternId {
30                 self.0
31             }
32         }
33     };
34 }
35
36 pub trait Upcast<T: ?Sized> {
37     fn upcast(&self) -> &T;
38 }
39
40 #[derive(Clone, Copy, Debug)]
41 pub struct FilePosition {
42     pub file_id: FileId,
43     pub offset: TextSize,
44 }
45
46 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
47 pub struct FileRange {
48     pub file_id: FileId,
49     pub range: TextRange,
50 }
51
52 pub const DEFAULT_LRU_CAP: usize = 128;
53
54 pub trait FileLoader {
55     /// Text of the file.
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>>;
59 }
60
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>;
68
69     /// The crate graph.
70     #[salsa::input]
71     fn crate_graph(&self) -> Arc<CrateGraph>;
72 }
73
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)
78 }
79
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 {
84     #[salsa::input]
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.
88     #[salsa::input]
89     fn file_source_root(&self, file_id: FileId) -> SourceRootId;
90     /// Contents of the source root.
91     #[salsa::input]
92     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
93
94     fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
95 }
96
97 fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
98     let graph = db.crate_graph();
99     let res = graph
100         .iter()
101         .filter(|&krate| {
102             let root_file = graph[krate].root_file_id;
103             db.file_source_root(root_file) == id
104         })
105         .collect();
106     Arc::new(res)
107 }
108
109 /// Silly workaround for cyclic deps between the traits
110 pub struct FileLoaderDelegate<T>(pub T);
111
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)
115     }
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)
121     }
122
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)
127     }
128 }