rubydex 0.1.0.beta14 → 0.2.1
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.
- checksums.yaml +4 -4
- data/exe/rdx +28 -24
- data/ext/rubydex/declaration.c +38 -0
- data/ext/rubydex/extconf.rb +7 -5
- data/ext/rubydex/graph.c +89 -17
- data/ext/rubydex/reference.c +23 -0
- data/lib/rubydex/declaration.rb +31 -0
- data/lib/rubydex/version.rb +1 -1
- data/rbi/rubydex.rbi +47 -11
- data/rust/rubydex/src/diagnostic.rs +1 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +4 -5
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +27 -7
- data/rust/rubydex/src/model/declaration.rs +48 -0
- data/rust/rubydex/src/model/definitions.rs +18 -9
- data/rust/rubydex/src/model/graph.rs +237 -35
- data/rust/rubydex/src/query.rs +1475 -159
- data/rust/rubydex/src/resolution.rs +173 -61
- data/rust/rubydex/src/resolution_tests.rs +178 -0
- data/rust/rubydex-sys/src/declaration_api.rs +19 -0
- data/rust/rubydex-sys/src/graph_api.rs +113 -6
- data/rust/rubydex-sys/src/reference_api.rs +37 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8b492c7be7e3fdd85ffa12dc17e7bdb19a77e469dbfa2a69cdb175a4c0b0cb84
|
|
4
|
+
data.tar.gz: e0b0f1f47e15a93f99e1e634ab76aee01aa6c4d78110a95344817fa4276b769a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 31e6325b46717f297adacc1ceb08d5700f6f189976358677858710150073e1f016d6a739bc88cb936d777c1bb318e48f96d0cba9f3f6287697d33e0d5c679bc4
|
|
7
|
+
data.tar.gz: c9bc693cdb897e65def20958848762997cc3f6cb1d7b6d42e5b58f7620495da4bb20bf181391cc7d42cce9f5bf7d9106060019874f224214c22b9a6a2a15fec1
|
data/exe/rdx
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
|
5
|
+
|
|
5
6
|
require "optparse"
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
parser.banner = "Usage: [path1, path2]"
|
|
8
|
+
options = {}
|
|
9
9
|
|
|
10
|
+
OptionParser.new do |parser|
|
|
10
11
|
parser.on("--version", "Print the gem's version") do
|
|
11
12
|
require "rubydex/version"
|
|
12
13
|
puts "v#{Rubydex::VERSION}"
|
|
@@ -17,31 +18,34 @@ OptionParser.new do |parser|
|
|
|
17
18
|
puts parser
|
|
18
19
|
exit
|
|
19
20
|
end
|
|
21
|
+
|
|
22
|
+
parser.on("-i", "--interactive", "Open an interactive session with a populated graph for the current workspace") do
|
|
23
|
+
options[:interactive] = true
|
|
24
|
+
end
|
|
20
25
|
end.parse!
|
|
21
26
|
|
|
22
27
|
require "rubydex"
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if File.exist?(gemfile_path)
|
|
32
|
-
ENV["BUNDLE_GEMFILE"] = gemfile_path
|
|
33
|
-
|
|
34
|
-
begin
|
|
35
|
-
Bundler.setup
|
|
36
|
-
rescue Bundler::BundlerError => e
|
|
37
|
-
$stderr.puts(<<~MESSAGE)
|
|
38
|
-
Bundle setup failed for #{gemfile_path}. Indexing of dependencies may be partial
|
|
39
|
-
Error:
|
|
40
|
-
#{e.message}
|
|
41
|
-
MESSAGE
|
|
42
|
-
end
|
|
43
|
-
end
|
|
29
|
+
def __with_timer(message, &block)
|
|
30
|
+
print(message)
|
|
31
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
|
32
|
+
block.call
|
|
33
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start
|
|
34
|
+
puts " finished in #{duration.round(2)}ms"
|
|
44
35
|
end
|
|
45
36
|
|
|
46
|
-
graph = Rubydex::Graph.new
|
|
47
|
-
graph.index_workspace
|
|
37
|
+
graph = Rubydex::Graph.new
|
|
38
|
+
__with_timer("Indexing workspace...") { graph.index_workspace }
|
|
39
|
+
__with_timer("Resolving graph...") { graph.resolve }
|
|
40
|
+
|
|
41
|
+
if options[:interactive]
|
|
42
|
+
begin
|
|
43
|
+
require "irb"
|
|
44
|
+
IRB.setup(nil)
|
|
45
|
+
IRB.conf[:IRB_NAME] = "rubydex"
|
|
46
|
+
workspace = IRB::WorkSpace.new(binding)
|
|
47
|
+
IRB::Irb.new(workspace).run(IRB.conf)
|
|
48
|
+
rescue LoadError
|
|
49
|
+
abort("Interactive mode requires `irb` to be in the bundle")
|
|
50
|
+
end
|
|
51
|
+
end
|
data/ext/rubydex/declaration.c
CHANGED
|
@@ -407,6 +407,38 @@ static VALUE rdxr_variable_declaration_references(VALUE self) {
|
|
|
407
407
|
return rb_ary_new();
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
+
static VALUE rdxi_visibility_to_symbol(CVisibility visibility) {
|
|
411
|
+
switch (visibility) {
|
|
412
|
+
case CVisibility_Public:
|
|
413
|
+
return ID2SYM(rb_intern("public"));
|
|
414
|
+
case CVisibility_Protected:
|
|
415
|
+
return ID2SYM(rb_intern("protected"));
|
|
416
|
+
case CVisibility_Private:
|
|
417
|
+
return ID2SYM(rb_intern("private"));
|
|
418
|
+
default:
|
|
419
|
+
rb_raise(rb_eRuntimeError, "Unknown CVisibility: %d", visibility);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Declaration#visibility -> Symbol
|
|
424
|
+
static VALUE rdxr_declaration_visibility(VALUE self) {
|
|
425
|
+
HandleData *data;
|
|
426
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
427
|
+
|
|
428
|
+
void *graph;
|
|
429
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
430
|
+
|
|
431
|
+
const CVisibility *visibility = rdx_graph_visibility(graph, data->id);
|
|
432
|
+
if (visibility == NULL) {
|
|
433
|
+
rb_raise(rb_eRuntimeError, "declaration has no visibility");
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
VALUE symbol = rdxi_visibility_to_symbol(*visibility);
|
|
437
|
+
free_c_visibility(visibility);
|
|
438
|
+
|
|
439
|
+
return symbol;
|
|
440
|
+
}
|
|
441
|
+
|
|
410
442
|
// ConstantAlias#target -> Declaration?
|
|
411
443
|
// Returns the first resolved target declaration for this constant alias, or nil if none of its definitions resolved to
|
|
412
444
|
// a target
|
|
@@ -459,13 +491,19 @@ void rdxi_initialize_declaration(VALUE mRubydex) {
|
|
|
459
491
|
rb_define_method(cNamespace, "descendants", rdxr_declaration_descendants, 0);
|
|
460
492
|
rb_define_method(cNamespace, "members", rdxr_declaration_members, 0);
|
|
461
493
|
|
|
494
|
+
rb_define_method(cClass, "visibility", rdxr_declaration_visibility, 0);
|
|
495
|
+
rb_define_method(cModule, "visibility", rdxr_declaration_visibility, 0);
|
|
496
|
+
|
|
462
497
|
// Constant and ConstantAlias have constant references
|
|
463
498
|
rb_define_method(cConstant, "references", rdxr_constant_declaration_references, 0);
|
|
499
|
+
rb_define_method(cConstant, "visibility", rdxr_declaration_visibility, 0);
|
|
464
500
|
rb_define_method(cConstantAlias, "references", rdxr_constant_declaration_references, 0);
|
|
465
501
|
rb_define_method(cConstantAlias, "target", rdxr_constant_alias_target, 0);
|
|
502
|
+
rb_define_method(cConstantAlias, "visibility", rdxr_declaration_visibility, 0);
|
|
466
503
|
|
|
467
504
|
// Method has method references
|
|
468
505
|
rb_define_method(cMethod, "references", rdxr_method_declaration_references, 0);
|
|
506
|
+
rb_define_method(cMethod, "visibility", rdxr_declaration_visibility, 0);
|
|
469
507
|
|
|
470
508
|
// Variable declarations don't yet support references
|
|
471
509
|
rb_define_method(cGlobalVariable, "references", rdxr_variable_declaration_references, 0);
|
data/ext/rubydex/extconf.rb
CHANGED
|
@@ -141,10 +141,12 @@ end
|
|
|
141
141
|
|
|
142
142
|
File.write("Makefile", new_makefile)
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
if developing_rubydex
|
|
145
|
+
begin
|
|
146
|
+
require "extconf_compile_commands_json"
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
rescue LoadError # rubocop:disable Lint/SuppressedException
|
|
148
|
+
ExtconfCompileCommandsJson.generate!
|
|
149
|
+
ExtconfCompileCommandsJson.symlink!
|
|
150
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
|
151
|
+
end
|
|
150
152
|
end
|
data/ext/rubydex/graph.c
CHANGED
|
@@ -13,6 +13,31 @@ static VALUE mRubydex;
|
|
|
13
13
|
static VALUE cKeyword;
|
|
14
14
|
static VALUE cKeywordParameter;
|
|
15
15
|
|
|
16
|
+
// Interned once in `rdxi_initialize_graph` to avoid repeated symbol-table lookups on hot completion paths.
|
|
17
|
+
static ID id_self_receiver;
|
|
18
|
+
|
|
19
|
+
// Extracts the optional `self_receiver:` kwarg from `opts`. Returns NULL when the kwarg is
|
|
20
|
+
// absent or nil; raises ArgumentError when the value is the wrong type or empty.
|
|
21
|
+
static const char *extract_self_receiver(VALUE opts) {
|
|
22
|
+
if (NIL_P(opts)) {
|
|
23
|
+
return NULL;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
VALUE kwarg_val;
|
|
27
|
+
rb_get_kwargs(opts, &id_self_receiver, 0, 1, &kwarg_val);
|
|
28
|
+
|
|
29
|
+
if (kwarg_val == Qundef || NIL_P(kwarg_val)) {
|
|
30
|
+
return NULL;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Check_Type(kwarg_val, T_STRING);
|
|
34
|
+
if (RSTRING_LEN(kwarg_val) == 0) {
|
|
35
|
+
rb_raise(rb_eArgError, "self_receiver cannot be empty");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return StringValueCStr(kwarg_val);
|
|
39
|
+
}
|
|
40
|
+
|
|
16
41
|
// Free function for the custom Graph allocator. We always have to call into Rust to free data allocated by it
|
|
17
42
|
static void graph_free(void *ptr) {
|
|
18
43
|
if (ptr) {
|
|
@@ -303,6 +328,24 @@ static VALUE rdxr_graph_method_references(VALUE self) {
|
|
|
303
328
|
return self;
|
|
304
329
|
}
|
|
305
330
|
|
|
331
|
+
// Graph#document: (String uri) -> Document?
|
|
332
|
+
// Returns the Document for the given URI, or nil if it doesn't exist.
|
|
333
|
+
static VALUE rdxr_graph_document(VALUE self, VALUE uri) {
|
|
334
|
+
Check_Type(uri, T_STRING);
|
|
335
|
+
|
|
336
|
+
void *graph;
|
|
337
|
+
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
338
|
+
const uint64_t *uri_id = rdx_graph_get_document(graph, StringValueCStr(uri));
|
|
339
|
+
|
|
340
|
+
if (uri_id == NULL) {
|
|
341
|
+
return Qnil;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
VALUE argv[] = {self, ULL2NUM(*uri_id)};
|
|
345
|
+
free_u64(uri_id);
|
|
346
|
+
return rb_class_new_instance(2, argv, cDocument);
|
|
347
|
+
}
|
|
348
|
+
|
|
306
349
|
// Graph#delete_document: (String uri) -> Document?
|
|
307
350
|
// Deletes a document and all of its definitions from the graph.
|
|
308
351
|
// Returns the removed Document or nil if it doesn't exist.
|
|
@@ -546,12 +589,18 @@ static VALUE completion_result_to_ruby_array(struct CompletionResult result, VAL
|
|
|
546
589
|
return ruby_array;
|
|
547
590
|
}
|
|
548
591
|
|
|
549
|
-
// Graph#complete_expression: (Array[String] nesting) -> Array[Declaration | Keyword]
|
|
592
|
+
// Graph#complete_expression: (Array[String] nesting, self_receiver: nil) -> Array[Declaration | Keyword]
|
|
550
593
|
// Returns completion candidates for an expression context.
|
|
551
|
-
// The nesting array represents the lexical scope stack
|
|
552
|
-
|
|
594
|
+
// The nesting array represents the lexical scope stack. The optional self_receiver keyword argument
|
|
595
|
+
// overrides the self-type (e.g., "Foo::<Foo>" for `def Foo.bar`); when nil, self is derived from
|
|
596
|
+
// the innermost nesting element.
|
|
597
|
+
static VALUE rdxr_graph_complete_expression(int argc, VALUE *argv, VALUE self) {
|
|
598
|
+
VALUE nesting, opts;
|
|
599
|
+
rb_scan_args(argc, argv, "1:", &nesting, &opts);
|
|
553
600
|
rdxi_check_array_of_strings(nesting);
|
|
554
601
|
|
|
602
|
+
const char *self_receiver = extract_self_receiver(opts);
|
|
603
|
+
|
|
555
604
|
void *graph;
|
|
556
605
|
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
557
606
|
|
|
@@ -559,42 +608,62 @@ static VALUE rdxr_graph_complete_expression(VALUE self, VALUE nesting) {
|
|
|
559
608
|
char **converted_nesting = rdxi_str_array_to_char(nesting, nesting_count);
|
|
560
609
|
|
|
561
610
|
struct CompletionResult result =
|
|
562
|
-
rdx_graph_complete_expression(graph, (const char *const *)converted_nesting, nesting_count);
|
|
611
|
+
rdx_graph_complete_expression(graph, (const char *const *)converted_nesting, nesting_count, self_receiver);
|
|
563
612
|
|
|
564
613
|
rdxi_free_str_array(converted_nesting, nesting_count);
|
|
565
614
|
return completion_result_to_ruby_array(result, self);
|
|
566
615
|
}
|
|
567
616
|
|
|
568
|
-
// Graph#complete_namespace_access: (String name) -> Array[Declaration]
|
|
617
|
+
// Graph#complete_namespace_access: (String name, self_receiver: nil) -> Array[Declaration]
|
|
569
618
|
// Returns completion candidates after a namespace access operator (e.g., `Foo::`).
|
|
570
|
-
|
|
619
|
+
// The optional self_receiver kwarg is the caller's runtime self type, used to filter
|
|
620
|
+
// visibility-restricted singleton methods (e.g., `private_class_method`).
|
|
621
|
+
static VALUE rdxr_graph_complete_namespace_access(int argc, VALUE *argv, VALUE self) {
|
|
622
|
+
VALUE name, opts;
|
|
623
|
+
rb_scan_args(argc, argv, "1:", &name, &opts);
|
|
571
624
|
Check_Type(name, T_STRING);
|
|
572
625
|
|
|
626
|
+
const char *self_receiver = extract_self_receiver(opts);
|
|
627
|
+
|
|
573
628
|
void *graph;
|
|
574
629
|
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
575
630
|
|
|
576
|
-
struct CompletionResult result =
|
|
631
|
+
struct CompletionResult result =
|
|
632
|
+
rdx_graph_complete_namespace_access(graph, StringValueCStr(name), self_receiver);
|
|
577
633
|
return completion_result_to_ruby_array(result, self);
|
|
578
634
|
}
|
|
579
635
|
|
|
580
|
-
// Graph#complete_method_call: (String name) -> Array[Declaration]
|
|
636
|
+
// Graph#complete_method_call: (String name, self_receiver: nil) -> Array[Declaration]
|
|
581
637
|
// Returns completion candidates after a method call operator (e.g., `foo.`).
|
|
582
|
-
|
|
638
|
+
// The optional self_receiver kwarg is the caller's runtime self type, used for MRI-style
|
|
639
|
+
// visibility checks (private/protected).
|
|
640
|
+
static VALUE rdxr_graph_complete_method_call(int argc, VALUE *argv, VALUE self) {
|
|
641
|
+
VALUE name, opts;
|
|
642
|
+
rb_scan_args(argc, argv, "1:", &name, &opts);
|
|
583
643
|
Check_Type(name, T_STRING);
|
|
584
644
|
|
|
645
|
+
const char *self_receiver = extract_self_receiver(opts);
|
|
646
|
+
|
|
585
647
|
void *graph;
|
|
586
648
|
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
587
649
|
|
|
588
|
-
struct CompletionResult result =
|
|
650
|
+
struct CompletionResult result =
|
|
651
|
+
rdx_graph_complete_method_call(graph, StringValueCStr(name), self_receiver);
|
|
589
652
|
return completion_result_to_ruby_array(result, self);
|
|
590
653
|
}
|
|
591
654
|
|
|
592
|
-
// Graph#complete_method_argument: (String name, Array[String] nesting) -> Array[Declaration | Keyword | KeywordParameter]
|
|
655
|
+
// Graph#complete_method_argument: (String name, Array[String] nesting, self_receiver: nil) -> Array[Declaration | Keyword | KeywordParameter]
|
|
593
656
|
// Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`).
|
|
594
|
-
|
|
657
|
+
// See complete_expression for semantics of self_receiver.
|
|
658
|
+
static VALUE rdxr_graph_complete_method_argument(int argc, VALUE *argv, VALUE self) {
|
|
659
|
+
VALUE name, nesting, opts;
|
|
660
|
+
rb_scan_args(argc, argv, "2:", &name, &nesting, &opts);
|
|
661
|
+
|
|
595
662
|
Check_Type(name, T_STRING);
|
|
596
663
|
rdxi_check_array_of_strings(nesting);
|
|
597
664
|
|
|
665
|
+
const char *self_receiver = extract_self_receiver(opts);
|
|
666
|
+
|
|
598
667
|
void *graph;
|
|
599
668
|
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
600
669
|
|
|
@@ -602,7 +671,7 @@ static VALUE rdxr_graph_complete_method_argument(VALUE self, VALUE name, VALUE n
|
|
|
602
671
|
char **converted_nesting = rdxi_str_array_to_char(nesting, nesting_count);
|
|
603
672
|
|
|
604
673
|
struct CompletionResult result = rdx_graph_complete_method_argument(
|
|
605
|
-
graph, StringValueCStr(name), (const char *const *)converted_nesting, nesting_count);
|
|
674
|
+
graph, StringValueCStr(name), (const char *const *)converted_nesting, nesting_count, self_receiver);
|
|
606
675
|
|
|
607
676
|
rdxi_free_str_array(converted_nesting, nesting_count);
|
|
608
677
|
return completion_result_to_ruby_array(result, self);
|
|
@@ -673,9 +742,12 @@ void rdxi_initialize_graph(VALUE moduleRubydex) {
|
|
|
673
742
|
cKeyword = rb_define_class_under(mRubydex, "Keyword", rb_cObject);
|
|
674
743
|
cKeywordParameter = rb_define_class_under(mRubydex, "KeywordParameter", rb_cObject);
|
|
675
744
|
|
|
745
|
+
id_self_receiver = rb_intern("self_receiver");
|
|
746
|
+
|
|
676
747
|
rb_define_alloc_func(cGraph, rdxr_graph_alloc);
|
|
677
748
|
rb_define_method(cGraph, "index_all", rdxr_graph_index_all, 1);
|
|
678
749
|
rb_define_method(cGraph, "index_source", rdxr_graph_index_source, 3);
|
|
750
|
+
rb_define_method(cGraph, "document", rdxr_graph_document, 1);
|
|
679
751
|
rb_define_method(cGraph, "delete_document", rdxr_graph_delete_document, 1);
|
|
680
752
|
rb_define_method(cGraph, "resolve", rdxr_graph_resolve, 0);
|
|
681
753
|
rb_define_method(cGraph, "resolve_constant", rdxr_graph_resolve_constant, 2);
|
|
@@ -691,10 +763,10 @@ void rdxi_initialize_graph(VALUE moduleRubydex) {
|
|
|
691
763
|
rb_define_method(cGraph, "encoding=", rdxr_graph_set_encoding, 1);
|
|
692
764
|
rb_define_method(cGraph, "resolve_require_path", rdxr_graph_resolve_require_path, 2);
|
|
693
765
|
rb_define_method(cGraph, "require_paths", rdxr_graph_require_paths, 1);
|
|
694
|
-
rb_define_method(cGraph, "complete_expression", rdxr_graph_complete_expression, 1);
|
|
695
|
-
rb_define_method(cGraph, "complete_namespace_access", rdxr_graph_complete_namespace_access, 1);
|
|
696
|
-
rb_define_method(cGraph, "complete_method_call", rdxr_graph_complete_method_call, 1);
|
|
697
|
-
rb_define_method(cGraph, "complete_method_argument", rdxr_graph_complete_method_argument,
|
|
766
|
+
rb_define_method(cGraph, "complete_expression", rdxr_graph_complete_expression, -1);
|
|
767
|
+
rb_define_method(cGraph, "complete_namespace_access", rdxr_graph_complete_namespace_access, -1);
|
|
768
|
+
rb_define_method(cGraph, "complete_method_call", rdxr_graph_complete_method_call, -1);
|
|
769
|
+
rb_define_method(cGraph, "complete_method_argument", rdxr_graph_complete_method_argument, -1);
|
|
698
770
|
rb_define_method(cGraph, "exclude_paths", rdxr_graph_exclude_paths, 1);
|
|
699
771
|
rb_define_method(cGraph, "excluded_paths", rdxr_graph_excluded_paths, 0);
|
|
700
772
|
rb_define_method(cGraph, "keyword", rdxr_graph_keyword, 1);
|
data/ext/rubydex/reference.c
CHANGED
|
@@ -75,6 +75,28 @@ static VALUE rdxr_method_reference_location(VALUE self) {
|
|
|
75
75
|
return location;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// MethodReference#receiver -> Rubydex::Declaration?
|
|
79
|
+
// Returns the resolved declaration for the receiver of the method call. Returns nil when the receiver is not a
|
|
80
|
+
// tracked constant or cannot be resolved.
|
|
81
|
+
static VALUE rdxr_method_reference_receiver(VALUE self) {
|
|
82
|
+
HandleData *data;
|
|
83
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
84
|
+
|
|
85
|
+
void *graph;
|
|
86
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
87
|
+
|
|
88
|
+
const struct CDeclaration *decl = rdx_method_reference_receiver_declaration(graph, data->id);
|
|
89
|
+
if (decl == NULL) {
|
|
90
|
+
return Qnil;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
VALUE decl_class = rdxi_declaration_class_for_kind(decl->kind);
|
|
94
|
+
VALUE argv[] = {data->graph_obj, ULL2NUM(decl->id)};
|
|
95
|
+
free_c_declaration(decl);
|
|
96
|
+
|
|
97
|
+
return rb_class_new_instance(2, argv, decl_class);
|
|
98
|
+
}
|
|
99
|
+
|
|
78
100
|
// ResolvedConstantReference#declaration -> Declaration
|
|
79
101
|
static VALUE rdxr_resolved_constant_reference_declaration(VALUE self) {
|
|
80
102
|
HandleData *data;
|
|
@@ -120,4 +142,5 @@ void rdxi_initialize_reference(VALUE mRubydex) {
|
|
|
120
142
|
rb_define_method(cMethodReference, "initialize", rdxr_handle_initialize, 2);
|
|
121
143
|
rb_define_method(cMethodReference, "name", rdxr_method_reference_name, 0);
|
|
122
144
|
rb_define_method(cMethodReference, "location", rdxr_method_reference_location, 0);
|
|
145
|
+
rb_define_method(cMethodReference, "receiver", rdxr_method_reference_receiver, 0);
|
|
123
146
|
}
|
data/lib/rubydex/declaration.rb
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Rubydex
|
|
4
|
+
module Visibility
|
|
5
|
+
#: () -> bool
|
|
6
|
+
def public? = visibility == :public
|
|
7
|
+
|
|
8
|
+
#: () -> bool
|
|
9
|
+
def private? = visibility == :private
|
|
10
|
+
|
|
11
|
+
#: () -> bool
|
|
12
|
+
def protected? = visibility == :protected
|
|
13
|
+
end
|
|
14
|
+
|
|
4
15
|
class Declaration
|
|
5
16
|
# @abstract
|
|
6
17
|
#: () -> Enumerable[Reference]
|
|
@@ -8,4 +19,24 @@ module Rubydex
|
|
|
8
19
|
raise NotImplementedError, "Subclasses must implement #references"
|
|
9
20
|
end
|
|
10
21
|
end
|
|
22
|
+
|
|
23
|
+
class Class < Namespace
|
|
24
|
+
include Visibility
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class Module < Namespace
|
|
28
|
+
include Visibility
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Constant < Declaration
|
|
32
|
+
include Visibility
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class ConstantAlias < Declaration
|
|
36
|
+
include Visibility
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Method < Declaration
|
|
40
|
+
include Visibility
|
|
41
|
+
end
|
|
11
42
|
end
|
data/lib/rubydex/version.rb
CHANGED
data/rbi/rubydex.rbi
CHANGED
|
@@ -152,6 +152,7 @@ class Rubydex::GlobalVariableDefinition < Rubydex::Definition; end
|
|
|
152
152
|
class Rubydex::InstanceVariableDefinition < Rubydex::Definition; end
|
|
153
153
|
class Rubydex::MethodAliasDefinition < Rubydex::Definition; end
|
|
154
154
|
class Rubydex::MethodDefinition < Rubydex::Definition; end
|
|
155
|
+
|
|
155
156
|
class Rubydex::ModuleDefinition < Rubydex::Definition
|
|
156
157
|
sig { returns(T::Array[Rubydex::Mixin]) }
|
|
157
158
|
def mixins; end
|
|
@@ -259,6 +260,9 @@ class Rubydex::Graph
|
|
|
259
260
|
sig { params(uri: String).returns(T.nilable(Rubydex::Document)) }
|
|
260
261
|
def delete_document(uri); end
|
|
261
262
|
|
|
263
|
+
sig { params(uri: String).returns(T.nilable(Rubydex::Document)) }
|
|
264
|
+
def document(uri); end
|
|
265
|
+
|
|
262
266
|
sig { returns(T::Array[Rubydex::Diagnostic]) }
|
|
263
267
|
def diagnostics; end
|
|
264
268
|
|
|
@@ -314,27 +318,56 @@ class Rubydex::Graph
|
|
|
314
318
|
# Returns completion candidates for an expression context. This includes all keywords, constants, methods, instance
|
|
315
319
|
# variables, class variables and global variables reachable from the current lexical scope and self type.
|
|
316
320
|
#
|
|
317
|
-
# The nesting array represents the lexical scope stack
|
|
318
|
-
#
|
|
319
|
-
|
|
320
|
-
|
|
321
|
+
# The nesting array represents the lexical scope stack. The optional `self_receiver` keyword argument overrides the
|
|
322
|
+
# self type independently of the lexical scope (e.g., `"Foo::<Foo>"` for `def Foo.bar`). This distinction is important
|
|
323
|
+
# because constants and class variables are always attached to the lexical scope. Meanwhile, methods and instance
|
|
324
|
+
# variables are attached to the type of `self` and those don't always match.
|
|
325
|
+
sig do
|
|
326
|
+
params(
|
|
327
|
+
nesting: T::Array[String],
|
|
328
|
+
self_receiver: T.nilable(String),
|
|
329
|
+
).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword)])
|
|
330
|
+
end
|
|
331
|
+
def complete_expression(nesting, self_receiver: nil); end
|
|
321
332
|
|
|
322
333
|
# Returns completion candidates after a namespace access operator (e.g., `Foo::`). This includes all constants and
|
|
323
334
|
# singleton methods for the namespace and its ancestors.
|
|
324
|
-
|
|
325
|
-
|
|
335
|
+
#
|
|
336
|
+
# The optional `self_receiver` kwarg is the caller's runtime self type. It's used to filter visibility-restricted
|
|
337
|
+
# singleton methods (e.g., `private_class_method`). Pass `nil` (the default) for top-level/script scope.
|
|
338
|
+
sig do
|
|
339
|
+
params(
|
|
340
|
+
name: String,
|
|
341
|
+
self_receiver: T.nilable(String),
|
|
342
|
+
).returns(T::Array[Rubydex::Declaration])
|
|
343
|
+
end
|
|
344
|
+
def complete_namespace_access(name, self_receiver: nil); end
|
|
326
345
|
|
|
327
346
|
# Returns completion candidates after a method call operator (e.g., `foo.`). This includes all methods that exist on
|
|
328
347
|
# the type of the receiver and its ancestors.
|
|
329
|
-
|
|
330
|
-
|
|
348
|
+
#
|
|
349
|
+
# The optional `self_receiver` kwarg is the caller's runtime self type. It's used for visibility checks for `private`
|
|
350
|
+
# and `protected` methods. Pass `nil` (the default) for top-level/script scope.
|
|
351
|
+
sig do
|
|
352
|
+
params(
|
|
353
|
+
name: String,
|
|
354
|
+
self_receiver: T.nilable(String),
|
|
355
|
+
).returns(T::Array[Rubydex::Method])
|
|
356
|
+
end
|
|
357
|
+
def complete_method_call(name, self_receiver: nil); end
|
|
331
358
|
|
|
332
359
|
# Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`). This includes everything
|
|
333
360
|
# that expression completion provides plus keyword argument names of the method being called.
|
|
334
361
|
#
|
|
335
|
-
#
|
|
336
|
-
sig
|
|
337
|
-
|
|
362
|
+
# See `complete_expression` for the semantics of `nesting` and `self_receiver`.
|
|
363
|
+
sig do
|
|
364
|
+
params(
|
|
365
|
+
name: String,
|
|
366
|
+
nesting: T::Array[String],
|
|
367
|
+
self_receiver: T.nilable(String),
|
|
368
|
+
).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword, Rubydex::KeywordParameter)])
|
|
369
|
+
end
|
|
370
|
+
def complete_method_argument(name, nesting, self_receiver: nil); end
|
|
338
371
|
|
|
339
372
|
private
|
|
340
373
|
|
|
@@ -415,6 +448,9 @@ class Rubydex::MethodReference < Rubydex::Reference
|
|
|
415
448
|
|
|
416
449
|
sig { returns(String) }
|
|
417
450
|
def name; end
|
|
451
|
+
|
|
452
|
+
sig { returns(T.nilable(Rubydex::Declaration)) }
|
|
453
|
+
def receiver; end
|
|
418
454
|
end
|
|
419
455
|
|
|
420
456
|
class Rubydex::Reference
|
|
@@ -234,6 +234,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
234
234
|
Offset::from_prism_location(&name_loc),
|
|
235
235
|
str_id,
|
|
236
236
|
)));
|
|
237
|
+
self.visit(&opt_param.value());
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
if let Some(rest) = parameters_list.rest() {
|
|
@@ -276,6 +277,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
276
277
|
let str_id = self.local_graph.intern_string(self.offset_to_string(&offset));
|
|
277
278
|
|
|
278
279
|
parameters.push(Parameter::OptionalKeyword(ParameterStruct::new(offset, str_id)));
|
|
280
|
+
self.visit(&optional.value());
|
|
279
281
|
}
|
|
280
282
|
_ => {}
|
|
281
283
|
}
|
|
@@ -1258,11 +1260,8 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1258
1260
|
let str_id = self.local_graph.intern_string(name);
|
|
1259
1261
|
let offset = Offset::from_prism_location(&location);
|
|
1260
1262
|
let definition = Definition::ConstantVisibility(Box::new(ConstantVisibilityDefinition::new(
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
receiver_name_id.map_or(ParentScope::None, ParentScope::Some),
|
|
1264
|
-
self.current_lexical_scope_name_id(),
|
|
1265
|
-
)),
|
|
1263
|
+
receiver_name_id,
|
|
1264
|
+
str_id,
|
|
1266
1265
|
visibility,
|
|
1267
1266
|
self.uri_id,
|
|
1268
1267
|
offset,
|
|
@@ -3271,31 +3271,38 @@ mod visibility_tests {
|
|
|
3271
3271
|
assert_no_local_diagnostics!(&context);
|
|
3272
3272
|
|
|
3273
3273
|
assert_definition_at!(&context, "6:21-6:24", ConstantVisibility, |def| {
|
|
3274
|
-
|
|
3274
|
+
assert_string_eq!(&context, def.target(), "BAR");
|
|
3275
|
+
assert!(def.receiver().is_none());
|
|
3275
3276
|
assert_eq!(def.visibility(), &Visibility::Private);
|
|
3276
3277
|
});
|
|
3277
3278
|
assert_definition_at!(&context, "6:27-6:30", ConstantVisibility, |def| {
|
|
3278
|
-
|
|
3279
|
+
assert_string_eq!(&context, def.target(), "BAZ");
|
|
3280
|
+
assert!(def.receiver().is_none());
|
|
3279
3281
|
assert_eq!(def.visibility(), &Visibility::Private);
|
|
3280
3282
|
});
|
|
3281
3283
|
assert_definition_at!(&context, "7:20-7:25", ConstantVisibility, |def| {
|
|
3282
|
-
|
|
3284
|
+
assert_string_eq!(&context, def.target(), "FOO");
|
|
3285
|
+
assert!(def.receiver().is_none());
|
|
3283
3286
|
assert_eq!(def.visibility(), &Visibility::Private);
|
|
3284
3287
|
});
|
|
3285
3288
|
assert_definition_at!(&context, "13:26-13:29", ConstantVisibility, |def| {
|
|
3286
|
-
|
|
3289
|
+
assert_string_eq!(&context, def.target(), "BAR");
|
|
3290
|
+
assert_name_path_eq!(&context, "Foo", def.receiver().unwrap());
|
|
3287
3291
|
assert_eq!(def.visibility(), &Visibility::Public);
|
|
3288
3292
|
});
|
|
3289
3293
|
assert_definition_at!(&context, "14:25-14:30", ConstantVisibility, |def| {
|
|
3290
|
-
|
|
3294
|
+
assert_string_eq!(&context, def.target(), "BAZ");
|
|
3295
|
+
assert_name_path_eq!(&context, "Foo", def.receiver().unwrap());
|
|
3291
3296
|
assert_eq!(def.visibility(), &Visibility::Public);
|
|
3292
3297
|
});
|
|
3293
3298
|
assert_definition_at!(&context, "17:26-17:29", ConstantVisibility, |def| {
|
|
3294
|
-
|
|
3299
|
+
assert_string_eq!(&context, def.target(), "Qux");
|
|
3300
|
+
assert!(def.receiver().is_none());
|
|
3295
3301
|
assert_eq!(def.visibility(), &Visibility::Private);
|
|
3296
3302
|
});
|
|
3297
3303
|
assert_definition_at!(&context, "20:22-20:25", ConstantVisibility, |def| {
|
|
3298
|
-
|
|
3304
|
+
assert_string_eq!(&context, def.target(), "BAR");
|
|
3305
|
+
assert_name_path_eq!(&context, "Foo", def.receiver().unwrap());
|
|
3299
3306
|
assert_eq!(def.visibility(), &Visibility::Public);
|
|
3300
3307
|
});
|
|
3301
3308
|
}
|
|
@@ -4060,6 +4067,19 @@ mod constant_reference_tests {
|
|
|
4060
4067
|
);
|
|
4061
4068
|
}
|
|
4062
4069
|
|
|
4070
|
+
#[test]
|
|
4071
|
+
fn index_unresolved_constant_references_in_default_values() {
|
|
4072
|
+
let context = index_source({
|
|
4073
|
+
"
|
|
4074
|
+
def foo(a = C1, b = C2::C3); end
|
|
4075
|
+
def bar(a: C4, b: C5::C6); end
|
|
4076
|
+
"
|
|
4077
|
+
});
|
|
4078
|
+
|
|
4079
|
+
assert_no_local_diagnostics!(&context);
|
|
4080
|
+
assert_constant_references_eq!(&context, ["C1", "C2", "C3", "C4", "C5", "C6"]);
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4063
4083
|
#[test]
|
|
4064
4084
|
fn index_constant_path_and_write_visits_value() {
|
|
4065
4085
|
let context = index_source({
|