diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-28 01:10:58 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-28 01:10:58 +0000 |
commit | 95c0c8f3986c8b3bcf0052d34d3ace09ebb9fa1b (patch) | |
tree | 0e5aa7337c000dd8c6ef3a7fedba68abf7feca8a /crates/ra_db | |
parent | 9f08341aa486ea59cb488635f19e960523568fb8 (diff) | |
parent | 59e29aef633e906837f8fed604435976a46be691 (diff) |
Merge #247
247: Hir r=matklad a=matklad
This doesn't achive anything new, just a big refactoring.
The main change is that Descriptors are now called `hir`, and live in a separate crate.
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_db')
-rw-r--r-- | crates/ra_db/Cargo.toml | 16 | ||||
-rw-r--r-- | crates/ra_db/src/file_resolver.rs | 76 | ||||
-rw-r--r-- | crates/ra_db/src/input.rs | 73 | ||||
-rw-r--r-- | crates/ra_db/src/lib.rs | 89 | ||||
-rw-r--r-- | crates/ra_db/src/loc2id.rs | 100 | ||||
-rw-r--r-- | crates/ra_db/src/syntax_ptr.rs | 48 |
6 files changed, 402 insertions, 0 deletions
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml new file mode 100644 index 000000000..3bf2f635e --- /dev/null +++ b/crates/ra_db/Cargo.toml | |||
@@ -0,0 +1,16 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_db" | ||
4 | version = "0.1.0" | ||
5 | authors = ["Aleksey Kladov <[email protected]>"] | ||
6 | |||
7 | [dependencies] | ||
8 | log = "0.4.5" | ||
9 | relative-path = "0.4.0" | ||
10 | salsa = "0.8.0" | ||
11 | rustc-hash = "1.0" | ||
12 | parking_lot = "0.6.4" | ||
13 | id-arena = { git = "https://github.com/fitzgen/id-arena/", rev = "43ecd67" } | ||
14 | ra_syntax = { path = "../ra_syntax" } | ||
15 | ra_editor = { path = "../ra_editor" } | ||
16 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ra_db/src/file_resolver.rs b/crates/ra_db/src/file_resolver.rs new file mode 100644 index 000000000..f849ac752 --- /dev/null +++ b/crates/ra_db/src/file_resolver.rs | |||
@@ -0,0 +1,76 @@ | |||
1 | use std::{ | ||
2 | sync::Arc, | ||
3 | hash::{Hash, Hasher}, | ||
4 | fmt, | ||
5 | }; | ||
6 | |||
7 | use relative_path::RelativePath; | ||
8 | |||
9 | use crate::input::FileId; | ||
10 | |||
11 | pub trait FileResolver: fmt::Debug + Send + Sync + 'static { | ||
12 | fn file_stem(&self, file_id: FileId) -> String; | ||
13 | fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId>; | ||
14 | fn debug_path(&self, _1file_id: FileId) -> Option<std::path::PathBuf> { | ||
15 | None | ||
16 | } | ||
17 | } | ||
18 | |||
19 | #[derive(Clone, Debug)] | ||
20 | pub struct FileResolverImp { | ||
21 | inner: Arc<FileResolver>, | ||
22 | } | ||
23 | |||
24 | impl PartialEq for FileResolverImp { | ||
25 | fn eq(&self, other: &FileResolverImp) -> bool { | ||
26 | self.inner() == other.inner() | ||
27 | } | ||
28 | } | ||
29 | |||
30 | impl Eq for FileResolverImp {} | ||
31 | |||
32 | impl Hash for FileResolverImp { | ||
33 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
34 | self.inner().hash(hasher); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | impl FileResolverImp { | ||
39 | pub fn new(inner: Arc<FileResolver>) -> FileResolverImp { | ||
40 | FileResolverImp { inner } | ||
41 | } | ||
42 | pub fn file_stem(&self, file_id: FileId) -> String { | ||
43 | self.inner.file_stem(file_id) | ||
44 | } | ||
45 | pub fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { | ||
46 | self.inner.resolve(file_id, path) | ||
47 | } | ||
48 | pub fn debug_path(&self, file_id: FileId) -> Option<std::path::PathBuf> { | ||
49 | self.inner.debug_path(file_id) | ||
50 | } | ||
51 | fn inner(&self) -> *const FileResolver { | ||
52 | &*self.inner | ||
53 | } | ||
54 | } | ||
55 | |||
56 | impl Default for FileResolverImp { | ||
57 | fn default() -> FileResolverImp { | ||
58 | #[derive(Debug)] | ||
59 | struct DummyResolver; | ||
60 | impl FileResolver for DummyResolver { | ||
61 | fn file_stem(&self, _file_: FileId) -> String { | ||
62 | panic!("file resolver not set") | ||
63 | } | ||
64 | fn resolve( | ||
65 | &self, | ||
66 | _file_id: FileId, | ||
67 | _path: &::relative_path::RelativePath, | ||
68 | ) -> Option<FileId> { | ||
69 | panic!("file resolver not set") | ||
70 | } | ||
71 | } | ||
72 | FileResolverImp { | ||
73 | inner: Arc::new(DummyResolver), | ||
74 | } | ||
75 | } | ||
76 | } | ||
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs new file mode 100644 index 000000000..9101ac7a8 --- /dev/null +++ b/crates/ra_db/src/input.rs | |||
@@ -0,0 +1,73 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use rustc_hash::FxHashMap; | ||
4 | use rustc_hash::FxHashSet; | ||
5 | use salsa; | ||
6 | |||
7 | use crate::file_resolver::FileResolverImp; | ||
8 | |||
9 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
10 | pub struct FileId(pub u32); | ||
11 | |||
12 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
13 | pub struct CrateId(pub u32); | ||
14 | |||
15 | #[derive(Debug, Clone, Default, PartialEq, Eq)] | ||
16 | pub struct CrateGraph { | ||
17 | pub(crate) crate_roots: FxHashMap<CrateId, FileId>, | ||
18 | } | ||
19 | |||
20 | impl CrateGraph { | ||
21 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | ||
22 | self.crate_roots[&crate_id] | ||
23 | } | ||
24 | pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { | ||
25 | let crate_id = CrateId(self.crate_roots.len() as u32); | ||
26 | let prev = self.crate_roots.insert(crate_id, file_id); | ||
27 | assert!(prev.is_none()); | ||
28 | crate_id | ||
29 | } | ||
30 | pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { | ||
31 | let (&crate_id, _) = self | ||
32 | .crate_roots | ||
33 | .iter() | ||
34 | .find(|(_crate_id, &root_id)| root_id == file_id)?; | ||
35 | Some(crate_id) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | salsa::query_group! { | ||
40 | pub trait FilesDatabase: salsa::Database { | ||
41 | fn file_text(file_id: FileId) -> Arc<String> { | ||
42 | type FileTextQuery; | ||
43 | storage input; | ||
44 | } | ||
45 | fn file_source_root(file_id: FileId) -> SourceRootId { | ||
46 | type FileSourceRootQuery; | ||
47 | storage input; | ||
48 | } | ||
49 | fn source_root(id: SourceRootId) -> Arc<SourceRoot> { | ||
50 | type SourceRootQuery; | ||
51 | storage input; | ||
52 | } | ||
53 | fn libraries() -> Arc<Vec<SourceRootId>> { | ||
54 | type LibrariesQuery; | ||
55 | storage input; | ||
56 | } | ||
57 | fn crate_graph() -> Arc<CrateGraph> { | ||
58 | type CrateGraphQuery; | ||
59 | storage input; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
65 | pub struct SourceRootId(pub u32); | ||
66 | |||
67 | #[derive(Default, Clone, Debug, PartialEq, Eq)] | ||
68 | pub struct SourceRoot { | ||
69 | pub file_resolver: FileResolverImp, | ||
70 | pub files: FxHashSet<FileId>, | ||
71 | } | ||
72 | |||
73 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | ||
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs new file mode 100644 index 000000000..33cb0e2ec --- /dev/null +++ b/crates/ra_db/src/lib.rs | |||
@@ -0,0 +1,89 @@ | |||
1 | //! ra_db defines basic database traits. Concrete DB is defined by ra_analysis. | ||
2 | |||
3 | extern crate ra_editor; | ||
4 | extern crate ra_syntax; | ||
5 | extern crate relative_path; | ||
6 | extern crate rustc_hash; | ||
7 | extern crate salsa; | ||
8 | |||
9 | mod syntax_ptr; | ||
10 | mod file_resolver; | ||
11 | mod input; | ||
12 | mod loc2id; | ||
13 | |||
14 | use std::sync::Arc; | ||
15 | use ra_editor::LineIndex; | ||
16 | use ra_syntax::{TextUnit, SourceFileNode}; | ||
17 | |||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
19 | pub struct Canceled; | ||
20 | |||
21 | pub type Cancelable<T> = Result<T, Canceled>; | ||
22 | |||
23 | impl std::fmt::Display for Canceled { | ||
24 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
25 | fmt.write_str("Canceled") | ||
26 | } | ||
27 | } | ||
28 | |||
29 | impl std::error::Error for Canceled {} | ||
30 | |||
31 | pub use crate::{ | ||
32 | syntax_ptr::LocalSyntaxPtr, | ||
33 | file_resolver::{FileResolver, FileResolverImp}, | ||
34 | input::{ | ||
35 | FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, WORKSPACE, | ||
36 | FileTextQuery, FileSourceRootQuery, SourceRootQuery, LibrariesQuery, CrateGraphQuery, | ||
37 | }, | ||
38 | loc2id::{LocationIntener, NumericId}, | ||
39 | }; | ||
40 | |||
41 | #[macro_export] | ||
42 | macro_rules! impl_numeric_id { | ||
43 | ($id:ident) => { | ||
44 | impl $crate::NumericId for $id { | ||
45 | fn from_u32(id: u32) -> Self { | ||
46 | $id(id) | ||
47 | } | ||
48 | fn to_u32(self) -> u32 { | ||
49 | self.0 | ||
50 | } | ||
51 | } | ||
52 | }; | ||
53 | } | ||
54 | |||
55 | pub trait BaseDatabase: salsa::Database { | ||
56 | fn check_canceled(&self) -> Cancelable<()> { | ||
57 | if self.salsa_runtime().is_current_revision_canceled() { | ||
58 | Err(Canceled) | ||
59 | } else { | ||
60 | Ok(()) | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | |||
65 | salsa::query_group! { | ||
66 | pub trait SyntaxDatabase: crate::input::FilesDatabase + BaseDatabase { | ||
67 | fn source_file(file_id: FileId) -> SourceFileNode { | ||
68 | type SourceFileQuery; | ||
69 | } | ||
70 | fn file_lines(file_id: FileId) -> Arc<LineIndex> { | ||
71 | type FileLinesQuery; | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | fn source_file(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode { | ||
77 | let text = db.file_text(file_id); | ||
78 | SourceFileNode::parse(&*text) | ||
79 | } | ||
80 | fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> { | ||
81 | let text = db.file_text(file_id); | ||
82 | Arc::new(LineIndex::new(&*text)) | ||
83 | } | ||
84 | |||
85 | #[derive(Clone, Copy, Debug)] | ||
86 | pub struct FilePosition { | ||
87 | pub file_id: FileId, | ||
88 | pub offset: TextUnit, | ||
89 | } | ||
diff --git a/crates/ra_db/src/loc2id.rs b/crates/ra_db/src/loc2id.rs new file mode 100644 index 000000000..69ba43d0f --- /dev/null +++ b/crates/ra_db/src/loc2id.rs | |||
@@ -0,0 +1,100 @@ | |||
1 | use parking_lot::Mutex; | ||
2 | |||
3 | use std::hash::Hash; | ||
4 | |||
5 | use rustc_hash::FxHashMap; | ||
6 | |||
7 | /// There are two principle ways to refer to things: | ||
8 | /// - by their locatinon (module in foo/bar/baz.rs at line 42) | ||
9 | /// - by their numeric id (module `ModuleId(42)`) | ||
10 | /// | ||
11 | /// The first one is more powerful (you can actually find the thing in question | ||
12 | /// by id), but the second one is so much more compact. | ||
13 | /// | ||
14 | /// `Loc2IdMap` allows us to have a cake an eat it as well: by maintaining a | ||
15 | /// bidirectional mapping between positional and numeric ids, we can use compact | ||
16 | /// representation wich still allows us to get the actual item | ||
17 | #[derive(Debug)] | ||
18 | struct Loc2IdMap<LOC, ID> | ||
19 | where | ||
20 | ID: NumericId, | ||
21 | LOC: Clone + Eq + Hash, | ||
22 | { | ||
23 | loc2id: FxHashMap<LOC, ID>, | ||
24 | id2loc: FxHashMap<ID, LOC>, | ||
25 | } | ||
26 | |||
27 | impl<LOC, ID> Default for Loc2IdMap<LOC, ID> | ||
28 | where | ||
29 | ID: NumericId, | ||
30 | LOC: Clone + Eq + Hash, | ||
31 | { | ||
32 | fn default() -> Self { | ||
33 | Loc2IdMap { | ||
34 | loc2id: FxHashMap::default(), | ||
35 | id2loc: FxHashMap::default(), | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl<LOC, ID> Loc2IdMap<LOC, ID> | ||
41 | where | ||
42 | ID: NumericId, | ||
43 | LOC: Clone + Eq + Hash, | ||
44 | { | ||
45 | pub fn loc2id(&mut self, loc: &LOC) -> ID { | ||
46 | match self.loc2id.get(loc) { | ||
47 | Some(id) => return id.clone(), | ||
48 | None => (), | ||
49 | } | ||
50 | let id = self.loc2id.len(); | ||
51 | assert!(id < u32::max_value() as usize); | ||
52 | let id = ID::from_u32(id as u32); | ||
53 | self.loc2id.insert(loc.clone(), id.clone()); | ||
54 | self.id2loc.insert(id.clone(), loc.clone()); | ||
55 | id | ||
56 | } | ||
57 | |||
58 | pub fn id2loc(&self, id: ID) -> LOC { | ||
59 | self.id2loc[&id].clone() | ||
60 | } | ||
61 | } | ||
62 | |||
63 | pub trait NumericId: Clone + Eq + Hash { | ||
64 | fn from_u32(id: u32) -> Self; | ||
65 | fn to_u32(self) -> u32; | ||
66 | } | ||
67 | |||
68 | #[derive(Debug)] | ||
69 | pub struct LocationIntener<LOC, ID> | ||
70 | where | ||
71 | ID: NumericId, | ||
72 | LOC: Clone + Eq + Hash, | ||
73 | { | ||
74 | map: Mutex<Loc2IdMap<LOC, ID>>, | ||
75 | } | ||
76 | |||
77 | impl<LOC, ID> Default for LocationIntener<LOC, ID> | ||
78 | where | ||
79 | ID: NumericId, | ||
80 | LOC: Clone + Eq + Hash, | ||
81 | { | ||
82 | fn default() -> Self { | ||
83 | LocationIntener { | ||
84 | map: Default::default(), | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | impl<LOC, ID> LocationIntener<LOC, ID> | ||
90 | where | ||
91 | ID: NumericId, | ||
92 | LOC: Clone + Eq + Hash, | ||
93 | { | ||
94 | pub fn loc2id(&self, loc: &LOC) -> ID { | ||
95 | self.map.lock().loc2id(loc) | ||
96 | } | ||
97 | pub fn id2loc(&self, id: ID) -> LOC { | ||
98 | self.map.lock().id2loc(id) | ||
99 | } | ||
100 | } | ||
diff --git a/crates/ra_db/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs new file mode 100644 index 000000000..dac94dd36 --- /dev/null +++ b/crates/ra_db/src/syntax_ptr.rs | |||
@@ -0,0 +1,48 @@ | |||
1 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; | ||
2 | |||
3 | /// A pionter to a syntax node inside a file. | ||
4 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
5 | pub struct LocalSyntaxPtr { | ||
6 | range: TextRange, | ||
7 | kind: SyntaxKind, | ||
8 | } | ||
9 | |||
10 | impl LocalSyntaxPtr { | ||
11 | pub fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { | ||
12 | LocalSyntaxPtr { | ||
13 | range: node.range(), | ||
14 | kind: node.kind(), | ||
15 | } | ||
16 | } | ||
17 | |||
18 | pub fn resolve(self, file: &SourceFileNode) -> SyntaxNode { | ||
19 | let mut curr = file.syntax(); | ||
20 | loop { | ||
21 | if curr.range() == self.range && curr.kind() == self.kind { | ||
22 | return curr.owned(); | ||
23 | } | ||
24 | curr = curr | ||
25 | .children() | ||
26 | .find(|it| self.range.is_subrange(&it.range())) | ||
27 | .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) | ||
28 | } | ||
29 | } | ||
30 | |||
31 | pub fn range(self) -> TextRange { | ||
32 | self.range | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #[test] | ||
37 | fn test_local_syntax_ptr() { | ||
38 | use ra_syntax::{ast, AstNode}; | ||
39 | let file = SourceFileNode::parse("struct Foo { f: u32, }"); | ||
40 | let field = file | ||
41 | .syntax() | ||
42 | .descendants() | ||
43 | .find_map(ast::NamedFieldDef::cast) | ||
44 | .unwrap(); | ||
45 | let ptr = LocalSyntaxPtr::new(field.syntax()); | ||
46 | let field_syntax = ptr.resolve(&file); | ||
47 | assert_eq!(field.syntax(), field_syntax); | ||
48 | } | ||