aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ids.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r--crates/ra_hir/src/ids.rs197
1 files changed, 45 insertions, 152 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 18401f865..eb9939df7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,16 +1,15 @@
1use std::{ 1use std::{
2 marker::PhantomData,
3 hash::{Hash, Hasher}, 2 hash::{Hash, Hasher},
4 sync::Arc, 3 sync::Arc,
5}; 4};
6 5
7use ra_db::{LocationInterner, FileId}; 6use ra_db::{LocationInterner, FileId};
8use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; 7use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 8use ra_arena::{RawId, ArenaId, impl_arena_id};
9use mbe::MacroRules;
10 10
11use crate::{ 11use crate::{
12 Module, 12 Module, DefDatabase, AstId, FileAstId,
13 DefDatabase,
14}; 13};
15 14
16#[derive(Debug, Default)] 15#[derive(Debug, Default)]
@@ -22,7 +21,7 @@ pub struct HirInterner {
22 consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>, 21 consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>,
23 statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>, 22 statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>,
24 traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>, 23 traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>,
25 types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeId>, 24 types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeAliasId>,
26} 25}
27 26
28impl HirInterner { 27impl HirInterner {
@@ -68,7 +67,7 @@ impl HirFileId {
68 HirFileIdRepr::File(file_id) => file_id, 67 HirFileIdRepr::File(file_id) => file_id,
69 HirFileIdRepr::Macro(macro_call_id) => { 68 HirFileIdRepr::Macro(macro_call_id) => {
70 let loc = macro_call_id.loc(db); 69 let loc = macro_call_id.loc(db);
71 loc.source_item_id.file_id.original_file(db) 70 loc.ast_id.file_id().original_file(db)
72 } 71 }
73 } 72 }
74 } 73 }
@@ -83,7 +82,10 @@ impl HirFileId {
83 } 82 }
84 } 83 }
85 84
86 pub(crate) fn hir_parse(db: &impl DefDatabase, file_id: HirFileId) -> TreeArc<SourceFile> { 85 pub(crate) fn hir_parse_query(
86 db: &impl DefDatabase,
87 file_id: HirFileId,
88 ) -> TreeArc<SourceFile> {
87 match file_id.0 { 89 match file_id.0 {
88 HirFileIdRepr::File(file_id) => db.parse(file_id), 90 HirFileIdRepr::File(file_id) => db.parse(file_id),
89 HirFileIdRepr::Macro(macro_call_id) => { 91 HirFileIdRepr::Macro(macro_call_id) => {
@@ -96,14 +98,10 @@ impl HirFileId {
96 98
97fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<TreeArc<SourceFile>> { 99fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<TreeArc<SourceFile>> {
98 let loc = macro_call_id.loc(db); 100 let loc = macro_call_id.loc(db);
99 let syntax = db.file_item(loc.source_item_id); 101 let macro_call = loc.ast_id.to_node(db);
100 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
101 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; 102 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?;
102 103
103 let def_map = db.crate_def_map(loc.module.krate); 104 let macro_rules = db.macro_def(loc.def)?;
104 let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?;
105 let def_map = db.crate_def_map(krate);
106 let macro_rules = &def_map[macro_id];
107 let tt = macro_rules.expand(&macro_arg).ok()?; 105 let tt = macro_rules.expand(&macro_arg).ok()?;
108 Some(mbe::token_tree_to_ast_item_list(&tt)) 106 Some(mbe::token_tree_to_ast_item_list(&tt))
109} 107}
@@ -126,6 +124,17 @@ impl From<MacroCallId> for HirFileId {
126 } 124 }
127} 125}
128 126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);
129
130pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
131 let macro_call = id.0.to_node(db);
132 let arg = macro_call.token_tree()?;
133 let (tt, _) = mbe::ast_to_token_tree(arg)?;
134 let rules = MacroRules::parse(&tt).ok()?;
135 Some(Arc::new(rules))
136}
137
129/// `MacroCallId` identifies a particular macro invocation, like 138/// `MacroCallId` identifies a particular macro invocation, like
130/// `println!("Hello, {}", world)`. 139/// `println!("Hello, {}", world)`.
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -134,8 +143,8 @@ impl_arena_id!(MacroCallId);
134 143
135#[derive(Debug, Clone, PartialEq, Eq, Hash)] 144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
136pub struct MacroCallLoc { 145pub struct MacroCallLoc {
137 pub(crate) module: Module, 146 pub(crate) def: MacroDefId,
138 pub(crate) source_item_id: SourceItemId, 147 pub(crate) ast_id: AstId<ast::MacroCall>,
139} 148}
140 149
141impl MacroCallId { 150impl MacroCallId {
@@ -145,7 +154,6 @@ impl MacroCallId {
145} 154}
146 155
147impl MacroCallLoc { 156impl MacroCallLoc {
148 #[allow(unused)]
149 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId { 157 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId {
150 db.as_ref().macros.loc2id(&self) 158 db.as_ref().macros.loc2id(&self)
151 } 159 }
@@ -154,26 +162,25 @@ impl MacroCallLoc {
154#[derive(Debug)] 162#[derive(Debug)]
155pub struct ItemLoc<N: AstNode> { 163pub struct ItemLoc<N: AstNode> {
156 pub(crate) module: Module, 164 pub(crate) module: Module,
157 raw: SourceItemId, 165 ast_id: AstId<N>,
158 _ty: PhantomData<N>,
159} 166}
160 167
161impl<N: AstNode> PartialEq for ItemLoc<N> { 168impl<N: AstNode> PartialEq for ItemLoc<N> {
162 fn eq(&self, other: &Self) -> bool { 169 fn eq(&self, other: &Self) -> bool {
163 self.module == other.module && self.raw == other.raw 170 self.module == other.module && self.ast_id == other.ast_id
164 } 171 }
165} 172}
166impl<N: AstNode> Eq for ItemLoc<N> {} 173impl<N: AstNode> Eq for ItemLoc<N> {}
167impl<N: AstNode> Hash for ItemLoc<N> { 174impl<N: AstNode> Hash for ItemLoc<N> {
168 fn hash<H: Hasher>(&self, hasher: &mut H) { 175 fn hash<H: Hasher>(&self, hasher: &mut H) {
169 self.module.hash(hasher); 176 self.module.hash(hasher);
170 self.raw.hash(hasher); 177 self.ast_id.hash(hasher);
171 } 178 }
172} 179}
173 180
174impl<N: AstNode> Clone for ItemLoc<N> { 181impl<N: AstNode> Clone for ItemLoc<N> {
175 fn clone(&self) -> ItemLoc<N> { 182 fn clone(&self) -> ItemLoc<N> {
176 ItemLoc { module: self.module, raw: self.raw, _ty: PhantomData } 183 ItemLoc { module: self.module, ast_id: self.ast_id }
177 } 184 }
178} 185}
179 186
@@ -200,26 +207,19 @@ impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
200pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { 207pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
201 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>; 208 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>;
202 fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self { 209 fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self {
203 let items = ctx.db.file_items(ctx.file_id); 210 let items = ctx.db.ast_id_map(ctx.file_id);
204 let item_id = items.id_of(ctx.file_id, ast.syntax()); 211 let item_id = items.ast_id(ast);
205 Self::from_source_item_id_unchecked(ctx, item_id) 212 Self::from_ast_id(ctx, item_id)
206 } 213 }
207 fn from_source_item_id_unchecked( 214 fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
208 ctx: LocationCtx<&impl DefDatabase>, 215 let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
209 item_id: SourceFileItemId,
210 ) -> Self {
211 let raw = SourceItemId { file_id: ctx.file_id, item_id };
212 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData };
213
214 Self::interner(ctx.db.as_ref()).loc2id(&loc) 216 Self::interner(ctx.db.as_ref()).loc2id(&loc)
215 } 217 }
216 fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) { 218 fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) {
217 let int = Self::interner(db.as_ref()); 219 let int = Self::interner(db.as_ref());
218 let loc = int.id2loc(self); 220 let loc = int.id2loc(self);
219 let syntax = db.file_item(loc.raw); 221 let ast = loc.ast_id.to_node(db);
220 let ast = 222 (loc.ast_id.file_id(), ast)
221 N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
222 (loc.raw.file_id, ast)
223 } 223 }
224 fn module(self, db: &impl DefDatabase) -> Module { 224 fn module(self, db: &impl DefDatabase) -> Module {
225 let int = Self::interner(db.as_ref()); 225 let int = Self::interner(db.as_ref());
@@ -229,7 +229,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
229} 229}
230 230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
232pub struct FunctionId(RawId); 232pub(crate) struct FunctionId(RawId);
233impl_arena_id!(FunctionId); 233impl_arena_id!(FunctionId);
234impl AstItemDef<ast::FnDef> for FunctionId { 234impl AstItemDef<ast::FnDef> for FunctionId {
235 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> { 235 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> {
@@ -238,7 +238,7 @@ impl AstItemDef<ast::FnDef> for FunctionId {
238} 238}
239 239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
241pub struct StructId(RawId); 241pub(crate) struct StructId(RawId);
242impl_arena_id!(StructId); 242impl_arena_id!(StructId);
243impl AstItemDef<ast::StructDef> for StructId { 243impl AstItemDef<ast::StructDef> for StructId {
244 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> { 244 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> {
@@ -247,7 +247,7 @@ impl AstItemDef<ast::StructDef> for StructId {
247} 247}
248 248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
250pub struct EnumId(RawId); 250pub(crate) struct EnumId(RawId);
251impl_arena_id!(EnumId); 251impl_arena_id!(EnumId);
252impl AstItemDef<ast::EnumDef> for EnumId { 252impl AstItemDef<ast::EnumDef> for EnumId {
253 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> { 253 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> {
@@ -256,7 +256,7 @@ impl AstItemDef<ast::EnumDef> for EnumId {
256} 256}
257 257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct ConstId(RawId); 259pub(crate) struct ConstId(RawId);
260impl_arena_id!(ConstId); 260impl_arena_id!(ConstId);
261impl AstItemDef<ast::ConstDef> for ConstId { 261impl AstItemDef<ast::ConstDef> for ConstId {
262 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> { 262 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> {
@@ -265,7 +265,7 @@ impl AstItemDef<ast::ConstDef> for ConstId {
265} 265}
266 266
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268pub struct StaticId(RawId); 268pub(crate) struct StaticId(RawId);
269impl_arena_id!(StaticId); 269impl_arena_id!(StaticId);
270impl AstItemDef<ast::StaticDef> for StaticId { 270impl AstItemDef<ast::StaticDef> for StaticId {
271 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> { 271 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> {
@@ -274,7 +274,7 @@ impl AstItemDef<ast::StaticDef> for StaticId {
274} 274}
275 275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
277pub struct TraitId(RawId); 277pub(crate) struct TraitId(RawId);
278impl_arena_id!(TraitId); 278impl_arena_id!(TraitId);
279impl AstItemDef<ast::TraitDef> for TraitId { 279impl AstItemDef<ast::TraitDef> for TraitId {
280 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> { 280 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> {
@@ -283,117 +283,10 @@ impl AstItemDef<ast::TraitDef> for TraitId {
283} 283}
284 284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
286pub struct TypeId(RawId); 286pub(crate) struct TypeAliasId(RawId);
287impl_arena_id!(TypeId); 287impl_arena_id!(TypeAliasId);
288impl AstItemDef<ast::TypeAliasDef> for TypeId { 288impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
289 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> { 289 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> {
290 &interner.types 290 &interner.types
291 } 291 }
292} 292}
293
294/// Identifier of item within a specific file. This is stable over reparses, so
295/// it's OK to use it as a salsa key/value.
296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
297pub struct SourceFileItemId(RawId);
298impl_arena_id!(SourceFileItemId);
299
300impl SourceFileItemId {
301 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
302 SourceItemId { file_id, item_id: self }
303 }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
307pub struct SourceItemId {
308 pub(crate) file_id: HirFileId,
309 pub(crate) item_id: SourceFileItemId,
310}
311
312/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
313#[derive(Debug, PartialEq, Eq)]
314pub struct SourceFileItems {
315 file_id: HirFileId,
316 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
317}
318
319impl SourceFileItems {
320 pub(crate) fn file_items_query(
321 db: &impl DefDatabase,
322 file_id: HirFileId,
323 ) -> Arc<SourceFileItems> {
324 let source_file = db.hir_parse(file_id);
325 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
326 }
327
328 pub(crate) fn file_item_query(
329 db: &impl DefDatabase,
330 source_item_id: SourceItemId,
331 ) -> TreeArc<SyntaxNode> {
332 let source_file = db.hir_parse(source_item_id.file_id);
333 db.file_items(source_item_id.file_id)[source_item_id.item_id]
334 .to_node(&source_file)
335 .to_owned()
336 }
337
338 pub(crate) fn from_source_file(
339 source_file: &SourceFile,
340 file_id: HirFileId,
341 ) -> SourceFileItems {
342 let mut res = SourceFileItems { file_id, arena: Arena::default() };
343 // By walking the tree in bread-first order we make sure that parents
344 // get lower ids then children. That is, adding a new child does not
345 // change parent's id. This means that, say, adding a new function to a
346 // trait does not change ids of top-level items, which helps caching.
347 bfs(source_file.syntax(), |it| {
348 if let Some(module_item) = ast::ModuleItem::cast(it) {
349 res.alloc(module_item.syntax());
350 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
351 res.alloc(macro_call.syntax());
352 }
353 });
354 res
355 }
356
357 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
358 self.arena.alloc(SyntaxNodePtr::new(item))
359 }
360 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
361 assert_eq!(
362 self.file_id, file_id,
363 "SourceFileItems: wrong file, expected {:?}, got {:?}",
364 self.file_id, file_id
365 );
366 self.id_of_unchecked(item)
367 }
368 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
369 let ptr = SyntaxNodePtr::new(item);
370 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
371 return id;
372 }
373 panic!(
374 "Can't find {:?} in SourceFileItems:\n{:?}",
375 item,
376 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
377 );
378 }
379}
380
381impl std::ops::Index<SourceFileItemId> for SourceFileItems {
382 type Output = SyntaxNodePtr;
383 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
384 &self.arena[idx]
385 }
386}
387
388/// Walks the subtree in bfs order, calling `f` for each node.
389fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
390 let mut curr_layer = vec![node];
391 let mut next_layer = vec![];
392 while !curr_layer.is_empty() {
393 curr_layer.drain(..).for_each(|node| {
394 next_layer.extend(node.children());
395 f(node);
396 });
397 std::mem::swap(&mut curr_layer, &mut next_layer);
398 }
399}