aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ids.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-01 21:30:00 +0000
committerAleksey Kladov <[email protected]>2019-01-01 21:30:00 +0000
commit42cc77703b041436b2507816cb394ad6fd3d07e0 (patch)
tree69fbd4722cea2a5a5d322d890bef14f11da60b36 /crates/ra_hir/src/ids.rs
parent37ed2f35badfb41cd6c50ef04d6fd6a6ce67e0d1 (diff)
move more stuff to ids
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r--crates/ra_hir/src/ids.rs175
1 files changed, 173 insertions, 2 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 3eba35a24..cd32033f3 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,6 +1,10 @@
1use crate::{FileId, MacroCallId, HirDatabase}; 1use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
2 3
3use ra_syntax::SourceFileNode; 4use crate::{
5 MacroCallId, HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum,
6 arena::{Arena, Id},
7};
4 8
5/// hir makes a heavy use of ids: integer (u32) handlers to various things. You 9/// hir makes a heavy use of ids: integer (u32) handlers to various things. You
6/// can think of id as a pointer (but without a lifetime) or a file descriptor 10/// can think of id as a pointer (but without a lifetime) or a file descriptor
@@ -72,3 +76,170 @@ impl From<MacroCallId> for HirFileId {
72 HirFileId(HirFileIdRepr::Macro(macro_call_id)) 76 HirFileId(HirFileIdRepr::Macro(macro_call_id))
73 } 77 }
74} 78}
79
80/// Def's are a core concept of hir. A `Def` is an Item (function, module, etc)
81/// in a specific module.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub struct DefId(u32);
84ra_db::impl_numeric_id!(DefId);
85
86#[derive(Clone, Debug, PartialEq, Eq, Hash)]
87pub struct DefLoc {
88 pub(crate) kind: DefKind,
89 pub(crate) source_root_id: SourceRootId,
90 pub(crate) module_id: ModuleId,
91 pub(crate) source_item_id: SourceItemId,
92}
93
94#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
95pub(crate) enum DefKind {
96 Module,
97 Function,
98 Struct,
99 Enum,
100 Item,
101
102 StructCtor,
103}
104
105impl DefId {
106 pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
107 db.as_ref().id2loc(self)
108 }
109
110 pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> {
111 let loc = self.loc(db);
112 let res = match loc.kind {
113 DefKind::Module => {
114 let module = Module::new(db, loc.source_root_id, loc.module_id)?;
115 Def::Module(module)
116 }
117 DefKind::Function => {
118 let function = Function::new(self);
119 Def::Function(function)
120 }
121 DefKind::Struct => {
122 let struct_def = Struct::new(self);
123 Def::Struct(struct_def)
124 }
125 DefKind::Enum => {
126 let enum_def = Enum::new(self);
127 Def::Enum(enum_def)
128 }
129 DefKind::StructCtor => Def::Item,
130 DefKind::Item => Def::Item,
131 };
132 Ok(res)
133 }
134
135 /// For a module, returns that module; for any other def, returns the containing module.
136 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> {
137 let loc = self.loc(db);
138 Module::new(db, loc.source_root_id, loc.module_id)
139 }
140}
141
142impl DefLoc {
143 pub(crate) fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId {
144 db.as_ref().loc2id(&self)
145 }
146}
147
148impl DefKind {
149 pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
150 match kind {
151 SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
152 SyntaxKind::MODULE => PerNs::types(DefKind::Module),
153 SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
154 SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
155 // These define items, but don't have their own DefKinds yet:
156 SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Item),
157 SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Item),
158 SyntaxKind::CONST_DEF => PerNs::values(DefKind::Item),
159 SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Item),
160 _ => PerNs::none(),
161 }
162 }
163}
164
165/// Identifier of item within a specific file. This is stable over reparses, so
166/// it's OK to use it as a salsa key/value.
167pub(crate) type SourceFileItemId = Id<SyntaxNode>;
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
170pub struct SourceItemId {
171 pub(crate) file_id: HirFileId,
172 /// None for the whole file.
173 pub(crate) item_id: Option<SourceFileItemId>,
174}
175
176/// Maps item's `SyntaxNode`s to `SourceFileItemId` and back.
177#[derive(Debug, PartialEq, Eq)]
178pub struct SourceFileItems {
179 file_id: HirFileId,
180 arena: Arena<SyntaxNode>,
181}
182
183impl SourceFileItems {
184 pub(crate) fn new(file_id: HirFileId, source_file: SourceFile) -> SourceFileItems {
185 let mut res = SourceFileItems {
186 file_id,
187 arena: Arena::default(),
188 };
189 res.init(source_file);
190 res
191 }
192
193 fn init(&mut self, source_file: SourceFile) {
194 source_file.syntax().descendants().for_each(|it| {
195 if let Some(module_item) = ast::ModuleItem::cast(it) {
196 self.alloc(module_item.syntax().owned());
197 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
198 self.alloc(macro_call.syntax().owned());
199 }
200 });
201 }
202
203 fn alloc(&mut self, item: SyntaxNode) -> SourceFileItemId {
204 self.arena.alloc(item)
205 }
206 pub(crate) fn id_of(&self, file_id: HirFileId, item: SyntaxNodeRef) -> SourceFileItemId {
207 assert_eq!(
208 self.file_id, file_id,
209 "SourceFileItems: wrong file, expected {:?}, got {:?}",
210 self.file_id, file_id
211 );
212 self.id_of_unchecked(item)
213 }
214 pub(crate) fn id_of_unchecked(&self, item: SyntaxNodeRef) -> SourceFileItemId {
215 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| i.borrowed() == item) {
216 return id;
217 }
218 // This should not happen. Let's try to give a sensible diagnostics.
219 if let Some((id, i)) = self.arena.iter().find(|(_id, i)| i.range() == item.range()) {
220 // FIXME(#288): whyyy are we getting here?
221 log::error!(
222 "unequal syntax nodes with the same range:\n{:?}\n{:?}",
223 item,
224 i
225 );
226 return id;
227 }
228 panic!(
229 "Can't find {:?} in SourceFileItems:\n{:?}",
230 item,
231 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
232 );
233 }
234 pub fn id_of_source_file(&self) -> SourceFileItemId {
235 let (id, _syntax) = self.arena.iter().next().unwrap();
236 id
237 }
238}
239
240impl std::ops::Index<SourceFileItemId> for SourceFileItems {
241 type Output = SyntaxNode;
242 fn index(&self, idx: SourceFileItemId) -> &SyntaxNode {
243 &self.arena[idx]
244 }
245}