rubydex 0.1.0.beta1-x86_64-linux → 0.1.0.beta2-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rubydex/declaration.c +146 -0
  3. data/ext/rubydex/declaration.h +10 -0
  4. data/ext/rubydex/definition.c +234 -0
  5. data/ext/rubydex/definition.h +28 -0
  6. data/ext/rubydex/diagnostic.c +6 -0
  7. data/ext/rubydex/diagnostic.h +11 -0
  8. data/ext/rubydex/document.c +98 -0
  9. data/ext/rubydex/document.h +10 -0
  10. data/ext/rubydex/extconf.rb +36 -15
  11. data/ext/rubydex/graph.c +405 -0
  12. data/ext/rubydex/graph.h +10 -0
  13. data/ext/rubydex/handle.h +44 -0
  14. data/ext/rubydex/location.c +22 -0
  15. data/ext/rubydex/location.h +15 -0
  16. data/ext/rubydex/reference.c +104 -0
  17. data/ext/rubydex/reference.h +16 -0
  18. data/ext/rubydex/rubydex.c +22 -0
  19. data/ext/rubydex/utils.c +27 -0
  20. data/ext/rubydex/utils.h +13 -0
  21. data/lib/rubydex/3.2/rubydex.so +0 -0
  22. data/lib/rubydex/3.3/rubydex.so +0 -0
  23. data/lib/rubydex/3.4/rubydex.so +0 -0
  24. data/lib/rubydex/4.0/rubydex.so +0 -0
  25. data/lib/rubydex/librubydex_sys.so +0 -0
  26. data/lib/rubydex/version.rb +1 -1
  27. data/rust/Cargo.lock +1275 -0
  28. data/rust/Cargo.toml +23 -0
  29. data/rust/about.hbs +78 -0
  30. data/rust/about.toml +9 -0
  31. data/rust/rubydex/Cargo.toml +41 -0
  32. data/rust/rubydex/src/diagnostic.rs +108 -0
  33. data/rust/rubydex/src/errors.rs +28 -0
  34. data/rust/rubydex/src/indexing/local_graph.rs +172 -0
  35. data/rust/rubydex/src/indexing/ruby_indexer.rs +5397 -0
  36. data/rust/rubydex/src/indexing.rs +128 -0
  37. data/rust/rubydex/src/job_queue.rs +186 -0
  38. data/rust/rubydex/src/lib.rs +15 -0
  39. data/rust/rubydex/src/listing.rs +249 -0
  40. data/rust/rubydex/src/main.rs +116 -0
  41. data/rust/rubydex/src/model/comment.rs +24 -0
  42. data/rust/rubydex/src/model/declaration.rs +541 -0
  43. data/rust/rubydex/src/model/definitions.rs +1475 -0
  44. data/rust/rubydex/src/model/document.rs +111 -0
  45. data/rust/rubydex/src/model/encoding.rs +22 -0
  46. data/rust/rubydex/src/model/graph.rs +1387 -0
  47. data/rust/rubydex/src/model/id.rs +90 -0
  48. data/rust/rubydex/src/model/identity_maps.rs +54 -0
  49. data/rust/rubydex/src/model/ids.rs +32 -0
  50. data/rust/rubydex/src/model/name.rs +188 -0
  51. data/rust/rubydex/src/model/references.rs +129 -0
  52. data/rust/rubydex/src/model/string_ref.rs +44 -0
  53. data/rust/rubydex/src/model/visibility.rs +41 -0
  54. data/rust/rubydex/src/model.rs +13 -0
  55. data/rust/rubydex/src/offset.rs +70 -0
  56. data/rust/rubydex/src/position.rs +6 -0
  57. data/rust/rubydex/src/query.rs +103 -0
  58. data/rust/rubydex/src/resolution.rs +4421 -0
  59. data/rust/rubydex/src/stats/memory.rs +71 -0
  60. data/rust/rubydex/src/stats/timer.rs +126 -0
  61. data/rust/rubydex/src/stats.rs +9 -0
  62. data/rust/rubydex/src/test_utils/context.rs +226 -0
  63. data/rust/rubydex/src/test_utils/graph_test.rs +229 -0
  64. data/rust/rubydex/src/test_utils/local_graph_test.rs +166 -0
  65. data/rust/rubydex/src/test_utils.rs +52 -0
  66. data/rust/rubydex/src/visualization/dot.rs +176 -0
  67. data/rust/rubydex/src/visualization.rs +6 -0
  68. data/rust/rubydex/tests/cli.rs +167 -0
  69. data/rust/rubydex-sys/Cargo.toml +20 -0
  70. data/rust/rubydex-sys/build.rs +14 -0
  71. data/rust/rubydex-sys/cbindgen.toml +12 -0
  72. data/rust/rubydex-sys/src/declaration_api.rs +114 -0
  73. data/rust/rubydex-sys/src/definition_api.rs +350 -0
  74. data/rust/rubydex-sys/src/diagnostic_api.rs +99 -0
  75. data/rust/rubydex-sys/src/document_api.rs +54 -0
  76. data/rust/rubydex-sys/src/graph_api.rs +493 -0
  77. data/rust/rubydex-sys/src/lib.rs +9 -0
  78. data/rust/rubydex-sys/src/location_api.rs +79 -0
  79. data/rust/rubydex-sys/src/name_api.rs +81 -0
  80. data/rust/rubydex-sys/src/reference_api.rs +191 -0
  81. data/rust/rubydex-sys/src/utils.rs +50 -0
  82. data/rust/rustfmt.toml +2 -0
  83. metadata +77 -2
@@ -0,0 +1,24 @@
1
+ use crate::offset::Offset;
2
+
3
+ #[derive(Debug, Clone)]
4
+ pub struct Comment {
5
+ offset: Offset,
6
+ string: String,
7
+ }
8
+
9
+ impl Comment {
10
+ #[must_use]
11
+ pub fn new(offset: Offset, string: String) -> Self {
12
+ Self { offset, string }
13
+ }
14
+
15
+ #[must_use]
16
+ pub fn offset(&self) -> &Offset {
17
+ &self.offset
18
+ }
19
+
20
+ #[must_use]
21
+ pub fn string(&self) -> &String {
22
+ &self.string
23
+ }
24
+ }
@@ -0,0 +1,541 @@
1
+ use crate::diagnostic::Diagnostic;
2
+ use crate::model::{
3
+ identity_maps::{IdentityHashMap, IdentityHashSet},
4
+ ids::{DeclarationId, DefinitionId, NameId, ReferenceId, StringId},
5
+ };
6
+
7
+ /// A single ancestor in the linearized ancestor chain
8
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
9
+ pub enum Ancestor {
10
+ /// A complete ancestor that we have fully linearized
11
+ Complete(DeclarationId),
12
+ /// A partial ancestor that is missing linearization
13
+ Partial(NameId),
14
+ }
15
+
16
+ /// The ancestor chain and its current state
17
+ #[derive(Debug, Clone)]
18
+ pub enum Ancestors {
19
+ /// A complete linearization of ancestors with all parts resolved
20
+ Complete(Vec<Ancestor>),
21
+ /// A cyclic linearization of ancestors (e.g.: a module that includes itself)
22
+ Cyclic(Vec<Ancestor>),
23
+ /// A partial linearization of ancestors with some parts unresolved. This chain state always triggers retries
24
+ Partial(Vec<Ancestor>),
25
+ }
26
+
27
+ impl Ancestors {
28
+ pub fn iter(&self) -> std::slice::Iter<'_, Ancestor> {
29
+ match self {
30
+ Ancestors::Complete(ancestors) | Ancestors::Partial(ancestors) | Ancestors::Cyclic(ancestors) => {
31
+ ancestors.iter()
32
+ }
33
+ }
34
+ }
35
+
36
+ #[must_use]
37
+ pub fn to_partial(self) -> Self {
38
+ match self {
39
+ Ancestors::Complete(ancestors) | Ancestors::Cyclic(ancestors) | Ancestors::Partial(ancestors) => {
40
+ Ancestors::Partial(ancestors)
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ impl<'a> IntoIterator for &'a Ancestors {
47
+ type Item = &'a Ancestor;
48
+ type IntoIter = std::slice::Iter<'a, Ancestor>;
49
+
50
+ fn into_iter(self) -> Self::IntoIter {
51
+ self.iter()
52
+ }
53
+ }
54
+
55
+ macro_rules! all_declarations {
56
+ ($value:expr, $var:ident => $expr:expr) => {
57
+ match $value {
58
+ Declaration::Namespace(Namespace::Class($var)) => $expr,
59
+ Declaration::Namespace(Namespace::Module($var)) => $expr,
60
+ Declaration::Namespace(Namespace::SingletonClass($var)) => $expr,
61
+ Declaration::Constant($var) => $expr,
62
+ Declaration::ConstantAlias($var) => $expr,
63
+ Declaration::Method($var) => $expr,
64
+ Declaration::GlobalVariable($var) => $expr,
65
+ Declaration::InstanceVariable($var) => $expr,
66
+ Declaration::ClassVariable($var) => $expr,
67
+ }
68
+ };
69
+ }
70
+
71
+ macro_rules! all_namespaces {
72
+ ($value:expr, $var:ident => $expr:expr) => {
73
+ match $value {
74
+ Namespace::Class($var) => $expr,
75
+ Namespace::Module($var) => $expr,
76
+ Namespace::SingletonClass($var) => $expr,
77
+ }
78
+ };
79
+ }
80
+
81
+ /// Macro to generate a new struct for namespace-like declarations such as classes and modules
82
+ macro_rules! namespace_declaration {
83
+ ($variant:ident, $name:ident) => {
84
+ #[derive(Debug)]
85
+ pub struct $name {
86
+ /// The fully qualified name of this declaration
87
+ name: String,
88
+ /// The list of definition IDs that compose this declaration
89
+ definition_ids: Vec<DefinitionId>,
90
+ /// The set of references that are made to this declaration
91
+ references: IdentityHashSet<ReferenceId>,
92
+ /// The ID of the owner of this declaration. For singleton classes, this is the ID of the attached object
93
+ owner_id: DeclarationId,
94
+ /// The entities that are owned by this declaration. For example, constants and methods that are defined inside of
95
+ /// the namespace. Note that this is a hashmap of unqualified name IDs to declaration IDs. That assists the
96
+ /// traversal of the graph when trying to resolve constant references or trying to discover which methods exist in a
97
+ /// class
98
+ members: IdentityHashMap<StringId, DeclarationId>,
99
+ /// The linearized ancestor chain for this declaration. These are the other declarations that this
100
+ /// declaration inherits from
101
+ ancestors: Ancestors,
102
+ /// The set of declarations that inherit from this declaration
103
+ descendants: IdentityHashSet<DeclarationId>,
104
+ /// The singleton class associated with this declaration
105
+ singleton_class_id: Option<DeclarationId>,
106
+ /// Diagnostics associated with this declaration
107
+ diagnostics: Vec<Diagnostic>,
108
+ }
109
+
110
+ impl $name {
111
+ #[must_use]
112
+ pub fn new(name: String, owner_id: DeclarationId) -> Self {
113
+ Self {
114
+ name,
115
+ definition_ids: Vec::new(),
116
+ members: IdentityHashMap::default(),
117
+ references: IdentityHashSet::default(),
118
+ owner_id,
119
+ ancestors: Ancestors::Partial(Vec::new()),
120
+ descendants: IdentityHashSet::default(),
121
+ singleton_class_id: None,
122
+ diagnostics: Vec::new(),
123
+ }
124
+ }
125
+
126
+ pub fn extend(&mut self, mut other: Namespace) {
127
+ self.definition_ids.extend(other.definitions());
128
+ self.references.extend(other.references());
129
+ self.members.extend(other.members());
130
+ self.diagnostics.extend(other.take_diagnostics());
131
+ }
132
+
133
+ pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
134
+ self.singleton_class_id = Some(declaration_id);
135
+ }
136
+
137
+ pub fn singleton_class_id(&self) -> Option<&DeclarationId> {
138
+ self.singleton_class_id.as_ref()
139
+ }
140
+
141
+ #[must_use]
142
+ pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
143
+ &self.members
144
+ }
145
+
146
+ pub fn add_member(&mut self, string_id: StringId, declaration_id: DeclarationId) {
147
+ self.members.insert(string_id, declaration_id);
148
+ }
149
+
150
+ pub fn remove_member(&mut self, string_id: &StringId) -> Option<DeclarationId> {
151
+ self.members.remove(string_id)
152
+ }
153
+
154
+ #[must_use]
155
+ pub fn member(&self, string_id: &StringId) -> Option<&DeclarationId> {
156
+ self.members.get(string_id)
157
+ }
158
+
159
+ pub fn set_ancestors(&mut self, ancestors: Ancestors) {
160
+ self.ancestors = ancestors;
161
+ }
162
+
163
+ pub fn ancestors(&self) -> &Ancestors {
164
+ &self.ancestors
165
+ }
166
+
167
+ pub fn ancestors_mut(&mut self) -> &mut Ancestors {
168
+ &mut self.ancestors
169
+ }
170
+
171
+ #[must_use]
172
+ pub fn clone_ancestors(&self) -> Ancestors {
173
+ self.ancestors.clone()
174
+ }
175
+
176
+ #[must_use]
177
+ pub fn has_complete_ancestors(&self) -> bool {
178
+ matches!(&self.ancestors, Ancestors::Complete(_) | Ancestors::Cyclic(_))
179
+ }
180
+
181
+ pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
182
+ self.descendants.insert(descendant_id);
183
+ }
184
+
185
+ fn remove_descendant(&mut self, descendant_id: &DeclarationId) {
186
+ self.descendants.remove(descendant_id);
187
+ }
188
+
189
+ pub fn clear_descendants(&mut self) {
190
+ self.descendants.clear();
191
+ }
192
+
193
+ pub fn descendants(&self) -> &IdentityHashSet<DeclarationId> {
194
+ &self.descendants
195
+ }
196
+ }
197
+ };
198
+ }
199
+
200
+ /// Macro to generate a new struct for simple declarations like variables and methods
201
+ macro_rules! simple_declaration {
202
+ ($name:ident) => {
203
+ #[derive(Debug)]
204
+ pub struct $name {
205
+ /// The fully qualified name of this declaration
206
+ name: String,
207
+ /// The list of definition IDs that compose this declaration
208
+ definition_ids: Vec<DefinitionId>,
209
+ /// The set of references that are made to this declaration
210
+ references: IdentityHashSet<ReferenceId>,
211
+ /// The ID of the owner of this declaration
212
+ owner_id: DeclarationId,
213
+ /// Diagnostics associated with this declaration
214
+ diagnostics: Vec<Diagnostic>,
215
+ }
216
+
217
+ impl $name {
218
+ #[must_use]
219
+ pub fn new(name: String, owner_id: DeclarationId) -> Self {
220
+ Self {
221
+ name,
222
+ definition_ids: Vec::new(),
223
+ references: IdentityHashSet::default(),
224
+ owner_id,
225
+ diagnostics: Vec::new(),
226
+ }
227
+ }
228
+
229
+ pub fn extend(&mut self, mut other: Declaration) {
230
+ self.definition_ids.extend(other.definitions());
231
+ self.references.extend(other.references());
232
+ self.diagnostics.extend(other.take_diagnostics());
233
+ }
234
+ }
235
+ };
236
+ }
237
+
238
+ /// A `Declaration` represents the global concept of an entity in Ruby. For example, the class `Foo` may be defined 3
239
+ /// times in different files and the `Foo` declaration is the combination of all of those definitions that contribute to
240
+ /// the same fully qualified name
241
+ #[derive(Debug)]
242
+ pub enum Declaration {
243
+ Namespace(Namespace),
244
+ Constant(Box<ConstantDeclaration>),
245
+ ConstantAlias(Box<ConstantAliasDeclaration>),
246
+ Method(Box<MethodDeclaration>),
247
+ GlobalVariable(Box<GlobalVariableDeclaration>),
248
+ InstanceVariable(Box<InstanceVariableDeclaration>),
249
+ ClassVariable(Box<ClassVariableDeclaration>),
250
+ }
251
+
252
+ impl Declaration {
253
+ #[must_use]
254
+ pub fn name(&self) -> &str {
255
+ all_declarations!(self, it => &it.name)
256
+ }
257
+
258
+ #[must_use]
259
+ pub fn kind(&self) -> &'static str {
260
+ match self {
261
+ Declaration::Namespace(namespace) => namespace.kind(),
262
+ Declaration::Constant(_) => "Constant",
263
+ Declaration::ConstantAlias(_) => "ConstantAlias",
264
+ Declaration::Method(_) => "Method",
265
+ Declaration::GlobalVariable(_) => "GlobalVariable",
266
+ Declaration::InstanceVariable(_) => "InstanceVariable",
267
+ Declaration::ClassVariable(_) => "ClassVariable",
268
+ }
269
+ }
270
+
271
+ #[must_use]
272
+ pub fn as_namespace(&self) -> Option<&Namespace> {
273
+ match self {
274
+ Declaration::Namespace(namespace) => Some(namespace),
275
+ _ => None,
276
+ }
277
+ }
278
+
279
+ #[must_use]
280
+ pub fn as_namespace_mut(&mut self) -> Option<&mut Namespace> {
281
+ match self {
282
+ Declaration::Namespace(namespace) => Some(namespace),
283
+ _ => None,
284
+ }
285
+ }
286
+
287
+ #[must_use]
288
+ pub fn references(&self) -> &IdentityHashSet<ReferenceId> {
289
+ all_declarations!(self, it => &it.references)
290
+ }
291
+
292
+ #[must_use]
293
+ pub fn definitions(&self) -> &[DefinitionId] {
294
+ all_declarations!(self, it => &it.definition_ids)
295
+ }
296
+
297
+ #[must_use]
298
+ pub fn has_no_definitions(&self) -> bool {
299
+ all_declarations!(self, it => it.definition_ids.is_empty())
300
+ }
301
+
302
+ pub fn add_definition(&mut self, definition_id: DefinitionId) {
303
+ all_declarations!(self, it => {
304
+ debug_assert!(
305
+ !it.definition_ids.contains(&definition_id),
306
+ "Cannot add the same exact definition to a declaration twice. Duplicate definition IDs"
307
+ );
308
+
309
+ it.definition_ids.push(definition_id);
310
+ });
311
+ }
312
+
313
+ pub fn add_reference(&mut self, id: ReferenceId) {
314
+ all_declarations!(self, it => {
315
+ it.references.insert(id);
316
+ });
317
+ }
318
+
319
+ pub fn remove_reference(&mut self, reference_id: &ReferenceId) {
320
+ all_declarations!(self, it => {
321
+ it.references.remove(reference_id);
322
+ });
323
+ }
324
+
325
+ // Deletes a definition from this declaration
326
+ pub fn remove_definition(&mut self, definition_id: &DefinitionId) -> bool {
327
+ all_declarations!(self, it => {
328
+ if let Some(pos) = it.definition_ids.iter().position(|id| id == definition_id) {
329
+ it.definition_ids.swap_remove(pos);
330
+ it.definition_ids.shrink_to_fit();
331
+ true
332
+ } else {
333
+ false
334
+ }
335
+ })
336
+ }
337
+
338
+ #[must_use]
339
+ pub fn owner_id(&self) -> &DeclarationId {
340
+ all_declarations!(self, it => &it.owner_id)
341
+ }
342
+
343
+ // Splits the fully qualified name either in the last `::` or the `#` to return the simple name of this declaration
344
+ #[must_use]
345
+ pub fn unqualified_name(&self) -> String {
346
+ all_declarations!(self, it => {
347
+ let after_colons = it.name.rsplit("::").next().unwrap_or(&it.name);
348
+ after_colons.rsplit('#').next().unwrap_or(after_colons).to_string()
349
+ })
350
+ }
351
+
352
+ #[must_use]
353
+ pub fn diagnostics(&self) -> &[Diagnostic] {
354
+ all_declarations!(self, it => &it.diagnostics)
355
+ }
356
+
357
+ pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
358
+ all_declarations!(self, it => std::mem::take(&mut it.diagnostics))
359
+ }
360
+
361
+ pub fn add_diagnostic(&mut self, diagnostic: Diagnostic) {
362
+ all_declarations!(self, it => it.diagnostics.push(diagnostic));
363
+ }
364
+
365
+ pub fn clear_diagnostics(&mut self) {
366
+ all_declarations!(self, it => it.diagnostics.clear());
367
+ }
368
+ }
369
+
370
+ #[derive(Debug)]
371
+ pub enum Namespace {
372
+ Class(Box<ClassDeclaration>),
373
+ SingletonClass(Box<SingletonClassDeclaration>),
374
+ Module(Box<ModuleDeclaration>),
375
+ }
376
+
377
+ impl Namespace {
378
+ #[must_use]
379
+ pub fn kind(&self) -> &'static str {
380
+ match self {
381
+ Namespace::Class(_) => "Class",
382
+ Namespace::SingletonClass(_) => "SingletonClass",
383
+ Namespace::Module(_) => "Module",
384
+ }
385
+ }
386
+
387
+ #[must_use]
388
+ pub fn references(&self) -> &IdentityHashSet<ReferenceId> {
389
+ all_namespaces!(self, it => &it.references)
390
+ }
391
+
392
+ #[must_use]
393
+ pub fn definitions(&self) -> &[DefinitionId] {
394
+ all_namespaces!(self, it => &it.definition_ids)
395
+ }
396
+
397
+ #[must_use]
398
+ pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
399
+ all_namespaces!(self, it => &it.members)
400
+ }
401
+
402
+ #[must_use]
403
+ pub fn diagnostics(&self) -> &[Diagnostic] {
404
+ all_namespaces!(self, it => &it.diagnostics)
405
+ }
406
+
407
+ pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
408
+ all_namespaces!(self, it => std::mem::take(&mut it.diagnostics))
409
+ }
410
+
411
+ /// # Panics
412
+ ///
413
+ /// Panics if the declaration is not a namespace or a constant
414
+ #[must_use]
415
+ pub fn ancestors(&self) -> Ancestors {
416
+ all_namespaces!(self, it => it.clone_ancestors())
417
+ }
418
+
419
+ pub fn set_ancestors(&mut self, ancestors: Ancestors) {
420
+ all_namespaces!(self, it => it.set_ancestors(ancestors));
421
+ }
422
+
423
+ #[must_use]
424
+ pub fn has_complete_ancestors(&self) -> bool {
425
+ all_namespaces!(self, it => it.has_complete_ancestors())
426
+ }
427
+
428
+ pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
429
+ all_namespaces!(self, it => it.add_descendant(descendant_id));
430
+ }
431
+
432
+ pub fn remove_descendant(&mut self, descendant_id: &DeclarationId) {
433
+ all_namespaces!(self, it => it.remove_descendant(descendant_id));
434
+ }
435
+
436
+ pub fn for_each_ancestor<F>(&self, mut f: F)
437
+ where
438
+ F: FnMut(&Ancestor),
439
+ {
440
+ all_namespaces!(self, it => it.ancestors().iter().for_each(&mut f));
441
+ }
442
+
443
+ pub fn for_each_descendant<F>(&self, mut f: F)
444
+ where
445
+ F: FnMut(&DeclarationId),
446
+ {
447
+ all_namespaces!(self, it => it.descendants().iter().for_each(&mut f));
448
+ }
449
+
450
+ pub fn clear_ancestors(&mut self) {
451
+ all_namespaces!(self, it => it.set_ancestors(Ancestors::Partial(vec![])));
452
+ }
453
+
454
+ pub fn clear_descendants(&mut self) {
455
+ all_namespaces!(self, it => it.clear_descendants());
456
+ }
457
+
458
+ #[must_use]
459
+ pub fn member(&self, str_id: &StringId) -> Option<&DeclarationId> {
460
+ all_namespaces!(self, it => it.member(str_id))
461
+ }
462
+
463
+ #[must_use]
464
+ pub fn singleton_class(&self) -> Option<&DeclarationId> {
465
+ all_namespaces!(self, it => it.singleton_class_id())
466
+ }
467
+
468
+ pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
469
+ all_namespaces!(self, it => it.set_singleton_class_id(declaration_id));
470
+ }
471
+ }
472
+
473
+ namespace_declaration!(Class, ClassDeclaration);
474
+ namespace_declaration!(Module, ModuleDeclaration);
475
+ namespace_declaration!(SingletonClass, SingletonClassDeclaration);
476
+ simple_declaration!(ConstantDeclaration);
477
+ simple_declaration!(MethodDeclaration);
478
+ simple_declaration!(GlobalVariableDeclaration);
479
+ simple_declaration!(InstanceVariableDeclaration);
480
+ simple_declaration!(ClassVariableDeclaration);
481
+ simple_declaration!(ConstantAliasDeclaration);
482
+
483
+ #[cfg(test)]
484
+ mod tests {
485
+ use super::*;
486
+
487
+ #[test]
488
+ #[should_panic(expected = "Cannot add the same exact definition to a declaration twice. Duplicate definition IDs")]
489
+ fn inserting_duplicate_definitions() {
490
+ let mut decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
491
+ "MyDecl".to_string(),
492
+ DeclarationId::from("Object"),
493
+ ))));
494
+ let def_id = DefinitionId::new(123);
495
+
496
+ // The second call will panic because we're adding the same exact ID twice
497
+ decl.add_definition(def_id);
498
+ decl.add_definition(def_id);
499
+ }
500
+
501
+ #[test]
502
+ fn adding_and_removing_members() {
503
+ let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
504
+ "Foo".to_string(),
505
+ DeclarationId::from("Object"),
506
+ ))));
507
+ let member_name_id = StringId::from("Bar");
508
+ let member_decl_id = DeclarationId::from("Foo::Bar");
509
+
510
+ let Declaration::Namespace(Namespace::Class(mut class)) = decl else {
511
+ panic!("Expected a class declaration");
512
+ };
513
+ class.add_member(member_name_id, member_decl_id);
514
+ assert_eq!(class.members.len(), 1);
515
+
516
+ let removed = class.remove_member(&member_name_id);
517
+ assert_eq!(removed, Some(member_decl_id));
518
+ assert_eq!(class.members.len(), 0);
519
+ }
520
+
521
+ #[test]
522
+ fn unqualified_name() {
523
+ let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
524
+ "Foo".to_string(),
525
+ DeclarationId::from("Foo"),
526
+ ))));
527
+ assert_eq!(decl.unqualified_name(), "Foo");
528
+
529
+ let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
530
+ "Foo::Bar".to_string(),
531
+ DeclarationId::from("Foo"),
532
+ ))));
533
+ assert_eq!(decl.unqualified_name(), "Bar");
534
+
535
+ let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
536
+ "Foo::Bar#baz".to_string(),
537
+ DeclarationId::from("Foo::Bar"),
538
+ ))));
539
+ assert_eq!(decl.unqualified_name(), "baz");
540
+ }
541
+ }