diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/db.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/function.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 172 | ||||
-rw-r--r-- | crates/ra_hir/src/krate.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/module.rs | 15 |
8 files changed, 225 insertions, 5 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 73a4cdc5c..6d5235ba4 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{SyntaxNode, SourceFileNode}; | |||
4 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable}; | 4 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, | 7 | Crate, DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, |
8 | SourceFileItems, SourceItemId, | 8 | SourceFileItems, SourceItemId, |
9 | query_definitions, | 9 | query_definitions, |
10 | FnScopes, | 10 | FnScopes, |
@@ -13,6 +13,7 @@ use crate::{ | |||
13 | nameres::{ItemMap, InputModuleItems}}, | 13 | nameres::{ItemMap, InputModuleItems}}, |
14 | ty::{InferenceResult, Ty}, | 14 | ty::{InferenceResult, Ty}, |
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::CrateImplBlocks, | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | salsa::query_group! { | 19 | salsa::query_group! { |
@@ -87,6 +88,11 @@ pub trait HirDatabase: SyntaxDatabase | |||
87 | type ModuleTreeQuery; | 88 | type ModuleTreeQuery; |
88 | use fn crate::module::imp::module_tree; | 89 | use fn crate::module::imp::module_tree; |
89 | } | 90 | } |
91 | |||
92 | fn impls_in_crate(krate: Crate) -> Cancelable<Arc<CrateImplBlocks>> { | ||
93 | type ImplsInCrateQuery; | ||
94 | use fn crate::impl_block::impls_in_crate; | ||
95 | } | ||
90 | } | 96 | } |
91 | 97 | ||
92 | } | 98 | } |
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 5a44132fc..75ef308ae 100644 --- a/crates/ra_hir/src/function.rs +++ b/crates/ra_hir/src/function.rs | |||
@@ -11,11 +11,11 @@ use ra_syntax::{ | |||
11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module}; | 14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock}; |
15 | 15 | ||
16 | pub use self::scope::FnScopes; | 16 | pub use self::scope::FnScopes; |
17 | 17 | ||
18 | #[derive(Debug)] | 18 | #[derive(Debug, Clone, PartialEq, Eq)] |
19 | pub struct Function { | 19 | pub struct Function { |
20 | def_id: DefId, | 20 | def_id: DefId, |
21 | } | 21 | } |
@@ -25,6 +25,10 @@ impl Function { | |||
25 | Function { def_id } | 25 | Function { def_id } |
26 | } | 26 | } |
27 | 27 | ||
28 | pub fn def_id(&self) -> DefId { | ||
29 | self.def_id | ||
30 | } | ||
31 | |||
28 | pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { | 32 | pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { |
29 | let def_loc = self.def_id.loc(db); | 33 | let def_loc = self.def_id.loc(db); |
30 | assert!(def_loc.kind == DefKind::Function); | 34 | assert!(def_loc.kind == DefKind::Function); |
@@ -48,6 +52,15 @@ impl Function { | |||
48 | pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { | 52 | pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { |
49 | self.def_id.module(db) | 53 | self.def_id.module(db) |
50 | } | 54 | } |
55 | |||
56 | pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> { | ||
57 | self.def_id.krate(db) | ||
58 | } | ||
59 | |||
60 | /// The containing impl block, if this is a method. | ||
61 | pub fn impl_block(&self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> { | ||
62 | self.def_id.impl_block(db) | ||
63 | } | ||
51 | } | 64 | } |
52 | 65 | ||
53 | #[derive(Debug, Clone)] | 66 | #[derive(Debug, Clone)] |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 66adacc7d..c98be66f9 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -2,7 +2,7 @@ use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId}; | |||
2 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; | 2 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; |
3 | use ra_arena::{Arena, RawId, impl_arena_id}; | 3 | use ra_arena::{Arena, RawId, impl_arena_id}; |
4 | 4 | ||
5 | use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum}; | 5 | use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate}; |
6 | 6 | ||
7 | /// hir makes a heavy use of ids: integer (u32) handlers to various things. You | 7 | /// hir makes a heavy use of ids: integer (u32) handlers to various things. You |
8 | /// can think of id as a pointer (but without a lifetime) or a file descriptor | 8 | /// can think of id as a pointer (but without a lifetime) or a file descriptor |
@@ -177,6 +177,17 @@ impl DefId { | |||
177 | let loc = self.loc(db); | 177 | let loc = self.loc(db); |
178 | Module::new(db, loc.source_root_id, loc.module_id) | 178 | Module::new(db, loc.source_root_id, loc.module_id) |
179 | } | 179 | } |
180 | |||
181 | /// Returns the containing crate. | ||
182 | pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> { | ||
183 | Ok(self.module(db)?.krate(db)) | ||
184 | } | ||
185 | |||
186 | /// Returns the containing impl block, if this is an impl item. | ||
187 | pub fn impl_block(self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> { | ||
188 | let crate_impls = db.impls_in_crate(ctry!(self.krate(db)?))?; | ||
189 | Ok(ImplBlock::containing(crate_impls, self)) | ||
190 | } | ||
180 | } | 191 | } |
181 | 192 | ||
182 | impl DefLoc { | 193 | impl DefLoc { |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs new file mode 100644 index 000000000..22f0a4461 --- /dev/null +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -0,0 +1,172 @@ | |||
1 | use std::sync::Arc; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
5 | use ra_syntax::ast::{self, AstNode}; | ||
6 | use ra_db::{LocationIntener, Cancelable}; | ||
7 | |||
8 | use crate::{ | ||
9 | Crate, DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, | ||
10 | Module, Function, | ||
11 | db::HirDatabase, | ||
12 | type_ref::TypeRef, | ||
13 | module::{ModuleSourceNode}, | ||
14 | }; | ||
15 | |||
16 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
17 | pub struct ImplBlock { | ||
18 | crate_impl_blocks: Arc<CrateImplBlocks>, | ||
19 | impl_id: ImplId, | ||
20 | } | ||
21 | |||
22 | impl ImplBlock { | ||
23 | pub(crate) fn containing( | ||
24 | crate_impl_blocks: Arc<CrateImplBlocks>, | ||
25 | def_id: DefId, | ||
26 | ) -> Option<ImplBlock> { | ||
27 | let impl_id = *crate_impl_blocks.impls_by_def.get(&def_id)?; | ||
28 | Some(ImplBlock { | ||
29 | crate_impl_blocks, | ||
30 | impl_id, | ||
31 | }) | ||
32 | } | ||
33 | |||
34 | fn impl_data(&self) -> &ImplData { | ||
35 | &self.crate_impl_blocks.impls[self.impl_id] | ||
36 | } | ||
37 | |||
38 | pub fn target(&self) -> &TypeRef { | ||
39 | &self.impl_data().impl_for | ||
40 | } | ||
41 | |||
42 | pub fn items(&self) -> &[ImplItem] { | ||
43 | &self.impl_data().items | ||
44 | } | ||
45 | } | ||
46 | |||
47 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
48 | pub struct ImplData { | ||
49 | impl_for: TypeRef, | ||
50 | items: Vec<ImplItem>, | ||
51 | } | ||
52 | |||
53 | impl ImplData { | ||
54 | pub(crate) fn from_ast( | ||
55 | db: &impl AsRef<LocationIntener<DefLoc, DefId>>, | ||
56 | file_items: &SourceFileItems, | ||
57 | module: &Module, | ||
58 | node: ast::ImplBlock, | ||
59 | ) -> Self { | ||
60 | let impl_for = TypeRef::from_ast_opt(node.target_type()); | ||
61 | let file_id = module.source().file_id(); | ||
62 | let items = if let Some(item_list) = node.item_list() { | ||
63 | item_list | ||
64 | .impl_items() | ||
65 | .map(|item_node| { | ||
66 | let kind = match item_node { | ||
67 | ast::ImplItem::FnDef(..) => DefKind::Function, | ||
68 | ast::ImplItem::ConstDef(..) => DefKind::Item, | ||
69 | ast::ImplItem::TypeDef(..) => DefKind::Item, | ||
70 | }; | ||
71 | let item_id = file_items.id_of_unchecked(item_node.syntax()); | ||
72 | let def_loc = DefLoc { | ||
73 | kind, | ||
74 | source_root_id: module.source_root_id, | ||
75 | module_id: module.module_id, | ||
76 | source_item_id: SourceItemId { | ||
77 | file_id, | ||
78 | item_id: Some(item_id), | ||
79 | }, | ||
80 | }; | ||
81 | let def_id = def_loc.id(db); | ||
82 | match item_node { | ||
83 | ast::ImplItem::FnDef(..) => ImplItem::Method(Function::new(def_id)), | ||
84 | ast::ImplItem::ConstDef(..) => ImplItem::Const(def_id), | ||
85 | ast::ImplItem::TypeDef(..) => ImplItem::Type(def_id), | ||
86 | } | ||
87 | }) | ||
88 | .collect() | ||
89 | } else { | ||
90 | Vec::new() | ||
91 | }; | ||
92 | ImplData { impl_for, items } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
97 | pub enum ImplItem { | ||
98 | Method(Function), | ||
99 | // these don't have their own types yet | ||
100 | Const(DefId), | ||
101 | Type(DefId), | ||
102 | // Existential | ||
103 | } | ||
104 | |||
105 | impl ImplItem { | ||
106 | pub fn def_id(&self) -> DefId { | ||
107 | match self { | ||
108 | ImplItem::Method(f) => f.def_id(), | ||
109 | ImplItem::Const(def_id) => *def_id, | ||
110 | ImplItem::Type(def_id) => *def_id, | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
116 | pub struct ImplId(pub RawId); | ||
117 | impl_arena_id!(ImplId); | ||
118 | |||
119 | /// We have to collect all impl blocks in a crate, to later be able to find | ||
120 | /// impls for specific types. | ||
121 | #[derive(Debug, PartialEq, Eq)] | ||
122 | pub struct CrateImplBlocks { | ||
123 | impls: Arena<ImplId, ImplData>, | ||
124 | impls_by_def: FxHashMap<DefId, ImplId>, | ||
125 | } | ||
126 | |||
127 | impl CrateImplBlocks { | ||
128 | fn new() -> Self { | ||
129 | CrateImplBlocks { | ||
130 | impls: Arena::default(), | ||
131 | impls_by_def: FxHashMap::default(), | ||
132 | } | ||
133 | } | ||
134 | |||
135 | fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> { | ||
136 | let module_source_node = module.source().resolve(db); | ||
137 | let node = match &module_source_node { | ||
138 | ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(), | ||
139 | ModuleSourceNode::Module(node) => node.borrowed().syntax(), | ||
140 | }; | ||
141 | |||
142 | let source_file_items = db.file_items(module.source().file_id()); | ||
143 | |||
144 | for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { | ||
145 | let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast); | ||
146 | let id = self.impls.alloc(impl_block); | ||
147 | for impl_item in &self.impls[id].items { | ||
148 | self.impls_by_def.insert(impl_item.def_id(), id); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | for (_, child) in module.children() { | ||
153 | self.collect(db, child)?; | ||
154 | } | ||
155 | |||
156 | Ok(()) | ||
157 | } | ||
158 | } | ||
159 | |||
160 | pub(crate) fn impls_in_crate( | ||
161 | db: &impl HirDatabase, | ||
162 | krate: Crate, | ||
163 | ) -> Cancelable<Arc<CrateImplBlocks>> { | ||
164 | let mut result = CrateImplBlocks::new(); | ||
165 | let root_module = if let Some(root) = krate.root_module(db)? { | ||
166 | root | ||
167 | } else { | ||
168 | return Ok(Arc::new(result)); | ||
169 | }; | ||
170 | result.collect(db, root_module)?; | ||
171 | Ok(Arc::new(result)) | ||
172 | } | ||
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs index a0821d15d..5194e280b 100644 --- a/crates/ra_hir/src/krate.rs +++ b/crates/ra_hir/src/krate.rs | |||
@@ -5,7 +5,7 @@ use crate::{HirDatabase, Module, Name, AsName, HirFileId}; | |||
5 | /// hir::Crate describes a single crate. It's the main inteface with which | 5 | /// hir::Crate describes a single crate. It's the main inteface with which |
6 | /// crate's dependencies interact. Mostly, it should be just a proxy for the | 6 | /// crate's dependencies interact. Mostly, it should be just a proxy for the |
7 | /// root module. | 7 | /// root module. |
8 | #[derive(Debug)] | 8 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
9 | pub struct Crate { | 9 | pub struct Crate { |
10 | crate_id: CrateId, | 10 | crate_id: CrateId, |
11 | } | 11 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 344b543b6..2abcec441 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -31,6 +31,7 @@ mod function; | |||
31 | mod adt; | 31 | mod adt; |
32 | mod type_ref; | 32 | mod type_ref; |
33 | mod ty; | 33 | mod ty; |
34 | mod impl_block; | ||
34 | 35 | ||
35 | use crate::{ | 36 | use crate::{ |
36 | db::HirDatabase, | 37 | db::HirDatabase, |
@@ -48,6 +49,7 @@ pub use self::{ | |||
48 | function::{Function, FnScopes}, | 49 | function::{Function, FnScopes}, |
49 | adt::{Struct, Enum}, | 50 | adt::{Struct, Enum}, |
50 | ty::Ty, | 51 | ty::Ty, |
52 | impl_block::{ImplBlock, ImplItem}, | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | pub use self::function::FnSignatureInfo; | 55 | pub use self::function::FnSignatureInfo; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 89b18194a..ef245ec7a 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -203,6 +203,7 @@ salsa::database_storage! { | |||
203 | fn type_for_field() for db::TypeForFieldQuery; | 203 | fn type_for_field() for db::TypeForFieldQuery; |
204 | fn struct_data() for db::StructDataQuery; | 204 | fn struct_data() for db::StructDataQuery; |
205 | fn enum_data() for db::EnumDataQuery; | 205 | fn enum_data() for db::EnumDataQuery; |
206 | fn impls_in_crate() for db::ImplsInCrateQuery; | ||
206 | } | 207 | } |
207 | } | 208 | } |
208 | } | 209 | } |
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index c70dc54dd..b9821115c 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs | |||
@@ -71,6 +71,21 @@ impl Module { | |||
71 | }) | 71 | }) |
72 | } | 72 | } |
73 | 73 | ||
74 | /// Returns an iterator of all children of this module. | ||
75 | pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a { | ||
76 | self.module_id | ||
77 | .children(&self.tree) | ||
78 | .map(move |(name, module_id)| { | ||
79 | ( | ||
80 | name, | ||
81 | Module { | ||
82 | module_id, | ||
83 | ..self.clone() | ||
84 | }, | ||
85 | ) | ||
86 | }) | ||
87 | } | ||
88 | |||
74 | /// Returns the crate this module is part of. | 89 | /// Returns the crate this module is part of. |
75 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | 90 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { |
76 | let root_id = self.module_id.crate_root(&self.tree); | 91 | let root_id = self.module_id.crate_root(&self.tree); |