rubydex 0.3.0 → 0.4.0

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -7
  3. data/THIRD_PARTY_LICENSES.html +238 -2
  4. data/exe/rdx +2 -149
  5. data/ext/rubydex/config.c +140 -0
  6. data/ext/rubydex/config.h +16 -0
  7. data/ext/rubydex/diagnostic.c +75 -1
  8. data/ext/rubydex/diagnostic.h +2 -0
  9. data/ext/rubydex/graph.c +13 -45
  10. data/ext/rubydex/graph.h +6 -0
  11. data/ext/rubydex/query.c +398 -16
  12. data/ext/rubydex/rubydex.c +2 -0
  13. data/ext/rubydex/utils.c +11 -4
  14. data/lib/ruby_lsp/rubydex/addon.rb +211 -0
  15. data/lib/rubydex/cli/command/console.rb +55 -0
  16. data/lib/rubydex/cli/command/lint/explain.rb +74 -0
  17. data/lib/rubydex/cli/command/lint.rb +202 -0
  18. data/lib/rubydex/cli/command/mcp.rb +30 -0
  19. data/lib/rubydex/cli/command/query.rb +70 -0
  20. data/lib/rubydex/cli/command/skill.rb +69 -0
  21. data/lib/rubydex/cli/command.rb +168 -0
  22. data/lib/rubydex/cli.rb +93 -0
  23. data/lib/rubydex/config.rb +59 -0
  24. data/lib/rubydex/diagnostic.rb +12 -3
  25. data/lib/rubydex/errors.rb +42 -1
  26. data/lib/rubydex/graph.rb +10 -3
  27. data/lib/rubydex/linter/custom_rule.rb +97 -0
  28. data/lib/rubydex/linter/helpers/path_helpers.rb +78 -0
  29. data/lib/rubydex/linter/helpers/source_access_helpers.rb +31 -0
  30. data/lib/rubydex/linter/rule_loader.rb +36 -0
  31. data/lib/rubydex/linter/rule_test_case.rb +343 -0
  32. data/lib/rubydex/linter/runner.rb +56 -0
  33. data/lib/rubydex/linter.rb +19 -0
  34. data/lib/rubydex/location.rb +3 -0
  35. data/lib/rubydex/mcp_server.rb +1 -2
  36. data/lib/rubydex/related_information.rb +17 -0
  37. data/lib/rubydex/rule.rb +33 -0
  38. data/lib/rubydex/severity.rb +70 -0
  39. data/lib/rubydex/skill.rb +88 -0
  40. data/lib/rubydex/skill_registry.rb +62 -0
  41. data/lib/rubydex/version.rb +1 -1
  42. data/lib/rubydex.rb +6 -0
  43. data/lib/rubydex_linter/rules/rule_structure.rb +125 -0
  44. data/rbi/rubydex.rbi +558 -17
  45. data/rust/Cargo.lock +2 -2
  46. data/rust/rubydex/Cargo.toml +1 -1
  47. data/rust/rubydex/benches/graph_memory.rs +3 -5
  48. data/rust/rubydex/src/config.rs +538 -157
  49. data/rust/rubydex/src/diagnostic.rs +66 -40
  50. data/rust/rubydex/src/errors.rs +0 -1
  51. data/rust/rubydex/src/indexing/local_graph.rs +6 -5
  52. data/rust/rubydex/src/indexing/rbs_indexer.rs +270 -6
  53. data/rust/rubydex/src/indexing/ruby_indexer.rs +10 -12
  54. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +134 -81
  55. data/rust/rubydex/src/lib.rs +1 -0
  56. data/rust/rubydex/src/listing.rs +26 -1
  57. data/rust/rubydex/src/main.rs +7 -4
  58. data/rust/rubydex/src/model/declaration.rs +302 -219
  59. data/rust/rubydex/src/model/graph.rs +27 -40
  60. data/rust/rubydex/src/model/name.rs +58 -17
  61. data/rust/rubydex/src/operation/ruby_builder.rs +30 -45
  62. data/rust/rubydex/src/path_helpers.rs +77 -0
  63. data/rust/rubydex/src/query/cypher/schema.rs +63 -0
  64. data/rust/rubydex/src/query/cypher/tests.rs +26 -1
  65. data/rust/rubydex/src/query/cypher.rs +8 -11
  66. data/rust/rubydex/src/query.rs +123 -43
  67. data/rust/rubydex/src/resolution.rs +139 -187
  68. data/rust/rubydex/src/resolution_tests.rs +247 -19
  69. data/rust/rubydex/src/test_utils/context.rs +2 -1
  70. data/rust/rubydex/src/test_utils/graph_test.rs +26 -12
  71. data/rust/rubydex/src/test_utils/local_graph_test.rs +19 -0
  72. data/rust/rubydex/tests/cli.rs +4 -4
  73. data/rust/rubydex-sys/src/config_api.rs +205 -0
  74. data/rust/rubydex-sys/src/cypher_api.rs +791 -0
  75. data/rust/rubydex-sys/src/diagnostic_api.rs +77 -8
  76. data/rust/rubydex-sys/src/graph_api.rs +13 -194
  77. data/rust/rubydex-sys/src/lib.rs +2 -0
  78. data/rust/rubydex-sys/src/name_api.rs +2 -6
  79. data/rust/rubydex-sys/src/utils.rs +37 -0
  80. data/skills/send-private-method/SKILL.md +133 -0
  81. metadata +31 -2
@@ -1,3 +1,5 @@
1
+ use std::hash::Hash;
2
+
1
3
  use crate::assert_mem_size;
2
4
  use crate::model::ids::{
3
5
  ClassVariableReferenceId, GlobalVariableReferenceId, InstanceVariableReferenceId, MethodReferenceId,
@@ -57,23 +59,6 @@ impl<'a> IntoIterator for &'a Ancestors {
57
59
  }
58
60
  }
59
61
 
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
62
  macro_rules! all_namespaces {
78
63
  ($value:expr, $var:ident => $expr:expr) => {
79
64
  match $value {
@@ -90,56 +75,29 @@ macro_rules! namespace_declaration {
90
75
  ($variant:ident, $name:ident) => {
91
76
  #[derive(Debug)]
92
77
  pub struct $name {
93
- /// The fully qualified name of this declaration
94
- name: Box<str>,
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>,
78
+ core: DeclarationCore<ConstantReferenceId>,
79
+ namespace_store: NamespaceStore,
113
80
  }
114
81
 
115
82
  impl $name {
116
83
  #[must_use]
117
84
  pub fn new(name: String, owner_id: DeclarationId) -> Self {
118
85
  Self {
119
- name: name.into_boxed_str(),
120
- definition_ids: Vec::new(),
121
- members: IdentityHashMap::default(),
122
- references: IdentityHashSet::default(),
123
- owner_id,
124
- ancestors: Ancestors::Partial(Vec::new()),
125
- descendants: IdentityHashSet::default(),
126
- singleton_class_id: None,
86
+ core: DeclarationCore::new(name, owner_id),
87
+ namespace_store: NamespaceStore::new(),
127
88
  }
128
89
  }
129
90
 
130
91
  pub fn extend(&mut self, other: Declaration) {
131
- self.definition_ids.extend(other.definitions());
92
+ self.core.definition_ids.extend(other.definitions());
132
93
 
133
94
  match other {
134
95
  Declaration::Namespace(namespace) => {
135
- self.members.extend(namespace.members());
136
- self.references.extend(namespace.references());
137
- }
138
- Declaration::Constant(constant) => {
139
- self.references.extend(constant.references());
96
+ self.namespace_store.members.extend(namespace.members());
97
+ self.core.references.extend(namespace.references());
140
98
  }
141
- Declaration::ConstantAlias(constant_alias) => {
142
- self.references.extend(constant_alias.references());
99
+ Declaration::Constant(it) | Declaration::ConstantAlias(it) => {
100
+ self.core.references.extend(it.references());
143
101
  }
144
102
  Declaration::Method(_)
145
103
  | Declaration::GlobalVariable(_)
@@ -149,128 +107,198 @@ macro_rules! namespace_declaration {
149
107
  }
150
108
  }
151
109
  }
110
+ }
111
+ };
112
+ }
152
113
 
153
- pub fn add_reference(&mut self, reference_id: ConstantReferenceId) {
154
- self.references.insert(reference_id);
155
- }
156
-
157
- pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
158
- self.singleton_class_id = Some(declaration_id);
159
- }
160
-
161
- pub fn clear_singleton_class_id(&mut self) {
162
- self.singleton_class_id = None;
163
- }
164
-
165
- pub fn singleton_class_id(&self) -> Option<&DeclarationId> {
166
- self.singleton_class_id.as_ref()
167
- }
114
+ /// The core data of a declaration, shared across all of them
115
+ #[derive(Debug)]
116
+ pub struct DeclarationCore<T> {
117
+ /// The fully qualified name of this declaration
118
+ name: Box<str>,
119
+ /// The list of definition IDs that compose this declaration
120
+ definition_ids: Vec<DefinitionId>,
121
+ /// The set of references that are made to this declaration
122
+ references: IdentityHashSet<T>,
123
+ /// The ID of the owner of this declaration
124
+ owner_id: DeclarationId,
125
+ }
168
126
 
169
- #[must_use]
170
- pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
171
- &self.members
172
- }
127
+ impl<T: Eq + Hash> DeclarationCore<T> {
128
+ #[must_use]
129
+ pub fn new(name: String, owner_id: DeclarationId) -> Self {
130
+ Self {
131
+ name: name.into_boxed_str(),
132
+ definition_ids: Vec::new(),
133
+ references: IdentityHashSet::default(),
134
+ owner_id,
135
+ }
136
+ }
173
137
 
174
- pub fn add_member(&mut self, string_id: StringId, declaration_id: DeclarationId) {
175
- self.members.insert(string_id, declaration_id);
176
- }
138
+ #[must_use]
139
+ pub fn name(&self) -> &str {
140
+ &self.name
141
+ }
177
142
 
178
- pub fn remove_member(&mut self, string_id: &StringId) -> Option<DeclarationId> {
179
- self.members.remove(string_id)
180
- }
143
+ #[must_use]
144
+ pub fn unqualified_name(&self) -> String {
145
+ let after_colons = self.name.rsplit("::").next().unwrap_or(&self.name);
146
+ after_colons.rsplit('#').next().unwrap_or(after_colons).to_string()
147
+ }
181
148
 
182
- #[must_use]
183
- pub fn member(&self, string_id: &StringId) -> Option<&DeclarationId> {
184
- self.members.get(string_id)
185
- }
149
+ pub fn extend(&mut self, other: Self) {
150
+ self.definition_ids.extend(other.definition_ids);
151
+ self.references.extend(other.references);
152
+ }
186
153
 
187
- pub fn set_ancestors(&mut self, ancestors: Ancestors) {
188
- self.ancestors = ancestors;
189
- }
154
+ #[must_use]
155
+ pub fn references(&self) -> &IdentityHashSet<T> {
156
+ &self.references
157
+ }
190
158
 
191
- pub fn ancestors(&self) -> &Ancestors {
192
- &self.ancestors
193
- }
159
+ pub fn add_reference(&mut self, reference_id: T) {
160
+ self.references.insert(reference_id);
161
+ }
194
162
 
195
- #[must_use]
196
- pub fn clone_ancestors(&self) -> Ancestors {
197
- self.ancestors.clone()
198
- }
163
+ pub fn remove_reference(&mut self, reference_id: &T) {
164
+ self.references.remove(reference_id);
165
+ }
199
166
 
200
- #[must_use]
201
- pub fn has_complete_ancestors(&self) -> bool {
202
- matches!(&self.ancestors, Ancestors::Complete(_) | Ancestors::Cyclic(_))
203
- }
167
+ #[must_use]
168
+ pub fn has_no_definitions(&self) -> bool {
169
+ self.definition_ids.is_empty()
170
+ }
204
171
 
205
- pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
206
- self.descendants.insert(descendant_id);
207
- }
172
+ #[must_use]
173
+ pub fn definitions(&self) -> &[DefinitionId] {
174
+ &self.definition_ids
175
+ }
208
176
 
209
- fn remove_descendant(&mut self, descendant_id: &DeclarationId) {
210
- self.descendants.remove(descendant_id);
211
- }
177
+ pub fn add_definition(&mut self, definition_id: DefinitionId) {
178
+ debug_assert!(
179
+ !self.definition_ids.contains(&definition_id),
180
+ "Cannot add the same exact definition to a declaration twice. Duplicate definition IDs"
181
+ );
212
182
 
213
- pub fn clear_descendants(&mut self) {
214
- self.descendants.clear();
215
- }
183
+ self.definition_ids.push(definition_id);
184
+ }
216
185
 
217
- pub fn descendants(&self) -> &IdentityHashSet<DeclarationId> {
218
- &self.descendants
219
- }
186
+ pub fn remove_definition(&mut self, definition_id: &DefinitionId) -> bool {
187
+ if let Some(pos) = self.definition_ids.iter().position(|id| id == definition_id) {
188
+ self.definition_ids.swap_remove(pos);
189
+ self.definition_ids.shrink_to_fit();
190
+ true
191
+ } else {
192
+ false
220
193
  }
221
- };
194
+ }
222
195
  }
223
196
 
224
- /// Macro to generate a new struct for simple declarations like variables and methods
225
- macro_rules! simple_declaration {
226
- ($name:ident, $reference_type:ty) => {
227
- #[derive(Debug)]
228
- pub struct $name {
229
- /// The fully qualified name of this declaration
230
- name: Box<str>,
231
- /// The list of definition IDs that compose this declaration
232
- definition_ids: Vec<DefinitionId>,
233
- /// The set of references that are made to this declaration
234
- references: IdentityHashSet<$reference_type>,
235
- /// The ID of the owner of this declaration
236
- owner_id: DeclarationId,
197
+ /// Storage for namespace data, like ancestors, descendants, members and singleton class
198
+ #[derive(Debug)]
199
+ pub struct NamespaceStore {
200
+ /// The entities that are owned by this declaration. For example, constants and methods that are defined inside of
201
+ /// the namespace. Note that this is a hashmap of unqualified name IDs to declaration IDs. That assists the
202
+ /// traversal of the graph when trying to resolve constant references or trying to discover which methods exist in a
203
+ /// class
204
+ members: IdentityHashMap<StringId, DeclarationId>,
205
+ /// The linearized ancestor chain for this declaration. These are the other declarations that this
206
+ /// declaration inherits from
207
+ ancestors: Ancestors,
208
+ /// The set of declarations that inherit from this declaration
209
+ descendants: IdentityHashSet<DeclarationId>,
210
+ /// The singleton class associated with this declaration
211
+ singleton_class_id: Option<DeclarationId>,
212
+ }
213
+
214
+ impl NamespaceStore {
215
+ #[must_use]
216
+ pub fn new() -> Self {
217
+ Self {
218
+ members: IdentityHashMap::default(),
219
+ ancestors: Ancestors::Partial(Vec::new()),
220
+ descendants: IdentityHashSet::default(),
221
+ singleton_class_id: None,
237
222
  }
223
+ }
238
224
 
239
- impl $name {
240
- #[must_use]
241
- pub fn new(name: String, owner_id: DeclarationId) -> Self {
242
- Self {
243
- name: name.into_boxed_str(),
244
- definition_ids: Vec::new(),
245
- references: IdentityHashSet::default(),
246
- owner_id,
247
- }
248
- }
225
+ pub fn extend(&mut self, other: Self) {
226
+ self.members.extend(other.members);
227
+ self.descendants.extend(other.descendants);
228
+ }
249
229
 
250
- pub fn extend(&mut self, other: $name) {
251
- self.definition_ids.extend(other.definitions());
252
- self.references.extend(other.references());
253
- }
230
+ pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
231
+ self.singleton_class_id = Some(declaration_id);
232
+ }
254
233
 
255
- #[must_use]
256
- pub fn references(&self) -> &IdentityHashSet<$reference_type> {
257
- &self.references
258
- }
234
+ pub fn clear_singleton_class_id(&mut self) {
235
+ self.singleton_class_id = None;
236
+ }
259
237
 
260
- pub fn add_reference(&mut self, reference_id: $reference_type) {
261
- self.references.insert(reference_id);
262
- }
238
+ #[must_use]
239
+ pub fn singleton_class_id(&self) -> Option<&DeclarationId> {
240
+ self.singleton_class_id.as_ref()
241
+ }
263
242
 
264
- pub fn remove_reference(&mut self, reference_id: &$reference_type) {
265
- self.references.remove(reference_id);
266
- }
243
+ #[must_use]
244
+ pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
245
+ &self.members
246
+ }
267
247
 
268
- #[must_use]
269
- pub fn definitions(&self) -> &[DefinitionId] {
270
- &self.definition_ids
271
- }
272
- }
273
- };
248
+ pub fn add_member(&mut self, string_id: StringId, declaration_id: DeclarationId) {
249
+ self.members.insert(string_id, declaration_id);
250
+ }
251
+
252
+ pub fn remove_member(&mut self, string_id: &StringId) -> Option<DeclarationId> {
253
+ self.members.remove(string_id)
254
+ }
255
+
256
+ #[must_use]
257
+ pub fn member(&self, string_id: &StringId) -> Option<&DeclarationId> {
258
+ self.members.get(string_id)
259
+ }
260
+
261
+ pub fn set_ancestors(&mut self, ancestors: Ancestors) {
262
+ self.ancestors = ancestors;
263
+ }
264
+
265
+ #[must_use]
266
+ pub fn ancestors(&self) -> &Ancestors {
267
+ &self.ancestors
268
+ }
269
+
270
+ #[must_use]
271
+ pub fn clone_ancestors(&self) -> Ancestors {
272
+ self.ancestors.clone()
273
+ }
274
+
275
+ #[must_use]
276
+ pub fn has_complete_ancestors(&self) -> bool {
277
+ matches!(&self.ancestors, Ancestors::Complete(_) | Ancestors::Cyclic(_))
278
+ }
279
+
280
+ pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
281
+ self.descendants.insert(descendant_id);
282
+ }
283
+
284
+ fn remove_descendant(&mut self, descendant_id: DeclarationId) {
285
+ self.descendants.remove(&descendant_id);
286
+ }
287
+
288
+ pub fn clear_descendants(&mut self) {
289
+ self.descendants.clear();
290
+ }
291
+
292
+ #[must_use]
293
+ pub fn descendants(&self) -> &IdentityHashSet<DeclarationId> {
294
+ &self.descendants
295
+ }
296
+ }
297
+
298
+ impl Default for NamespaceStore {
299
+ fn default() -> Self {
300
+ Self::new()
301
+ }
274
302
  }
275
303
 
276
304
  /// A `Declaration` represents the global concept of an entity in Ruby. For example, the class `Foo` may be defined 3
@@ -291,7 +319,14 @@ assert_mem_size!(Declaration, 16);
291
319
  impl Declaration {
292
320
  #[must_use]
293
321
  pub fn name(&self) -> &str {
294
- all_declarations!(self, it => &it.name)
322
+ match self {
323
+ Self::Namespace(namespace) => namespace.core().name(),
324
+ Self::ConstantAlias(it) | Self::Constant(it) => it.name(),
325
+ Self::Method(it) => it.name(),
326
+ Self::GlobalVariable(it) => it.name(),
327
+ Self::InstanceVariable(it) => it.name(),
328
+ Self::ClassVariable(it) => it.name(),
329
+ }
295
330
  }
296
331
 
297
332
  #[must_use]
@@ -373,55 +408,86 @@ impl Declaration {
373
408
 
374
409
  #[must_use]
375
410
  pub fn definitions(&self) -> &[DefinitionId] {
376
- all_declarations!(self, it => &it.definition_ids)
411
+ match self {
412
+ Self::Namespace(namespace) => namespace.core().definitions(),
413
+ Self::Constant(it) | Self::ConstantAlias(it) => it.definitions(),
414
+ Self::Method(it) => it.definitions(),
415
+ Self::GlobalVariable(it) => it.definitions(),
416
+ Self::InstanceVariable(it) => it.definitions(),
417
+ Self::ClassVariable(it) => it.definitions(),
418
+ }
377
419
  }
378
420
 
379
421
  #[must_use]
380
422
  pub fn has_no_definitions(&self) -> bool {
381
- all_declarations!(self, it => it.definition_ids.is_empty())
423
+ match self {
424
+ Self::Namespace(namespace) => namespace.core().has_no_definitions(),
425
+ Self::Constant(it) | Self::ConstantAlias(it) => it.has_no_definitions(),
426
+ Self::Method(it) => it.has_no_definitions(),
427
+ Self::GlobalVariable(it) => it.has_no_definitions(),
428
+ Self::InstanceVariable(it) => it.has_no_definitions(),
429
+ Self::ClassVariable(it) => it.has_no_definitions(),
430
+ }
382
431
  }
383
432
 
384
433
  pub fn add_definition(&mut self, definition_id: DefinitionId) {
385
- all_declarations!(self, it => {
386
- debug_assert!(
387
- !it.definition_ids.contains(&definition_id),
388
- "Cannot add the same exact definition to a declaration twice. Duplicate definition IDs"
389
- );
390
-
391
- it.definition_ids.push(definition_id);
392
- });
434
+ match self {
435
+ Self::Namespace(namespace) => namespace.core_mut().add_definition(definition_id),
436
+ Self::Constant(it) | Self::ConstantAlias(it) => it.add_definition(definition_id),
437
+ Self::Method(it) => it.add_definition(definition_id),
438
+ Self::GlobalVariable(it) => it.add_definition(definition_id),
439
+ Self::InstanceVariable(it) => it.add_definition(definition_id),
440
+ Self::ClassVariable(it) => it.add_definition(definition_id),
441
+ }
393
442
  }
394
443
 
395
444
  // Deletes a definition from this declaration
396
445
  pub fn remove_definition(&mut self, definition_id: &DefinitionId) -> bool {
397
- all_declarations!(self, it => {
398
- if let Some(pos) = it.definition_ids.iter().position(|id| id == definition_id) {
399
- it.definition_ids.swap_remove(pos);
400
- it.definition_ids.shrink_to_fit();
401
- true
402
- } else {
403
- false
404
- }
405
- })
446
+ match self {
447
+ Self::Namespace(namespace) => namespace.core_mut().remove_definition(definition_id),
448
+ Self::Constant(it) | Self::ConstantAlias(it) => it.remove_definition(definition_id),
449
+ Self::Method(it) => it.remove_definition(definition_id),
450
+ Self::GlobalVariable(it) => it.remove_definition(definition_id),
451
+ Self::InstanceVariable(it) => it.remove_definition(definition_id),
452
+ Self::ClassVariable(it) => it.remove_definition(definition_id),
453
+ }
406
454
  }
407
455
 
408
456
  #[must_use]
409
457
  pub fn owner_id(&self) -> &DeclarationId {
410
- all_declarations!(self, it => &it.owner_id)
458
+ match self {
459
+ Self::Namespace(namespace) => &namespace.core().owner_id,
460
+ Self::Constant(it) | Self::ConstantAlias(it) => &it.owner_id,
461
+ Self::Method(it) => &it.owner_id,
462
+ Self::GlobalVariable(it) => &it.owner_id,
463
+ Self::InstanceVariable(it) => &it.owner_id,
464
+ Self::ClassVariable(it) => &it.owner_id,
465
+ }
411
466
  }
412
467
 
413
468
  // Splits the fully qualified name either in the last `::` or the `#` to return the simple name of this declaration
414
469
  #[must_use]
415
470
  pub fn unqualified_name(&self) -> String {
416
- all_declarations!(self, it => {
417
- let after_colons = it.name.rsplit("::").next().unwrap_or(&it.name);
418
- after_colons.rsplit('#').next().unwrap_or(after_colons).to_string()
419
- })
471
+ match self {
472
+ Self::Namespace(namespace) => namespace.core().unqualified_name(),
473
+ Self::Constant(it) | Self::ConstantAlias(it) => it.unqualified_name(),
474
+ Self::Method(it) => it.unqualified_name(),
475
+ Self::GlobalVariable(it) => it.unqualified_name(),
476
+ Self::InstanceVariable(it) => it.unqualified_name(),
477
+ Self::ClassVariable(it) => it.unqualified_name(),
478
+ }
420
479
  }
421
480
 
422
481
  #[must_use]
423
482
  pub fn reference_count(&self) -> usize {
424
- all_declarations!(self, it => it.references.len())
483
+ match self {
484
+ Self::Namespace(namespace) => namespace.core().references.len(),
485
+ Self::Constant(it) | Self::ConstantAlias(it) => it.references.len(),
486
+ Self::Method(it) => it.references.len(),
487
+ Self::GlobalVariable(it) => it.references.len(),
488
+ Self::InstanceVariable(it) => it.references.len(),
489
+ Self::ClassVariable(it) => it.references.len(),
490
+ }
425
491
  }
426
492
 
427
493
  /// Returns the constant reference IDs for declarations that track constant references (`Namespace`, `Constant`,
@@ -430,8 +496,7 @@ impl Declaration {
430
496
  pub fn constant_references(&self) -> Option<&IdentityHashSet<ConstantReferenceId>> {
431
497
  match self {
432
498
  Declaration::Namespace(it) => Some(it.references()),
433
- Declaration::Constant(it) => Some(it.references()),
434
- Declaration::ConstantAlias(it) => Some(it.references()),
499
+ Declaration::Constant(it) | Declaration::ConstantAlias(it) => Some(it.references()),
435
500
  _ => None,
436
501
  }
437
502
  }
@@ -444,8 +509,7 @@ impl Declaration {
444
509
  pub fn add_constant_reference(&mut self, reference_id: ConstantReferenceId) {
445
510
  match self {
446
511
  Declaration::Namespace(it) => it.add_reference(reference_id),
447
- Declaration::Constant(it) => it.add_reference(reference_id),
448
- Declaration::ConstantAlias(it) => it.add_reference(reference_id),
512
+ Declaration::Constant(it) | Declaration::ConstantAlias(it) => it.add_reference(reference_id),
449
513
  _ => unreachable!("Cannot add constant reference to {} declaration", self.kind()),
450
514
  }
451
515
  }
@@ -458,8 +522,7 @@ impl Declaration {
458
522
  pub fn remove_constant_reference(&mut self, reference_id: &ConstantReferenceId) {
459
523
  match self {
460
524
  Declaration::Namespace(it) => it.remove_reference(reference_id),
461
- Declaration::Constant(it) => it.remove_reference(reference_id),
462
- Declaration::ConstantAlias(it) => it.remove_reference(reference_id),
525
+ Declaration::Constant(it) | Declaration::ConstantAlias(it) => it.remove_reference(reference_id),
463
526
  _ => unreachable!("Cannot remove constant reference from {} declaration", self.kind()),
464
527
  }
465
528
  }
@@ -475,6 +538,16 @@ pub enum Namespace {
475
538
  assert_mem_size!(Namespace, 16);
476
539
 
477
540
  impl Namespace {
541
+ #[must_use]
542
+ pub fn core(&self) -> &DeclarationCore<ConstantReferenceId> {
543
+ all_namespaces!(self, it => &it.core)
544
+ }
545
+
546
+ #[must_use]
547
+ pub fn core_mut(&mut self) -> &mut DeclarationCore<ConstantReferenceId> {
548
+ all_namespaces!(self, it => &mut it.core)
549
+ }
550
+
478
551
  #[must_use]
479
552
  pub fn kind(&self) -> &'static str {
480
553
  match self {
@@ -487,29 +560,29 @@ impl Namespace {
487
560
 
488
561
  #[must_use]
489
562
  pub fn references(&self) -> &IdentityHashSet<ConstantReferenceId> {
490
- all_namespaces!(self, it => &it.references)
563
+ all_namespaces!(self, it => &it.core.references)
491
564
  }
492
565
 
493
566
  pub fn remove_reference(&mut self, reference_id: &ConstantReferenceId) {
494
567
  all_namespaces!(self, it => {
495
- it.references.remove(reference_id);
568
+ it.core.remove_reference(reference_id);
496
569
  });
497
570
  }
498
571
 
499
572
  pub fn add_reference(&mut self, reference_id: ConstantReferenceId) {
500
573
  all_namespaces!(self, it => {
501
- it.references.insert(reference_id);
574
+ it.core.add_reference(reference_id);
502
575
  });
503
576
  }
504
577
 
505
578
  #[must_use]
506
579
  pub fn definitions(&self) -> &[DefinitionId] {
507
- all_namespaces!(self, it => &it.definition_ids)
580
+ all_namespaces!(self, it => &it.core.definitions())
508
581
  }
509
582
 
510
583
  #[must_use]
511
584
  pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
512
- all_namespaces!(self, it => &it.members)
585
+ all_namespaces!(self, it => &it.namespace_store.members)
513
586
  }
514
587
 
515
588
  pub fn extend(&mut self, other: Declaration) {
@@ -518,81 +591,85 @@ impl Namespace {
518
591
 
519
592
  #[must_use]
520
593
  pub fn ancestors(&self) -> &Ancestors {
521
- all_namespaces!(self, it => it.ancestors())
594
+ all_namespaces!(self, it => it.namespace_store.ancestors())
522
595
  }
523
596
 
524
597
  #[must_use]
525
598
  pub fn clone_ancestors(&self) -> Ancestors {
526
- all_namespaces!(self, it => it.clone_ancestors())
599
+ all_namespaces!(self, it => it.namespace_store.clone_ancestors())
527
600
  }
528
601
 
529
602
  pub fn set_ancestors(&mut self, ancestors: Ancestors) {
530
- all_namespaces!(self, it => it.set_ancestors(ancestors));
603
+ all_namespaces!(self, it => it.namespace_store.set_ancestors(ancestors));
531
604
  }
532
605
 
533
606
  #[must_use]
534
607
  pub fn has_complete_ancestors(&self) -> bool {
535
- all_namespaces!(self, it => it.has_complete_ancestors())
608
+ all_namespaces!(self, it => it.namespace_store.has_complete_ancestors())
536
609
  }
537
610
 
538
611
  #[must_use]
539
612
  pub fn descendants(&self) -> &IdentityHashSet<DeclarationId> {
540
- all_namespaces!(self, it => it.descendants())
613
+ all_namespaces!(self, it => it.namespace_store.descendants())
541
614
  }
542
615
 
543
616
  pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
544
- all_namespaces!(self, it => it.add_descendant(descendant_id));
617
+ all_namespaces!(self, it => it.namespace_store.add_descendant(descendant_id));
545
618
  }
546
619
 
547
- pub fn remove_descendant(&mut self, descendant_id: &DeclarationId) {
548
- all_namespaces!(self, it => it.remove_descendant(descendant_id));
620
+ pub fn remove_descendant(&mut self, descendant_id: DeclarationId) {
621
+ all_namespaces!(self, it => it.namespace_store.remove_descendant(descendant_id));
549
622
  }
550
623
 
551
624
  pub fn for_each_descendant<F>(&self, mut f: F)
552
625
  where
553
626
  F: FnMut(&DeclarationId),
554
627
  {
555
- all_namespaces!(self, it => it.descendants().iter().for_each(&mut f));
628
+ all_namespaces!(self, it => it.namespace_store.descendants().iter().for_each(&mut f));
556
629
  }
557
630
 
558
631
  pub fn clear_ancestors(&mut self) {
559
- all_namespaces!(self, it => it.set_ancestors(Ancestors::Partial(vec![])));
632
+ all_namespaces!(self, it => it.namespace_store.set_ancestors(Ancestors::Partial(vec![])));
560
633
  }
561
634
 
562
635
  pub fn clear_descendants(&mut self) {
563
- all_namespaces!(self, it => it.clear_descendants());
636
+ all_namespaces!(self, it => it.namespace_store.clear_descendants());
564
637
  }
565
638
 
566
639
  #[must_use]
567
640
  pub fn member(&self, str_id: &StringId) -> Option<&DeclarationId> {
568
- all_namespaces!(self, it => it.member(str_id))
641
+ all_namespaces!(self, it => it.namespace_store.member(str_id))
642
+ }
643
+
644
+ pub fn add_member(&mut self, string_id: StringId, declaration_id: DeclarationId) {
645
+ all_namespaces!(self, it => it.namespace_store.add_member(string_id, declaration_id));
569
646
  }
570
647
 
571
648
  pub fn remove_member(&mut self, str_id: &StringId) -> Option<DeclarationId> {
572
- all_namespaces!(self, it => it.remove_member(str_id))
649
+ all_namespaces!(self, it => it.namespace_store.remove_member(str_id))
573
650
  }
574
651
 
575
652
  #[must_use]
576
653
  pub fn singleton_class(&self) -> Option<&DeclarationId> {
577
- all_namespaces!(self, it => it.singleton_class_id())
654
+ all_namespaces!(self, it => it.namespace_store.singleton_class_id())
578
655
  }
579
656
 
580
657
  pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
581
- all_namespaces!(self, it => it.set_singleton_class_id(declaration_id));
658
+ all_namespaces!(self, it => it.namespace_store.set_singleton_class_id(declaration_id));
582
659
  }
583
660
 
584
661
  pub fn clear_singleton_class_id(&mut self) {
585
- all_namespaces!(self, it => it.clear_singleton_class_id());
662
+ all_namespaces!(self, it => it.namespace_store.clear_singleton_class_id());
586
663
  }
587
664
 
588
665
  #[must_use]
589
666
  pub fn owner_id(&self) -> &DeclarationId {
590
- all_namespaces!(self, it => &it.owner_id)
667
+ all_namespaces!(self, it => &it.core.owner_id)
591
668
  }
592
669
 
593
670
  #[must_use]
594
671
  pub fn name(&self) -> &str {
595
- all_namespaces!(self, it => &it.name)
672
+ all_namespaces!(self, it => &it.core.name())
596
673
  }
597
674
  }
598
675
 
@@ -604,17 +681,23 @@ namespace_declaration!(SingletonClass, SingletonClassDeclaration);
604
681
  assert_mem_size!(SingletonClassDeclaration, 184);
605
682
  namespace_declaration!(Todo, TodoDeclaration);
606
683
  assert_mem_size!(TodoDeclaration, 184);
607
- simple_declaration!(ConstantDeclaration, ConstantReferenceId);
684
+
685
+ pub type ConstantDeclaration = DeclarationCore<ConstantReferenceId>;
608
686
  assert_mem_size!(ConstantDeclaration, 80);
609
- simple_declaration!(MethodDeclaration, MethodReferenceId);
687
+
688
+ pub type MethodDeclaration = DeclarationCore<MethodReferenceId>;
610
689
  assert_mem_size!(MethodDeclaration, 80);
611
- simple_declaration!(GlobalVariableDeclaration, GlobalVariableReferenceId);
690
+
691
+ pub type GlobalVariableDeclaration = DeclarationCore<GlobalVariableReferenceId>;
612
692
  assert_mem_size!(GlobalVariableDeclaration, 80);
613
- simple_declaration!(InstanceVariableDeclaration, InstanceVariableReferenceId);
693
+
694
+ pub type InstanceVariableDeclaration = DeclarationCore<InstanceVariableReferenceId>;
614
695
  assert_mem_size!(InstanceVariableDeclaration, 80);
615
- simple_declaration!(ClassVariableDeclaration, ClassVariableReferenceId);
696
+
697
+ pub type ClassVariableDeclaration = DeclarationCore<ClassVariableReferenceId>;
616
698
  assert_mem_size!(ClassVariableDeclaration, 80);
617
- simple_declaration!(ConstantAliasDeclaration, ConstantReferenceId);
699
+
700
+ pub type ConstantAliasDeclaration = DeclarationCore<ConstantReferenceId>;
618
701
  assert_mem_size!(ConstantAliasDeclaration, 80);
619
702
 
620
703
  #[cfg(test)]
@@ -644,15 +727,15 @@ mod tests {
644
727
  let member_name_id = StringId::from("Bar");
645
728
  let member_decl_id = DeclarationId::from("Foo::Bar");
646
729
 
647
- let Declaration::Namespace(Namespace::Class(mut class)) = decl else {
648
- panic!("Expected a class declaration");
730
+ let Declaration::Namespace(mut namespace) = decl else {
731
+ panic!("Expected a namespace declaration");
649
732
  };
650
- class.add_member(member_name_id, member_decl_id);
651
- assert_eq!(class.members.len(), 1);
733
+ namespace.add_member(member_name_id, member_decl_id);
734
+ assert_eq!(namespace.members().len(), 1);
652
735
 
653
- let removed = class.remove_member(&member_name_id);
736
+ let removed = namespace.remove_member(&member_name_id);
654
737
  assert_eq!(removed, Some(member_decl_id));
655
- assert_eq!(class.members.len(), 0);
738
+ assert_eq!(namespace.members().len(), 0);
656
739
  }
657
740
 
658
741
  #[test]