rubydex 0.1.0.beta11 → 0.1.0.beta12

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/THIRD_PARTY_LICENSES.html +2 -2
  3. data/ext/rubydex/declaration.c +84 -19
  4. data/ext/rubydex/definition.c +87 -0
  5. data/ext/rubydex/document.c +4 -5
  6. data/ext/rubydex/extconf.rb +12 -1
  7. data/ext/rubydex/graph.c +177 -8
  8. data/ext/rubydex/reference.c +29 -10
  9. data/ext/rubydex/reference.h +2 -3
  10. data/ext/rubydex/utils.c +30 -8
  11. data/ext/rubydex/utils.h +10 -4
  12. data/lib/rubydex/graph.rb +6 -0
  13. data/lib/rubydex/keyword.rb +17 -0
  14. data/lib/rubydex/keyword_parameter.rb +13 -0
  15. data/lib/rubydex/librubydex_sys.so +0 -0
  16. data/lib/rubydex/mixin.rb +22 -0
  17. data/lib/rubydex/version.rb +1 -1
  18. data/lib/rubydex.rb +3 -0
  19. data/rbi/rubydex.rbi +124 -12
  20. data/rust/Cargo.lock +4 -4
  21. data/rust/rubydex/Cargo.toml +1 -1
  22. data/rust/rubydex/src/diagnostic.rs +1 -0
  23. data/rust/rubydex/src/indexing/local_graph.rs +9 -9
  24. data/rust/rubydex/src/indexing/rbs_indexer.rs +17 -20
  25. data/rust/rubydex/src/indexing/ruby_indexer.rs +155 -4579
  26. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
  27. data/rust/rubydex/src/indexing.rs +5 -5
  28. data/rust/rubydex/src/integrity.rs +2 -1
  29. data/rust/rubydex/src/listing.rs +107 -8
  30. data/rust/rubydex/src/main.rs +2 -2
  31. data/rust/rubydex/src/model/built_in.rs +83 -0
  32. data/rust/rubydex/src/model/declaration.rs +116 -33
  33. data/rust/rubydex/src/model/definitions.rs +91 -11
  34. data/rust/rubydex/src/model/document.rs +9 -39
  35. data/rust/rubydex/src/model/graph.rs +353 -155
  36. data/rust/rubydex/src/model/ids.rs +29 -7
  37. data/rust/rubydex/src/model/references.rs +5 -5
  38. data/rust/rubydex/src/model.rs +1 -0
  39. data/rust/rubydex/src/query.rs +168 -27
  40. data/rust/rubydex/src/resolution.rs +828 -206
  41. data/rust/rubydex/src/stats/orphan_report.rs +1 -0
  42. data/rust/rubydex/src/test_utils/graph_test.rs +56 -5
  43. data/rust/rubydex/src/visualization/dot.rs +38 -22
  44. data/rust/rubydex/tests/cli.rs +24 -6
  45. data/rust/rubydex-mcp/src/server.rs +8 -8
  46. data/rust/rubydex-mcp/tests/mcp.rs +1 -1
  47. data/rust/rubydex-sys/src/declaration_api.rs +66 -50
  48. data/rust/rubydex-sys/src/definition_api.rs +150 -59
  49. data/rust/rubydex-sys/src/document_api.rs +31 -0
  50. data/rust/rubydex-sys/src/graph_api.rs +386 -138
  51. data/rust/rubydex-sys/src/lib.rs +70 -0
  52. data/rust/rubydex-sys/src/reference_api.rs +136 -64
  53. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d26e66bf7f1eac1c1bffa154b2a5e2c0621ce59883ae0367202cc82b6f85e64d
4
- data.tar.gz: 3ea90f481e9717834e2be5e2a7dc1140810f842e738132496c211b5a19b6837b
3
+ metadata.gz: 98e6dcc146395bd17fb654d336ad198a58c4726a2345d86c710a644ab85e415d
4
+ data.tar.gz: c27b9aeda854bac93d5be6c7cde3b77da6c3a2c564baf66c5d5dab4b8075e9e5
5
5
  SHA512:
6
- metadata.gz: 24f8c2aa31a6d1ad76dd76486d005f3ee1e9143e0624b91db920c33e39da5b1bf248c431d0efc97996019f24f02ed8673912d4731509fcaaa59b1075c84378f9
7
- data.tar.gz: 22b831aa47e08e9f3be4390054b645376e3e6d6974eeb2071e7e76499e1f9f056cdf0f0091eb1c28604047c2f0acea68a8e8f15a41ce939fa3acba13956e791f
6
+ metadata.gz: 4f807b20f75639d56c7df1ba831979d8f5880ac8bfcbabe4f0e23ac2709157f3f49d9feb1e4862645b03b348cdba982e515e9a8da262cab1d4e29e179d937acc
7
+ data.tar.gz: f4938ecf9d5e6e9fb9cdaa4bdb52318c8988814b7561462a129be1ec5923817a0af1753b09b54fbb5e3f23dbf3f6b9a38e56d788fff420a89197fe5fd31b077d
@@ -3336,10 +3336,10 @@ limitations under the License.
3336
3336
  <ul class="license-used-by">
3337
3337
  <li><a
3338
3338
  href=" https://github.com/ruby/rbs.git ">ruby-rbs-sys
3339
- 0.2.0</a></li>
3339
+ 0.3.0</a></li>
3340
3340
  <li><a
3341
3341
  href=" https://github.com/ruby/rbs.git ">ruby-rbs
3342
- 0.2.0</a></li>
3342
+ 0.3.0</a></li>
3343
3343
  </ul>
3344
3344
  <pre class="license-text">Copyright (c) &lt;year&gt; &lt;owner&gt;
3345
3345
 
@@ -2,7 +2,6 @@
2
2
  #include "definition.h"
3
3
  #include "graph.h"
4
4
  #include "handle.h"
5
- #include "reference.h"
6
5
  #include "rustbindings.h"
7
6
  #include "utils.h"
8
7
 
@@ -93,11 +92,10 @@ static VALUE declaration_definitions_yield(VALUE args) {
93
92
  HandleData *data;
94
93
  TypedData_Get_Struct(self, HandleData, &handle_type, data);
95
94
 
96
- uint64_t id = 0;
97
- DefinitionKind kind;
98
- while (rdx_definitions_iter_next(iter, &id, &kind)) {
99
- VALUE argv[] = {data->graph_obj, ULL2NUM(id)};
100
- VALUE defn_class = rdxi_definition_class_for_kind(kind);
95
+ CDefinition defn;
96
+ while (rdx_definitions_iter_next(iter, &defn)) {
97
+ VALUE argv[] = {data->graph_obj, ULL2NUM(defn.id)};
98
+ VALUE defn_class = rdxi_definition_class_for_kind(defn.kind);
101
99
  VALUE handle = rb_class_new_instance(2, argv, defn_class);
102
100
  rb_yield(handle);
103
101
  }
@@ -318,27 +316,30 @@ static VALUE rdxr_declaration_members(VALUE self) {
318
316
  return self;
319
317
  }
320
318
 
321
- // Size function for the Declaration#references enumerator
322
- static VALUE declaration_references_size(VALUE self, VALUE _args, VALUE _eobj) {
319
+ // Size function for constant declaration references enumerator
320
+ static VALUE constant_declaration_references_size(VALUE self, VALUE _args, VALUE _eobj) {
323
321
  HandleData *data;
324
322
  TypedData_Get_Struct(self, HandleData, &handle_type, data);
325
323
 
326
324
  void *graph;
327
325
  TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
328
326
 
329
- struct ReferencesIter *iter = rdx_declaration_references_iter_new(graph, data->id);
330
- size_t len = rdx_references_iter_len(iter);
331
- rdx_references_iter_free(iter);
327
+ struct ConstantReferencesIter *iter = rdx_declaration_constant_references_iter_new(graph, data->id);
328
+ if (iter == NULL) {
329
+ rb_raise(rb_eRuntimeError, "Declaration not found");
330
+ }
332
331
 
332
+ size_t len = rdx_constant_references_iter_len(iter);
333
+ rdx_constant_references_iter_free(iter);
333
334
  return SIZET2NUM(len);
334
335
  }
335
336
 
336
- // Returns an enumerator for all references to this declaration
337
- //
338
- // Declaration#references: () -> Enumerator[Reference]
339
- static VALUE rdxr_declaration_references(VALUE self) {
337
+ // Namespace#references, Constant#references, ConstantAlias#references
338
+ // Returns an enumerator that yields constant references to this declaration
339
+ static VALUE rdxr_constant_declaration_references(VALUE self) {
340
340
  if (!rb_block_given_p()) {
341
- return rb_enumeratorize_with_size(self, rb_str_new2("references"), 0, NULL, declaration_references_size);
341
+ return rb_enumeratorize_with_size(self, rb_str_new2("references"), 0, NULL,
342
+ constant_declaration_references_size);
342
343
  }
343
344
 
344
345
  HandleData *data;
@@ -347,13 +348,65 @@ static VALUE rdxr_declaration_references(VALUE self) {
347
348
  void *graph;
348
349
  TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
349
350
 
350
- void *iter = rdx_declaration_references_iter_new(graph, data->id);
351
+ void *iter = rdx_declaration_constant_references_iter_new(graph, data->id);
352
+ if (iter == NULL) {
353
+ rb_raise(rb_eRuntimeError, "Declaration not found");
354
+ }
355
+
351
356
  VALUE args = rb_ary_new_from_args(2, data->graph_obj, ULL2NUM((uintptr_t)iter));
352
- rb_ensure(rdxi_references_yield, args, rdxi_references_ensure, args);
357
+ rb_ensure(rdxi_constant_references_yield, args, rdxi_constant_references_ensure, args);
353
358
 
354
359
  return self;
355
360
  }
356
361
 
362
+ // Size function for method declaration references enumerator
363
+ static VALUE method_declaration_references_size(VALUE self, VALUE _args, VALUE _eobj) {
364
+ HandleData *data;
365
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
366
+
367
+ void *graph;
368
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
369
+
370
+ struct MethodReferencesIter *iter = rdx_declaration_method_references_iter_new(graph, data->id);
371
+ if (iter == NULL) {
372
+ rb_raise(rb_eRuntimeError, "Declaration not found");
373
+ }
374
+
375
+ size_t len = rdx_method_references_iter_len(iter);
376
+ rdx_method_references_iter_free(iter);
377
+ return SIZET2NUM(len);
378
+ }
379
+
380
+ // Method#references
381
+ // Returns an enumerator that yields method references to this declaration
382
+ static VALUE rdxr_method_declaration_references(VALUE self) {
383
+ if (!rb_block_given_p()) {
384
+ return rb_enumeratorize_with_size(self, rb_str_new2("references"), 0, NULL,
385
+ method_declaration_references_size);
386
+ }
387
+
388
+ HandleData *data;
389
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
390
+
391
+ void *graph;
392
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
393
+
394
+ void *iter = rdx_declaration_method_references_iter_new(graph, data->id);
395
+ if (iter == NULL) {
396
+ rb_raise(rb_eRuntimeError, "Declaration not found");
397
+ }
398
+
399
+ VALUE args = rb_ary_new_from_args(2, data->graph_obj, ULL2NUM((uintptr_t)iter));
400
+ rb_ensure(rdxi_method_references_yield, args, rdxi_method_references_ensure, args);
401
+
402
+ return self;
403
+ }
404
+
405
+ // Placeholder for variable declarations that don't yet support references
406
+ static VALUE rdxr_variable_declaration_references(VALUE self) {
407
+ return rb_ary_new();
408
+ }
409
+
357
410
  void rdxi_initialize_declaration(VALUE mRubydex) {
358
411
  cDeclaration = rb_define_class_under(mRubydex, "Declaration", rb_cObject);
359
412
  cNamespace = rb_define_class_under(mRubydex, "Namespace", cDeclaration);
@@ -373,10 +426,10 @@ void rdxi_initialize_declaration(VALUE mRubydex) {
373
426
  rb_define_method(cDeclaration, "name", rdxr_declaration_name, 0);
374
427
  rb_define_method(cDeclaration, "unqualified_name", rdxr_declaration_unqualified_name, 0);
375
428
  rb_define_method(cDeclaration, "definitions", rdxr_declaration_definitions, 0);
376
- rb_define_method(cDeclaration, "references", rdxr_declaration_references, 0);
377
429
  rb_define_method(cDeclaration, "owner", rdxr_declaration_owner, 0);
378
430
 
379
431
  // Namespace only methods
432
+ rb_define_method(cNamespace, "references", rdxr_constant_declaration_references, 0);
380
433
  rb_define_method(cNamespace, "member", rdxr_declaration_member, 1);
381
434
  rb_define_method(cNamespace, "find_member", rdxr_declaration_find_member, -1);
382
435
  rb_define_method(cNamespace, "singleton_class", rdxr_declaration_singleton_class, 0);
@@ -384,5 +437,17 @@ void rdxi_initialize_declaration(VALUE mRubydex) {
384
437
  rb_define_method(cNamespace, "descendants", rdxr_declaration_descendants, 0);
385
438
  rb_define_method(cNamespace, "members", rdxr_declaration_members, 0);
386
439
 
440
+ // Constant and ConstantAlias have constant references
441
+ rb_define_method(cConstant, "references", rdxr_constant_declaration_references, 0);
442
+ rb_define_method(cConstantAlias, "references", rdxr_constant_declaration_references, 0);
443
+
444
+ // Method has method references
445
+ rb_define_method(cMethod, "references", rdxr_method_declaration_references, 0);
446
+
447
+ // Variable declarations don't yet support references
448
+ rb_define_method(cGlobalVariable, "references", rdxr_variable_declaration_references, 0);
449
+ rb_define_method(cInstanceVariable, "references", rdxr_variable_declaration_references, 0);
450
+ rb_define_method(cClassVariable, "references", rdxr_variable_declaration_references, 0);
451
+
387
452
  rb_funcall(rb_singleton_class(cDeclaration), rb_intern("private"), 1, ID2SYM(rb_intern("new")));
388
453
  }
@@ -2,10 +2,14 @@
2
2
  #include "graph.h"
3
3
  #include "handle.h"
4
4
  #include "location.h"
5
+ #include "reference.h"
5
6
  #include "ruby/internal/scan_args.h"
6
7
  #include "rustbindings.h"
7
8
 
8
9
  static VALUE mRubydex;
10
+ static VALUE cInclude;
11
+ static VALUE cPrepend;
12
+ static VALUE cExtend;
9
13
  VALUE cComment;
10
14
  VALUE cDefinition;
11
15
  VALUE cClassDefinition;
@@ -14,6 +18,7 @@ VALUE cModuleDefinition;
14
18
  VALUE cConstantDefinition;
15
19
  VALUE cConstantAliasDefinition;
16
20
  VALUE cConstantVisibilityDefinition;
21
+ VALUE cMethodVisibilityDefinition;
17
22
  VALUE cMethodDefinition;
18
23
  VALUE cAttrAccessorDefinition;
19
24
  VALUE cAttrReaderDefinition;
@@ -39,6 +44,8 @@ VALUE rdxi_definition_class_for_kind(DefinitionKind kind) {
39
44
  return cConstantAliasDefinition;
40
45
  case DefinitionKind_ConstantVisibility:
41
46
  return cConstantVisibilityDefinition;
47
+ case DefinitionKind_MethodVisibility:
48
+ return cMethodVisibilityDefinition;
42
49
  case DefinitionKind_Method:
43
50
  return cMethodDefinition;
44
51
  case DefinitionKind_AttrAccessor:
@@ -164,9 +171,81 @@ static VALUE rdxr_definition_name_location(VALUE self) {
164
171
  return location;
165
172
  }
166
173
 
174
+ static VALUE rdxi_build_constant_reference(VALUE graph_obj, const CConstantReference *cref) {
175
+ VALUE ref_class = (cref->declaration_id == 0)
176
+ ? cUnresolvedConstantReference
177
+ : cResolvedConstantReference;
178
+
179
+ VALUE argv[] = {graph_obj, ULL2NUM(cref->id)};
180
+ return rb_class_new_instance(2, argv, ref_class);
181
+ }
182
+
183
+ // ClassDefinition#superclass -> ConstantReference?
184
+ static VALUE rdxr_class_definition_superclass(VALUE self) {
185
+ HandleData *data;
186
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
187
+
188
+ void *graph;
189
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
190
+
191
+ const CConstantReference *ref = rdx_class_definition_superclass(graph, data->id);
192
+ if (ref == NULL) {
193
+ return Qnil;
194
+ }
195
+
196
+ VALUE result = rdxi_build_constant_reference(data->graph_obj, ref);
197
+ free_c_constant_reference(ref);
198
+ return result;
199
+ }
200
+
201
+ static VALUE rdxi_mixin_class_for_kind(MixinKind kind) {
202
+ switch (kind) {
203
+ case MixinKind_Include:
204
+ return cInclude;
205
+ case MixinKind_Prepend:
206
+ return cPrepend;
207
+ case MixinKind_Extend:
208
+ return cExtend;
209
+ default:
210
+ rb_raise(rb_eRuntimeError, "Unknown MixinKind: %d", kind);
211
+ }
212
+ }
213
+
214
+ // Definition#mixins -> [Rubydex::Mixin]
215
+ static VALUE rdxr_definition_mixins(VALUE self) {
216
+ HandleData *data;
217
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
218
+
219
+ void *graph;
220
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
221
+
222
+ MixinsIter *iter = rdx_definition_mixins(graph, data->id);
223
+ if (iter == NULL) {
224
+ rb_raise(rb_eRuntimeError, "Tried to get mixins for a definition that isn't a namespace");
225
+ }
226
+
227
+ size_t len = rdx_mixins_iter_len(iter);
228
+ VALUE ary = rb_ary_new_capa((long)len);
229
+
230
+ CMixin entry;
231
+ while (rdx_mixins_iter_next(iter, &entry)) {
232
+ VALUE constant_ref = rdxi_build_constant_reference(data->graph_obj, &entry.constant_reference);
233
+ VALUE mixin_class = rdxi_mixin_class_for_kind(entry.kind);
234
+ VALUE mixin = rb_class_new_instance(1, &constant_ref, mixin_class);
235
+ rb_ary_push(ary, mixin);
236
+ }
237
+
238
+ rdx_mixins_iter_free(iter);
239
+ return ary;
240
+ }
241
+
167
242
  void rdxi_initialize_definition(VALUE mod) {
168
243
  mRubydex = mod;
169
244
 
245
+ cInclude = rb_const_get(mRubydex, rb_intern("Include"));
246
+ cPrepend = rb_const_get(mRubydex, rb_intern("Prepend"));
247
+ cExtend = rb_const_get(mRubydex, rb_intern("Extend"));
248
+
170
249
  cComment = rb_define_class_under(mRubydex, "Comment", rb_cObject);
171
250
 
172
251
  cDefinition = rb_define_class_under(mRubydex, "Definition", rb_cObject);
@@ -180,11 +259,19 @@ void rdxi_initialize_definition(VALUE mod) {
180
259
  rb_define_method(cDefinition, "name_location", rdxr_definition_name_location, 0);
181
260
 
182
261
  cClassDefinition = rb_define_class_under(mRubydex, "ClassDefinition", cDefinition);
262
+ rb_define_method(cClassDefinition, "superclass", rdxr_class_definition_superclass, 0);
263
+ rb_define_method(cClassDefinition, "mixins", rdxr_definition_mixins, 0);
264
+
183
265
  cSingletonClassDefinition = rb_define_class_under(mRubydex, "SingletonClassDefinition", cDefinition);
266
+ rb_define_method(cSingletonClassDefinition, "mixins", rdxr_definition_mixins, 0);
267
+
184
268
  cModuleDefinition = rb_define_class_under(mRubydex, "ModuleDefinition", cDefinition);
269
+ rb_define_method(cModuleDefinition, "mixins", rdxr_definition_mixins, 0);
270
+
185
271
  cConstantDefinition = rb_define_class_under(mRubydex, "ConstantDefinition", cDefinition);
186
272
  cConstantAliasDefinition = rb_define_class_under(mRubydex, "ConstantAliasDefinition", cDefinition);
187
273
  cConstantVisibilityDefinition = rb_define_class_under(mRubydex, "ConstantVisibilityDefinition", cDefinition);
274
+ cMethodVisibilityDefinition = rb_define_class_under(mRubydex, "MethodVisibilityDefinition", cDefinition);
188
275
  cMethodDefinition = rb_define_class_under(mRubydex, "MethodDefinition", cDefinition);
189
276
  cAttrAccessorDefinition = rb_define_class_under(mRubydex, "AttrAccessorDefinition", cDefinition);
190
277
  cAttrReaderDefinition = rb_define_class_under(mRubydex, "AttrReaderDefinition", cDefinition);
@@ -33,11 +33,10 @@ static VALUE document_definitions_yield(VALUE args) {
33
33
  HandleData *data;
34
34
  TypedData_Get_Struct(self, HandleData, &handle_type, data);
35
35
 
36
- uint64_t id = 0;
37
- DefinitionKind kind;
38
- while (rdx_definitions_iter_next(iter, &id, &kind)) {
39
- VALUE argv[] = {data->graph_obj, ULL2NUM(id)};
40
- VALUE defn_class = rdxi_definition_class_for_kind(kind);
36
+ CDefinition defn;
37
+ while (rdx_definitions_iter_next(iter, &defn)) {
38
+ VALUE argv[] = {data->graph_obj, ULL2NUM(defn.id)};
39
+ VALUE defn_class = rdxi_definition_class_for_kind(defn.kind);
41
40
  VALUE handle = rb_class_new_instance(2, argv, defn_class);
42
41
  rb_yield(handle);
43
42
  }
@@ -8,7 +8,18 @@ unless system("cargo", "--version", out: File::NULL, err: File::NULL)
8
8
  end
9
9
 
10
10
  gem_dir = Pathname.new("../..").expand_path(__dir__)
11
- release = ENV["RELEASE"] || !gem_dir.join(".git").exist?
11
+
12
+ # Use release mode for the compilation if:
13
+ # - The RELEASE environment variable is set
14
+ # - We're not working on Rubydex (BUNDLE_GEMFILE doesn't point to Rubydex's own Gemfile)
15
+ #
16
+ # We only need debug builds when working on Rubydex itself and on CI. This approach also lets people install Rubydex
17
+ # from the git source and get a release mode build
18
+
19
+ bundle_gemfile = ENV["BUNDLE_GEMFILE"]
20
+ developing_rubydex = bundle_gemfile && Pathname.new(bundle_gemfile).expand_path.dirname == gem_dir
21
+ release = ENV["RELEASE"] || !developing_rubydex
22
+
12
23
  root_dir = gem_dir.join("rust")
13
24
  target_dir = root_dir.join("target")
14
25
  target_dir = target_dir.join("x86_64-pc-windows-gnu") if Gem.win_platform?
data/ext/rubydex/graph.c CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  static VALUE cGraph;
12
12
  static VALUE mRubydex;
13
+ static VALUE cKeyword;
14
+ static VALUE cKeywordParameter;
13
15
 
14
16
  // Free function for the custom Graph allocator. We always have to call into Rust to free data allocated by it
15
17
  static void graph_free(void *ptr) {
@@ -246,9 +248,9 @@ static VALUE graph_constant_references_size(VALUE self, VALUE _args, VALUE _eobj
246
248
  void *graph;
247
249
  TypedData_Get_Struct(self, void *, &graph_type, graph);
248
250
 
249
- ReferencesIter *iter = rdx_graph_constant_references_iter_new(graph);
250
- size_t len = rdx_references_iter_len(iter);
251
- rdx_references_iter_free(iter);
251
+ struct ConstantReferencesIter *iter = rdx_graph_constant_references_iter_new(graph);
252
+ size_t len = rdx_constant_references_iter_len(iter);
253
+ rdx_constant_references_iter_free(iter);
252
254
 
253
255
  return SIZET2NUM(len);
254
256
  }
@@ -266,7 +268,7 @@ static VALUE rdxr_graph_constant_references(VALUE self) {
266
268
 
267
269
  void *iter = rdx_graph_constant_references_iter_new(graph);
268
270
  VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
269
- rb_ensure(rdxi_references_yield, args, rdxi_references_ensure, args);
271
+ rb_ensure(rdxi_constant_references_yield, args, rdxi_constant_references_ensure, args);
270
272
 
271
273
  return self;
272
274
  }
@@ -276,9 +278,9 @@ static VALUE graph_method_references_size(VALUE self, VALUE _args, VALUE _eobj)
276
278
  void *graph;
277
279
  TypedData_Get_Struct(self, void *, &graph_type, graph);
278
280
 
279
- ReferencesIter *iter = rdx_graph_method_references_iter_new(graph);
280
- size_t len = rdx_references_iter_len(iter);
281
- rdx_references_iter_free(iter);
281
+ struct MethodReferencesIter *iter = rdx_graph_method_references_iter_new(graph);
282
+ size_t len = rdx_method_references_iter_len(iter);
283
+ rdx_method_references_iter_free(iter);
282
284
 
283
285
  return SIZET2NUM(len);
284
286
  }
@@ -296,7 +298,7 @@ static VALUE rdxr_graph_method_references(VALUE self) {
296
298
 
297
299
  void *iter = rdx_graph_method_references_iter_new(graph);
298
300
  VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
299
- rb_ensure(rdxi_references_yield, args, rdxi_references_ensure, args);
301
+ rb_ensure(rdxi_method_references_yield, args, rdxi_method_references_ensure, args);
300
302
 
301
303
  return self;
302
304
  }
@@ -488,9 +490,170 @@ static VALUE rdxr_graph_diagnostics(VALUE self) {
488
490
  return diagnostics;
489
491
  }
490
492
 
493
+ // Helper: convert a CompletionResult into a Ruby array, raising ArgumentError on error.
494
+ static VALUE completion_result_to_ruby_array(struct CompletionResult result, VALUE graph_obj) {
495
+ if (result.error != NULL) {
496
+ VALUE msg = rb_utf8_str_new_cstr(result.error);
497
+ free_c_string(result.error);
498
+ rb_raise(rb_eArgError, "%s", StringValueCStr(msg));
499
+ }
500
+
501
+ CompletionCandidateArray *array = result.candidates;
502
+ if (array == NULL) {
503
+ return rb_ary_new();
504
+ }
505
+
506
+ if (array->len == 0) {
507
+ rdx_completion_candidates_free(array);
508
+ return rb_ary_new();
509
+ }
510
+
511
+ VALUE ruby_array = rb_ary_new_capa((long)array->len);
512
+
513
+ for (size_t i = 0; i < array->len; i++) {
514
+ CCompletionCandidate item = array->items[i];
515
+ VALUE obj;
516
+
517
+ switch (item.kind) {
518
+ case CCompletionCandidateKind_Declaration: {
519
+ VALUE decl_class = rdxi_declaration_class_for_kind(item.declaration->kind);
520
+ VALUE argv[] = {graph_obj, ULL2NUM(item.declaration->id)};
521
+ obj = rb_class_new_instance(2, argv, decl_class);
522
+ break;
523
+ }
524
+ case CCompletionCandidateKind_Keyword: {
525
+ VALUE argv[2] = {
526
+ rb_utf8_str_new_cstr(item.name),
527
+ rb_utf8_str_new_cstr(item.documentation),
528
+ };
529
+ obj = rb_class_new_instance(2, argv, cKeyword);
530
+ break;
531
+ }
532
+ case CCompletionCandidateKind_KeywordParameter: {
533
+ VALUE argv[1] = { rb_utf8_str_new_cstr(item.name) };
534
+ obj = rb_class_new_instance(1, argv, cKeywordParameter);
535
+ break;
536
+ }
537
+ default:
538
+ rdx_completion_candidates_free(array);
539
+ rb_raise(rb_eRuntimeError, "Unknown CCompletionCandidateKind: %d", item.kind);
540
+ }
541
+
542
+ rb_ary_push(ruby_array, obj);
543
+ }
544
+
545
+ rdx_completion_candidates_free(array);
546
+ return ruby_array;
547
+ }
548
+
549
+ // Graph#complete_expression: (Array[String] nesting) -> Array[Declaration | Keyword]
550
+ // Returns completion candidates for an expression context.
551
+ // The nesting array represents the lexical scope stack
552
+ static VALUE rdxr_graph_complete_expression(VALUE self, VALUE nesting) {
553
+ rdxi_check_array_of_strings(nesting);
554
+
555
+ void *graph;
556
+ TypedData_Get_Struct(self, void *, &graph_type, graph);
557
+
558
+ size_t nesting_count = RARRAY_LEN(nesting);
559
+ char **converted_nesting = rdxi_str_array_to_char(nesting, nesting_count);
560
+
561
+ struct CompletionResult result =
562
+ rdx_graph_complete_expression(graph, (const char *const *)converted_nesting, nesting_count);
563
+
564
+ rdxi_free_str_array(converted_nesting, nesting_count);
565
+ return completion_result_to_ruby_array(result, self);
566
+ }
567
+
568
+ // Graph#complete_namespace_access: (String name) -> Array[Declaration]
569
+ // Returns completion candidates after a namespace access operator (e.g., `Foo::`).
570
+ static VALUE rdxr_graph_complete_namespace_access(VALUE self, VALUE name) {
571
+ Check_Type(name, T_STRING);
572
+
573
+ void *graph;
574
+ TypedData_Get_Struct(self, void *, &graph_type, graph);
575
+
576
+ struct CompletionResult result = rdx_graph_complete_namespace_access(graph, StringValueCStr(name));
577
+ return completion_result_to_ruby_array(result, self);
578
+ }
579
+
580
+ // Graph#complete_method_call: (String name) -> Array[Declaration]
581
+ // Returns completion candidates after a method call operator (e.g., `foo.`).
582
+ static VALUE rdxr_graph_complete_method_call(VALUE self, VALUE name) {
583
+ Check_Type(name, T_STRING);
584
+
585
+ void *graph;
586
+ TypedData_Get_Struct(self, void *, &graph_type, graph);
587
+
588
+ struct CompletionResult result = rdx_graph_complete_method_call(graph, StringValueCStr(name));
589
+ return completion_result_to_ruby_array(result, self);
590
+ }
591
+
592
+ // Graph#complete_method_argument: (String name, Array[String] nesting) -> Array[Declaration | Keyword | KeywordParameter]
593
+ // Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`).
594
+ static VALUE rdxr_graph_complete_method_argument(VALUE self, VALUE name, VALUE nesting) {
595
+ Check_Type(name, T_STRING);
596
+ rdxi_check_array_of_strings(nesting);
597
+
598
+ void *graph;
599
+ TypedData_Get_Struct(self, void *, &graph_type, graph);
600
+
601
+ size_t nesting_count = RARRAY_LEN(nesting);
602
+ char **converted_nesting = rdxi_str_array_to_char(nesting, nesting_count);
603
+
604
+ struct CompletionResult result = rdx_graph_complete_method_argument(
605
+ graph, StringValueCStr(name), (const char *const *)converted_nesting, nesting_count);
606
+
607
+ rdxi_free_str_array(converted_nesting, nesting_count);
608
+ return completion_result_to_ruby_array(result, self);
609
+ }
610
+
611
+ // Graph#exclude_paths: (Array[String] paths) -> void
612
+ // Excludes the given paths from file discovery during indexing.
613
+ static VALUE rdxr_graph_exclude_paths(VALUE self, VALUE paths) {
614
+ Check_Type(paths, T_ARRAY);
615
+ rdxi_check_array_of_strings(paths);
616
+
617
+ size_t length = RARRAY_LEN(paths);
618
+ char **converted_paths = rdxi_str_array_to_char(paths, length);
619
+
620
+ void *graph;
621
+ TypedData_Get_Struct(self, void*, &graph_type, graph);
622
+
623
+ rdx_graph_exclude_paths(graph, (const char **)converted_paths, length);
624
+ rdxi_free_str_array(converted_paths, length);
625
+
626
+ return Qnil;
627
+ }
628
+
629
+ // Graph#excluded_paths: () -> Array[String]
630
+ // Returns the list of paths currently excluded from file discovery.
631
+ static VALUE rdxr_graph_excluded_paths(VALUE self) {
632
+ void *graph;
633
+ TypedData_Get_Struct(self, void*, &graph_type, graph);
634
+
635
+ size_t out_count = 0;
636
+ const char *const *results = rdx_graph_excluded_paths(graph, &out_count);
637
+
638
+ if (results == NULL) {
639
+ return rb_ary_new();
640
+ }
641
+
642
+ VALUE array = rb_ary_new_capa((long)out_count);
643
+ for (size_t i = 0; i < out_count; i++) {
644
+ rb_ary_push(array, rb_utf8_str_new_cstr(results[i]));
645
+ }
646
+
647
+ free_c_string_array(results, out_count);
648
+ return array;
649
+ }
650
+
491
651
  void rdxi_initialize_graph(VALUE moduleRubydex) {
492
652
  mRubydex = moduleRubydex;
493
653
  cGraph = rb_define_class_under(mRubydex, "Graph", rb_cObject);
654
+ cKeyword = rb_define_class_under(mRubydex, "Keyword", rb_cObject);
655
+ cKeywordParameter = rb_define_class_under(mRubydex, "KeywordParameter", rb_cObject);
656
+
494
657
  rb_define_alloc_func(cGraph, rdxr_graph_alloc);
495
658
  rb_define_method(cGraph, "index_all", rdxr_graph_index_all, 1);
496
659
  rb_define_method(cGraph, "index_source", rdxr_graph_index_source, 3);
@@ -509,4 +672,10 @@ void rdxi_initialize_graph(VALUE moduleRubydex) {
509
672
  rb_define_method(cGraph, "encoding=", rdxr_graph_set_encoding, 1);
510
673
  rb_define_method(cGraph, "resolve_require_path", rdxr_graph_resolve_require_path, 2);
511
674
  rb_define_method(cGraph, "require_paths", rdxr_graph_require_paths, 1);
675
+ rb_define_method(cGraph, "complete_expression", rdxr_graph_complete_expression, 1);
676
+ rb_define_method(cGraph, "complete_namespace_access", rdxr_graph_complete_namespace_access, 1);
677
+ rb_define_method(cGraph, "complete_method_call", rdxr_graph_complete_method_call, 1);
678
+ rb_define_method(cGraph, "complete_method_argument", rdxr_graph_complete_method_argument, 2);
679
+ rb_define_method(cGraph, "exclude_paths", rdxr_graph_exclude_paths, 1);
680
+ rb_define_method(cGraph, "excluded_paths", rdxr_graph_excluded_paths, 0);
512
681
  }
@@ -1,4 +1,5 @@
1
1
  #include "reference.h"
2
+ #include "declaration.h"
2
3
  #include "graph.h"
3
4
  #include "handle.h"
4
5
  #include "location.h"
@@ -6,6 +7,8 @@
6
7
 
7
8
  VALUE cReference;
8
9
  VALUE cConstantReference;
10
+ VALUE cUnresolvedConstantReference;
11
+ VALUE cResolvedConstantReference;
9
12
  VALUE cMethodReference;
10
13
 
11
14
  // ConstantReference#name -> String
@@ -72,16 +75,24 @@ static VALUE rdxr_method_reference_location(VALUE self) {
72
75
  return location;
73
76
  }
74
77
 
75
- // Keep this in sync with unresolved_reference_api.rs
76
- VALUE rdxi_reference_class_for_kind(ReferenceKind kind) {
77
- switch (kind) {
78
- case ReferenceKind_Constant:
79
- return cConstantReference;
80
- case ReferenceKind_Method:
81
- return cMethodReference;
82
- default:
83
- rb_raise(rb_eRuntimeError, "Unknown UnresolvedReferenceKind: %d", kind);
78
+ // ResolvedConstantReference#declaration -> Declaration
79
+ static VALUE rdxr_resolved_constant_reference_declaration(VALUE self) {
80
+ HandleData *data;
81
+ TypedData_Get_Struct(self, HandleData, &handle_type, data);
82
+
83
+ void *graph;
84
+ TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
85
+
86
+ const struct CDeclaration *decl = rdx_resolved_constant_reference_declaration(graph, data->id);
87
+ if (decl == NULL) {
88
+ rb_raise(rb_eRuntimeError, "Invalid declaration for a resolved constant reference");
84
89
  }
90
+
91
+ VALUE decl_class = rdxi_declaration_class_for_kind(decl->kind);
92
+ VALUE argv[] = {data->graph_obj, ULL2NUM(decl->id)};
93
+ free_c_declaration(decl);
94
+
95
+ return rb_class_new_instance(2, argv, decl_class);
85
96
  }
86
97
 
87
98
  void rdxi_initialize_reference(VALUE mRubydex) {
@@ -93,8 +104,16 @@ void rdxi_initialize_reference(VALUE mRubydex) {
93
104
  cConstantReference = rb_define_class_under(mRubydex, "ConstantReference", cReference);
94
105
  rb_define_alloc_func(cConstantReference, rdxr_handle_alloc);
95
106
  rb_define_method(cConstantReference, "initialize", rdxr_handle_initialize, 2);
96
- rb_define_method(cConstantReference, "name", rdxr_constant_reference_name, 0);
97
107
  rb_define_method(cConstantReference, "location", rdxr_constant_reference_location, 0);
108
+ rb_funcall(rb_singleton_class(cConstantReference), rb_intern("private"), 1, ID2SYM(rb_intern("new")));
109
+
110
+ cUnresolvedConstantReference = rb_define_class_under(mRubydex, "UnresolvedConstantReference", cConstantReference);
111
+ rb_define_alloc_func(cUnresolvedConstantReference, rdxr_handle_alloc);
112
+ rb_define_method(cUnresolvedConstantReference, "name", rdxr_constant_reference_name, 0);
113
+
114
+ cResolvedConstantReference = rb_define_class_under(mRubydex, "ResolvedConstantReference", cConstantReference);
115
+ rb_define_alloc_func(cResolvedConstantReference, rdxr_handle_alloc);
116
+ rb_define_method(cResolvedConstantReference, "declaration", rdxr_resolved_constant_reference_declaration, 0);
98
117
 
99
118
  cMethodReference = rb_define_class_under(mRubydex, "MethodReference", cReference);
100
119
  rb_define_alloc_func(cMethodReference, rdxr_handle_alloc);
@@ -6,11 +6,10 @@
6
6
 
7
7
  extern VALUE cReference;
8
8
  extern VALUE cConstantReference;
9
+ extern VALUE cUnresolvedConstantReference;
10
+ extern VALUE cResolvedConstantReference;
9
11
  extern VALUE cMethodReference;
10
12
 
11
13
  void rdxi_initialize_reference(VALUE mRubydex);
12
14
 
13
- // Returns the Ruby class for a given UnresolvedReferenceKind without calling back into Rust
14
- VALUE rdxi_reference_class_for_kind(ReferenceKind kind);
15
-
16
15
  #endif // RUBYDEX_REFERENCE_H