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.rs246
1 files changed, 35 insertions, 211 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 499dcafea..dea288eb7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,168 +1,21 @@
1//! FIXME: write short doc here 1//! hir makes heavy use of ids: integer (u32) handlers to various things. You
2//! can think of id as a pointer (but without a lifetime) or a file descriptor
3//! (but for hir objects).
4//!
5//! This module defines a bunch of ids we are using. The most important ones are
6//! probably `HirFileId` and `DefId`.
2 7
3use std::{ 8use std::hash::{Hash, Hasher};
4 hash::{Hash, Hasher},
5 sync::Arc,
6};
7 9
8use mbe::MacroRules; 10use ra_db::salsa;
9use ra_db::{salsa, FileId}; 11use ra_syntax::{ast, AstNode};
10use ra_prof::profile;
11use ra_syntax::{ast, AstNode, Parse, SyntaxNode};
12 12
13use crate::{ 13use crate::{
14 db::{AstDatabase, DefDatabase, InternDatabase}, 14 db::{AstDatabase, InternDatabase},
15 AstId, Crate, FileAstId, Module, Source, 15 AstId, FileAstId, Module, Source,
16}; 16};
17 17
18/// hir makes heavy use of ids: integer (u32) handlers to various things. You 18pub use hir_expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind};
19/// can think of id as a pointer (but without a lifetime) or a file descriptor
20/// (but for hir objects).
21///
22/// This module defines a bunch of ids we are using. The most important ones are
23/// probably `HirFileId` and `DefId`.
24
25/// Input to the analyzer is a set of files, where each file is identified by
26/// `FileId` and contains source code. However, another source of source code in
27/// Rust are macros: each macro can be thought of as producing a "temporary
28/// file". To assign an id to such a file, we use the id of the macro call that
29/// produced the file. So, a `HirFileId` is either a `FileId` (source code
30/// written by user), or a `MacroCallId` (source code produced by macro).
31///
32/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
33/// containing the call plus the offset of the macro call in the file. Note that
34/// this is a recursive definition! However, the size_of of `HirFileId` is
35/// finite (because everything bottoms out at the real `FileId`) and small
36/// (`MacroCallId` uses the location interner).
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct HirFileId(HirFileIdRepr);
39
40impl HirFileId {
41 /// For macro-expansion files, returns the file original source file the
42 /// expansion originated from.
43 pub fn original_file(self, db: &impl InternDatabase) -> FileId {
44 match self.0 {
45 HirFileIdRepr::File(file_id) => file_id,
46 HirFileIdRepr::Macro(macro_file) => {
47 let loc = macro_file.macro_call_id.loc(db);
48 loc.ast_id.file_id().original_file(db)
49 }
50 }
51 }
52
53 /// Get the crate which the macro lives in, if it is a macro file.
54 pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
55 match self.0 {
56 HirFileIdRepr::File(_) => None,
57 HirFileIdRepr::Macro(macro_file) => {
58 let loc = macro_file.macro_call_id.loc(db);
59 Some(loc.def.krate)
60 }
61 }
62 }
63
64 pub(crate) fn parse_or_expand_query(
65 db: &impl AstDatabase,
66 file_id: HirFileId,
67 ) -> Option<SyntaxNode> {
68 match file_id.0 {
69 HirFileIdRepr::File(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
70 HirFileIdRepr::Macro(macro_file) => {
71 db.parse_macro(macro_file).map(|it| it.syntax_node())
72 }
73 }
74 }
75
76 pub(crate) fn parse_macro_query(
77 db: &impl AstDatabase,
78 macro_file: MacroFile,
79 ) -> Option<Parse<SyntaxNode>> {
80 let _p = profile("parse_macro_query");
81 let macro_call_id = macro_file.macro_call_id;
82 let tt = db
83 .macro_expand(macro_call_id)
84 .map_err(|err| {
85 // Note:
86 // The final goal we would like to make all parse_macro success,
87 // such that the following log will not call anyway.
88 log::warn!("fail on macro_parse: (reason: {})", err,);
89 })
90 .ok()?;
91 match macro_file.macro_file_kind {
92 MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
93 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99enum HirFileIdRepr {
100 File(FileId),
101 Macro(MacroFile),
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105pub struct MacroFile {
106 macro_call_id: MacroCallId,
107 macro_file_kind: MacroFileKind,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub(crate) enum MacroFileKind {
112 Items,
113 Expr,
114}
115
116impl From<FileId> for HirFileId {
117 fn from(file_id: FileId) -> HirFileId {
118 HirFileId(HirFileIdRepr::File(file_id))
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123pub struct MacroDefId {
124 pub(crate) ast_id: AstId<ast::MacroCall>,
125 pub(crate) krate: Crate,
126}
127
128pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
129 let macro_call = id.ast_id.to_node(db);
130 let arg = macro_call.token_tree()?;
131 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
132 log::warn!("fail on macro_def to token tree: {:#?}", arg);
133 None
134 })?;
135 let rules = MacroRules::parse(&tt).ok().or_else(|| {
136 log::warn!("fail on macro_def parse: {:#?}", tt);
137 None
138 })?;
139 Some(Arc::new(rules))
140}
141
142pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
143 let loc = id.loc(db);
144 let macro_call = loc.ast_id.to_node(db);
145 let arg = macro_call.token_tree()?;
146 let (tt, _) = mbe::ast_to_token_tree(&arg)?;
147 Some(Arc::new(tt))
148}
149
150pub(crate) fn macro_expand_query(
151 db: &impl AstDatabase,
152 id: MacroCallId,
153) -> Result<Arc<tt::Subtree>, String> {
154 let loc = id.loc(db);
155 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;
156
157 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
158 let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;
159 // Set a hard limit for the expanded tt
160 let count = tt.count();
161 if count > 65536 {
162 return Err(format!("Total tokens count exceed limit : count = {}", count));
163 }
164 Ok(Arc::new(tt))
165}
166 19
167macro_rules! impl_intern_key { 20macro_rules! impl_intern_key {
168 ($name:ident) => { 21 ($name:ident) => {
@@ -177,35 +30,6 @@ macro_rules! impl_intern_key {
177 }; 30 };
178} 31}
179 32
180/// `MacroCallId` identifies a particular macro invocation, like
181/// `println!("Hello, {}", world)`.
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
183pub struct MacroCallId(salsa::InternId);
184impl_intern_key!(MacroCallId);
185
186#[derive(Debug, Clone, PartialEq, Eq, Hash)]
187pub struct MacroCallLoc {
188 pub(crate) def: MacroDefId,
189 pub(crate) ast_id: AstId<ast::MacroCall>,
190}
191
192impl MacroCallId {
193 pub(crate) fn loc(self, db: &impl InternDatabase) -> MacroCallLoc {
194 db.lookup_intern_macro(self)
195 }
196
197 pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId {
198 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
199 HirFileId(HirFileIdRepr::Macro(macro_file))
200 }
201}
202
203impl MacroCallLoc {
204 pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId {
205 db.intern_macro(self)
206 }
207}
208
209#[derive(Debug)] 33#[derive(Debug)]
210pub struct ItemLoc<N: AstNode> { 34pub struct ItemLoc<N: AstNode> {
211 pub(crate) module: Module, 35 pub(crate) module: Module,
@@ -238,13 +62,13 @@ pub(crate) struct LocationCtx<DB> {
238 file_id: HirFileId, 62 file_id: HirFileId,
239} 63}
240 64
241impl<'a, DB: DefDatabase> LocationCtx<&'a DB> { 65impl<'a, DB> LocationCtx<&'a DB> {
242 pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> { 66 pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
243 LocationCtx { db, module, file_id } 67 LocationCtx { db, module, file_id }
244 } 68 }
245} 69}
246 70
247impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> { 71impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> {
248 pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF 72 pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
249 where 73 where
250 N: AstNode, 74 N: AstNode,
@@ -255,24 +79,24 @@ impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> {
255} 79}
256 80
257pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { 81pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
258 fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self; 82 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
259 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>; 83 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
260 84
261 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + DefDatabase)>, ast: &N) -> Self { 85 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self {
262 let items = ctx.db.ast_id_map(ctx.file_id); 86 let items = ctx.db.ast_id_map(ctx.file_id);
263 let item_id = items.ast_id(ast); 87 let item_id = items.ast_id(ast);
264 Self::from_ast_id(ctx, item_id) 88 Self::from_ast_id(ctx, item_id)
265 } 89 }
266 fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self { 90 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
267 let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) }; 91 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
268 Self::intern(ctx.db, loc) 92 Self::intern(ctx.db, loc)
269 } 93 }
270 fn source(self, db: &(impl AstDatabase + DefDatabase)) -> Source<N> { 94 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> {
271 let loc = self.lookup_intern(db); 95 let loc = self.lookup_intern(db);
272 let ast = loc.ast_id.to_node(db); 96 let ast = loc.ast_id.to_node(db);
273 Source { file_id: loc.ast_id.file_id(), ast } 97 Source { file_id: loc.ast_id.file_id(), ast }
274 } 98 }
275 fn module(self, db: &impl DefDatabase) -> Module { 99 fn module(self, db: &impl InternDatabase) -> Module {
276 let loc = self.lookup_intern(db); 100 let loc = self.lookup_intern(db);
277 loc.module 101 loc.module
278 } 102 }
@@ -283,10 +107,10 @@ pub struct FunctionId(salsa::InternId);
283impl_intern_key!(FunctionId); 107impl_intern_key!(FunctionId);
284 108
285impl AstItemDef<ast::FnDef> for FunctionId { 109impl AstItemDef<ast::FnDef> for FunctionId {
286 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self { 110 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
287 db.intern_function(loc) 111 db.intern_function(loc)
288 } 112 }
289 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> { 113 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> {
290 db.lookup_intern_function(self) 114 db.lookup_intern_function(self)
291 } 115 }
292} 116}
@@ -295,10 +119,10 @@ impl AstItemDef<ast::FnDef> for FunctionId {
295pub struct StructId(salsa::InternId); 119pub struct StructId(salsa::InternId);
296impl_intern_key!(StructId); 120impl_intern_key!(StructId);
297impl AstItemDef<ast::StructDef> for StructId { 121impl AstItemDef<ast::StructDef> for StructId {
298 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self { 122 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
299 db.intern_struct(loc) 123 db.intern_struct(loc)
300 } 124 }
301 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> { 125 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
302 db.lookup_intern_struct(self) 126 db.lookup_intern_struct(self)
303 } 127 }
304} 128}
@@ -307,10 +131,10 @@ impl AstItemDef<ast::StructDef> for StructId {
307pub struct EnumId(salsa::InternId); 131pub struct EnumId(salsa::InternId);
308impl_intern_key!(EnumId); 132impl_intern_key!(EnumId);
309impl AstItemDef<ast::EnumDef> for EnumId { 133impl AstItemDef<ast::EnumDef> for EnumId {
310 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self { 134 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
311 db.intern_enum(loc) 135 db.intern_enum(loc)
312 } 136 }
313 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> { 137 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
314 db.lookup_intern_enum(self) 138 db.lookup_intern_enum(self)
315 } 139 }
316} 140}
@@ -319,10 +143,10 @@ impl AstItemDef<ast::EnumDef> for EnumId {
319pub struct ConstId(salsa::InternId); 143pub struct ConstId(salsa::InternId);
320impl_intern_key!(ConstId); 144impl_intern_key!(ConstId);
321impl AstItemDef<ast::ConstDef> for ConstId { 145impl AstItemDef<ast::ConstDef> for ConstId {
322 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self { 146 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
323 db.intern_const(loc) 147 db.intern_const(loc)
324 } 148 }
325 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> { 149 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> {
326 db.lookup_intern_const(self) 150 db.lookup_intern_const(self)
327 } 151 }
328} 152}
@@ -331,10 +155,10 @@ impl AstItemDef<ast::ConstDef> for ConstId {
331pub struct StaticId(salsa::InternId); 155pub struct StaticId(salsa::InternId);
332impl_intern_key!(StaticId); 156impl_intern_key!(StaticId);
333impl AstItemDef<ast::StaticDef> for StaticId { 157impl AstItemDef<ast::StaticDef> for StaticId {
334 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self { 158 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
335 db.intern_static(loc) 159 db.intern_static(loc)
336 } 160 }
337 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> { 161 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
338 db.lookup_intern_static(self) 162 db.lookup_intern_static(self)
339 } 163 }
340} 164}
@@ -343,10 +167,10 @@ impl AstItemDef<ast::StaticDef> for StaticId {
343pub struct TraitId(salsa::InternId); 167pub struct TraitId(salsa::InternId);
344impl_intern_key!(TraitId); 168impl_intern_key!(TraitId);
345impl AstItemDef<ast::TraitDef> for TraitId { 169impl AstItemDef<ast::TraitDef> for TraitId {
346 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self { 170 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
347 db.intern_trait(loc) 171 db.intern_trait(loc)
348 } 172 }
349 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> { 173 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
350 db.lookup_intern_trait(self) 174 db.lookup_intern_trait(self)
351 } 175 }
352} 176}
@@ -355,10 +179,10 @@ impl AstItemDef<ast::TraitDef> for TraitId {
355pub struct TypeAliasId(salsa::InternId); 179pub struct TypeAliasId(salsa::InternId);
356impl_intern_key!(TypeAliasId); 180impl_intern_key!(TypeAliasId);
357impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { 181impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
358 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self { 182 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
359 db.intern_type_alias(loc) 183 db.intern_type_alias(loc)
360 } 184 }
361 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> { 185 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> {
362 db.lookup_intern_type_alias(self) 186 db.lookup_intern_type_alias(self)
363 } 187 }
364} 188}