aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/query_definitions.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 14:51:10 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 14:51:10 +0000
commitcf0ce14351af03c620aca784ee2c03aad86b866e (patch)
treebffd84981df9cca1143807796dc6772ddcfe8e0b /crates/ra_hir/src/query_definitions.rs
parenteaf553dade9a28b41631387d7c88b09fd0ba64e2 (diff)
parent733383446fc229a35d4432d14c295c5a01e5a87f (diff)
Merge #429
429: Reorganize hir public API in terms of code model r=matklad a=matklad Recently, I've been thinking about introducing "object orient code model" API for rust: a set of APIs with types like `Function`, `Module`, etc, with methods like `get_containing_declaration()`, `get_type()`, etc. Here's how a similar API might look like in .Net land: https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.semanticmodel?view=roslyn-dotnet https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.imethodsymbol?view=roslyn-dotnet The main feature of such API is that it can be powered by different backends. For example, one can imagine a backend based on salsa, and a backend which reads all the data from a specially prepared JSON file. The "OO" bit is interesting mostly in this "can swap implementations via dynamic dispatch" aspect, the actual API could have a more database/ECS flavored feeling. It's not clear at this moment how exactly should we implement such a dynamically (or if we even need dynamism in the first pace) swapable API in Rust, but I'd love to experiment with this a bit. For starters, I propose creating a `code_model_api` which contains various definition types and their public methods (mandatory implemented as one-liners, so that the API has a header-file feel). Specifically, I propose that each type is a wrapper around some integer ID, and that all methods of it accept a `&db` argument. The actual impl goes elsewhere: into the db queries or, absent a better place, into the `code_model_api_impl`. In the first commit, I've moved the simplest type, `Crate`, over to this pattern. I *think* that we, at least initially, will be used types from `code_model_api` *inside* `hir` as well, but this is not required: we might pick a different implementation down the line, while preserving the API. Long term I'd love to replace the `db: &impl HirDatabase` argument by a `mp: &dyn ModelProvider`, implement `ModelProvider` for `T: HirDatabase`, and move `code_model_api` into the separate crate, which does not depend on `hir`. @flodiebold you've recently done some `Def`s work, would do you think of this plan? Could it become a good API in the future, or is it just a useless boilerplate duplicating method signatures between `code_model_api` and `code_model_impl`? Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/query_definitions.rs')
-rw-r--r--crates/ra_hir/src/query_definitions.rs59
1 files changed, 4 insertions, 55 deletions
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index d9ee9d37f..f4b380022 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -6,20 +6,17 @@ use std::{
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use ra_syntax::{ 7use ra_syntax::{
8 AstNode, SyntaxNode, 8 AstNode, SyntaxNode,
9 ast::{self, NameOwner, ModuleItemOwner} 9 ast::{self, ModuleItemOwner}
10}; 10};
11use ra_db::{SourceRootId, Cancelable,}; 11use ra_db::{SourceRootId, Cancelable,};
12 12
13use crate::{ 13use crate::{
14 SourceFileItems, SourceItemId, DefKind, DefId, Name, AsName, HirFileId, 14 SourceFileItems, SourceItemId, DefKind, DefId, HirFileId,
15 MacroCallLoc, 15 MacroCallLoc,
16 db::HirDatabase, 16 db::HirDatabase,
17 function::FnScopes, 17 function::FnScopes,
18 module::{ 18 module_tree::{ModuleId, ModuleSourceNode},
19 ModuleSource, ModuleSourceNode, ModuleId, 19 nameres::{InputModuleItems, ItemMap, Resolver},
20 imp::Submodule,
21 nameres::{InputModuleItems, ItemMap, Resolver},
22 },
23 adt::{StructData, EnumData}, 20 adt::{StructData, EnumData},
24}; 21};
25 22
@@ -61,54 +58,6 @@ pub(super) fn file_item(db: &impl HirDatabase, source_item_id: SourceItemId) ->
61 } 58 }
62} 59}
63 60
64pub(crate) fn submodules(
65 db: &impl HirDatabase,
66 source: ModuleSource,
67) -> Cancelable<Arc<Vec<Submodule>>> {
68 db.check_canceled()?;
69 let file_id = source.file_id();
70 let submodules = match source.resolve(db) {
71 ModuleSourceNode::SourceFile(it) => collect_submodules(db, file_id, it.borrowed()),
72 ModuleSourceNode::Module(it) => it
73 .borrowed()
74 .item_list()
75 .map(|it| collect_submodules(db, file_id, it))
76 .unwrap_or_else(Vec::new),
77 };
78 return Ok(Arc::new(submodules));
79
80 fn collect_submodules<'a>(
81 db: &impl HirDatabase,
82 file_id: HirFileId,
83 root: impl ast::ModuleItemOwner<'a>,
84 ) -> Vec<Submodule> {
85 modules(root)
86 .map(|(name, m)| {
87 if m.has_semi() {
88 Submodule::Declaration(name)
89 } else {
90 let src = ModuleSource::new_inline(db, file_id, m);
91 Submodule::Definition(name, src)
92 }
93 })
94 .collect()
95 }
96}
97
98pub(crate) fn modules<'a>(
99 root: impl ast::ModuleItemOwner<'a>,
100) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
101 root.items()
102 .filter_map(|item| match item {
103 ast::ModuleItem::Module(m) => Some(m),
104 _ => None,
105 })
106 .filter_map(|module| {
107 let name = module.name()?.as_name();
108 Some((name, module))
109 })
110}
111
112pub(super) fn input_module_items( 61pub(super) fn input_module_items(
113 db: &impl HirDatabase, 62 db: &impl HirDatabase,
114 source_root_id: SourceRootId, 63 source_root_id: SourceRootId,