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