rubydex 0.1.0.beta7 → 0.1.0.beta8
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/ext/rubydex/declaration.c +42 -0
- data/ext/rubydex/declaration.h +1 -0
- data/ext/rubydex/graph.c +2 -27
- data/ext/rubydex/utils.c +24 -0
- data/ext/rubydex/utils.h +6 -0
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/version.rb +1 -1
- data/rbi/rubydex.rbi +227 -196
- data/rust/rubydex/src/model/declaration.rs +6 -1
- data/rust/rubydex/src/model/graph.rs +18 -8
- data/rust/rubydex/src/resolution.rs +209 -7
- data/rust/rubydex-sys/src/declaration_api.rs +49 -7
- data/rust/rubydex-sys/src/graph_api.rs +3 -3
- data/rust/rubydex-sys/src/reference_api.rs +22 -18
- metadata +6 -6
- data/lib/rubydex/librubydex_sys.dylib +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c07115229a5715e4501adce61eefbb4bfe26694f7945736829230d77e97c65a
|
|
4
|
+
data.tar.gz: 5e845ff2cc4617790785c6cca4f5f67a0cfb02d02d88721062b39fff75e715d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e5103b95c2123cae03d2f40a1e39ef642aee65b47f99416b034a0f40365bf8535a8829794df393274155bf5e548c44a412457e00fdf8701922e08a9926e3b27
|
|
7
|
+
data.tar.gz: 478a4a347f1c95210e69e00c2e609abd6ed1c090bae1a5bf30266ade51efc68eaaa294a3f5371d6890497b5d9a782dc0d42c1009c7440d28a1030753a6a03647
|
data/ext/rubydex/declaration.c
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#include "definition.h"
|
|
3
3
|
#include "graph.h"
|
|
4
4
|
#include "handle.h"
|
|
5
|
+
#include "reference.h"
|
|
5
6
|
#include "rustbindings.h"
|
|
6
7
|
#include "utils.h"
|
|
7
8
|
|
|
@@ -10,6 +11,7 @@ VALUE cNamespace;
|
|
|
10
11
|
VALUE cClass;
|
|
11
12
|
VALUE cModule;
|
|
12
13
|
VALUE cSingletonClass;
|
|
14
|
+
VALUE cTodo;
|
|
13
15
|
VALUE cConstant;
|
|
14
16
|
VALUE cConstantAlias;
|
|
15
17
|
VALUE cMethod;
|
|
@@ -26,6 +28,8 @@ VALUE rdxi_declaration_class_for_kind(CDeclarationKind kind) {
|
|
|
26
28
|
return cModule;
|
|
27
29
|
case CDeclarationKind_SingletonClass:
|
|
28
30
|
return cSingletonClass;
|
|
31
|
+
case CDeclarationKind_Todo:
|
|
32
|
+
return cTodo;
|
|
29
33
|
case CDeclarationKind_Constant:
|
|
30
34
|
return cConstant;
|
|
31
35
|
case CDeclarationKind_ConstantAlias:
|
|
@@ -291,12 +295,49 @@ static VALUE rdxr_declaration_descendants(VALUE self) {
|
|
|
291
295
|
return self;
|
|
292
296
|
}
|
|
293
297
|
|
|
298
|
+
// Size function for the Declaration#references enumerator
|
|
299
|
+
static VALUE declaration_references_size(VALUE self, VALUE _args, VALUE _eobj) {
|
|
300
|
+
HandleData *data;
|
|
301
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
302
|
+
|
|
303
|
+
void *graph;
|
|
304
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
305
|
+
|
|
306
|
+
struct ReferencesIter *iter = rdx_declaration_references_iter_new(graph, data->id);
|
|
307
|
+
size_t len = rdx_references_iter_len(iter);
|
|
308
|
+
rdx_references_iter_free(iter);
|
|
309
|
+
|
|
310
|
+
return SIZET2NUM(len);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Returns an enumerator for all references to this declaration
|
|
314
|
+
//
|
|
315
|
+
// Declaration#references: () -> Enumerator[Reference]
|
|
316
|
+
static VALUE rdxr_declaration_references(VALUE self) {
|
|
317
|
+
if (!rb_block_given_p()) {
|
|
318
|
+
return rb_enumeratorize_with_size(self, rb_str_new2("references"), 0, NULL, declaration_references_size);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
HandleData *data;
|
|
322
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
323
|
+
|
|
324
|
+
void *graph;
|
|
325
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
326
|
+
|
|
327
|
+
void *iter = rdx_declaration_references_iter_new(graph, data->id);
|
|
328
|
+
VALUE args = rb_ary_new_from_args(2, data->graph_obj, ULL2NUM((uintptr_t)iter));
|
|
329
|
+
rb_ensure(rdxi_references_yield, args, rdxi_references_ensure, args);
|
|
330
|
+
|
|
331
|
+
return self;
|
|
332
|
+
}
|
|
333
|
+
|
|
294
334
|
void rdxi_initialize_declaration(VALUE mRubydex) {
|
|
295
335
|
cDeclaration = rb_define_class_under(mRubydex, "Declaration", rb_cObject);
|
|
296
336
|
cNamespace = rb_define_class_under(mRubydex, "Namespace", cDeclaration);
|
|
297
337
|
cClass = rb_define_class_under(mRubydex, "Class", cNamespace);
|
|
298
338
|
cModule = rb_define_class_under(mRubydex, "Module", cNamespace);
|
|
299
339
|
cSingletonClass = rb_define_class_under(mRubydex, "SingletonClass", cNamespace);
|
|
340
|
+
cTodo = rb_define_class_under(mRubydex, "Todo", cNamespace);
|
|
300
341
|
cConstant = rb_define_class_under(mRubydex, "Constant", cDeclaration);
|
|
301
342
|
cConstantAlias = rb_define_class_under(mRubydex, "ConstantAlias", cDeclaration);
|
|
302
343
|
cMethod = rb_define_class_under(mRubydex, "Method", cDeclaration);
|
|
@@ -309,6 +350,7 @@ void rdxi_initialize_declaration(VALUE mRubydex) {
|
|
|
309
350
|
rb_define_method(cDeclaration, "name", rdxr_declaration_name, 0);
|
|
310
351
|
rb_define_method(cDeclaration, "unqualified_name", rdxr_declaration_unqualified_name, 0);
|
|
311
352
|
rb_define_method(cDeclaration, "definitions", rdxr_declaration_definitions, 0);
|
|
353
|
+
rb_define_method(cDeclaration, "references", rdxr_declaration_references, 0);
|
|
312
354
|
rb_define_method(cDeclaration, "owner", rdxr_declaration_owner, 0);
|
|
313
355
|
|
|
314
356
|
// Namespace only methods
|
data/ext/rubydex/declaration.h
CHANGED
data/ext/rubydex/graph.c
CHANGED
|
@@ -228,31 +228,6 @@ static VALUE rdxr_graph_aref(VALUE self, VALUE key) {
|
|
|
228
228
|
return rb_class_new_instance(2, argv, decl_class);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
// Body function for rb_ensure for the reference enumerators
|
|
232
|
-
static VALUE graph_references_yield(VALUE args) {
|
|
233
|
-
VALUE self = rb_ary_entry(args, 0);
|
|
234
|
-
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
235
|
-
|
|
236
|
-
uint64_t id = 0;
|
|
237
|
-
ReferenceKind kind;
|
|
238
|
-
while (rdx_references_iter_next(iter, &id, &kind)) {
|
|
239
|
-
VALUE ref_class = rdxi_reference_class_for_kind(kind);
|
|
240
|
-
VALUE argv[] = {self, ULL2NUM(id)};
|
|
241
|
-
VALUE obj = rb_class_new_instance(2, argv, ref_class);
|
|
242
|
-
rb_yield(obj);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return Qnil;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Ensure function for rb_ensure for the reference enumerators to always free the iterator
|
|
249
|
-
static VALUE graph_references_ensure(VALUE args) {
|
|
250
|
-
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
251
|
-
rdx_references_iter_free(iter);
|
|
252
|
-
|
|
253
|
-
return Qnil;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
231
|
// Size function for the constant_references enumerator
|
|
257
232
|
static VALUE graph_constant_references_size(VALUE self, VALUE _args, VALUE _eobj) {
|
|
258
233
|
void *graph;
|
|
@@ -278,7 +253,7 @@ static VALUE rdxr_graph_constant_references(VALUE self) {
|
|
|
278
253
|
|
|
279
254
|
void *iter = rdx_graph_constant_references_iter_new(graph);
|
|
280
255
|
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
|
|
281
|
-
rb_ensure(
|
|
256
|
+
rb_ensure(rdxi_references_yield, args, rdxi_references_ensure, args);
|
|
282
257
|
|
|
283
258
|
return self;
|
|
284
259
|
}
|
|
@@ -308,7 +283,7 @@ static VALUE rdxr_graph_method_references(VALUE self) {
|
|
|
308
283
|
|
|
309
284
|
void *iter = rdx_graph_method_references_iter_new(graph);
|
|
310
285
|
VALUE args = rb_ary_new_from_args(2, self, ULL2NUM((uintptr_t)iter));
|
|
311
|
-
rb_ensure(
|
|
286
|
+
rb_ensure(rdxi_references_yield, args, rdxi_references_ensure, args);
|
|
312
287
|
|
|
313
288
|
return self;
|
|
314
289
|
}
|
data/ext/rubydex/utils.c
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "utils.h"
|
|
2
2
|
#include "declaration.h"
|
|
3
|
+
#include "reference.h"
|
|
3
4
|
#include "rustbindings.h"
|
|
4
5
|
|
|
5
6
|
// Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
|
|
@@ -50,3 +51,26 @@ VALUE rdxi_declarations_ensure(VALUE args) {
|
|
|
50
51
|
rdx_graph_declarations_iter_free(iter);
|
|
51
52
|
return Qnil;
|
|
52
53
|
}
|
|
54
|
+
|
|
55
|
+
// Yield body for iterating over references
|
|
56
|
+
VALUE rdxi_references_yield(VALUE args) {
|
|
57
|
+
VALUE graph_obj = rb_ary_entry(args, 0);
|
|
58
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
59
|
+
|
|
60
|
+
CReference cref;
|
|
61
|
+
while (rdx_references_iter_next(iter, &cref)) {
|
|
62
|
+
VALUE ref_class = rdxi_reference_class_for_kind(cref.kind);
|
|
63
|
+
VALUE argv[] = {graph_obj, ULL2NUM(cref.id)};
|
|
64
|
+
VALUE obj = rb_class_new_instance(2, argv, ref_class);
|
|
65
|
+
rb_yield(obj);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return Qnil;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Ensure function for iterating over references to always free the iterator
|
|
72
|
+
VALUE rdxi_references_ensure(VALUE args) {
|
|
73
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
74
|
+
rdx_references_iter_free(iter);
|
|
75
|
+
return Qnil;
|
|
76
|
+
}
|
data/ext/rubydex/utils.h
CHANGED
|
@@ -16,4 +16,10 @@ VALUE rdxi_declarations_yield(VALUE args);
|
|
|
16
16
|
// Ensure function for iterating over declarations to always free the iterator
|
|
17
17
|
VALUE rdxi_declarations_ensure(VALUE args);
|
|
18
18
|
|
|
19
|
+
// Yield body for iterating over references
|
|
20
|
+
VALUE rdxi_references_yield(VALUE args);
|
|
21
|
+
|
|
22
|
+
// Ensure function for iterating over references to always free the iterator
|
|
23
|
+
VALUE rdxi_references_ensure(VALUE args);
|
|
24
|
+
|
|
19
25
|
#endif // RUBYDEX_UTILS_H
|
|
Binary file
|
data/lib/rubydex/version.rb
CHANGED
data/rbi/rubydex.rbi
CHANGED
|
@@ -1,273 +1,304 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# typed: strict
|
|
3
3
|
|
|
4
|
-
module Rubydex
|
|
5
|
-
class Comment
|
|
6
|
-
sig { params(string: String, location: Location).void }
|
|
7
|
-
def initialize(string:, location:); end
|
|
4
|
+
module Rubydex; end
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
class Rubydex::Comment
|
|
7
|
+
sig { params(string: String, location: Rubydex::Location).void }
|
|
8
|
+
def initialize(string:, location:); end
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
10
|
+
sig { returns(Rubydex::Location) }
|
|
11
|
+
def location; end
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
sig { returns(String) }
|
|
14
|
+
def string; end
|
|
15
|
+
end
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
17
|
+
class Rubydex::ConstantReference < Rubydex::Reference
|
|
18
|
+
sig { returns(Rubydex::Location) }
|
|
19
|
+
def location; end
|
|
20
|
+
|
|
21
|
+
sig { returns(String) }
|
|
22
|
+
def name; end
|
|
23
|
+
end
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
class Rubydex::Declaration
|
|
26
|
+
sig { returns(T::Enumerable[Rubydex::Definition]) }
|
|
27
|
+
def definitions; end
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
sig { returns(String) }
|
|
30
|
+
def name; end
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
sig { returns(Rubydex::Declaration) }
|
|
33
|
+
def owner; end
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
sig { returns(T::Enumerable[Rubydex::Reference]) }
|
|
36
|
+
def references; end
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
sig { returns(String) }
|
|
39
|
+
def unqualified_name; end
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
class << self
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def new(*args); end
|
|
42
45
|
end
|
|
46
|
+
end
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
class Rubydex::GlobalVariable < Rubydex::Declaration; end
|
|
49
|
+
class Rubydex::InstanceVariable < Rubydex::Declaration; end
|
|
50
|
+
class Rubydex::Constant < Rubydex::Declaration; end
|
|
51
|
+
class Rubydex::ConstantAlias < Rubydex::Declaration; end
|
|
52
|
+
class Rubydex::ClassVariable < Rubydex::Declaration; end
|
|
53
|
+
class Rubydex::Method < Rubydex::Declaration; end
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
class Rubydex::Namespace < Rubydex::Declaration
|
|
56
|
+
sig { returns(T::Enumerable[Rubydex::Namespace]) }
|
|
57
|
+
def ancestors; end
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
sig { returns(T::Enumerable[Rubydex::Namespace]) }
|
|
60
|
+
def descendants; end
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
sig { params(name: String).returns(T.nilable(Rubydex::Declaration)) }
|
|
63
|
+
def member(name); end
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
sig { params(name: String, only_inherited: T::Boolean).returns(T.nilable(Rubydex::Declaration)) }
|
|
66
|
+
def find_member(name, only_inherited: false); end
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
sig { returns(T.nilable(Rubydex::SingletonClass)) }
|
|
69
|
+
def singleton_class; end
|
|
70
|
+
end
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
class Rubydex::Class < Rubydex::Namespace; end
|
|
73
|
+
class Rubydex::Module < Rubydex::Namespace; end
|
|
74
|
+
class Rubydex::SingletonClass < Rubydex::Namespace; end
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
class Rubydex::Definition
|
|
77
|
+
sig { returns(T::Array[Rubydex::Comment]) }
|
|
78
|
+
def comments; end
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
sig { returns(T::Boolean) }
|
|
81
|
+
def deprecated?; end
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
sig { returns(Rubydex::Location) }
|
|
84
|
+
def location; end
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
sig { returns(String) }
|
|
87
|
+
def name; end
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
sig { returns(T.nilable(Rubydex::Location)) }
|
|
90
|
+
def name_location; end
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
class << self
|
|
93
|
+
private
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
end
|
|
95
|
+
def new(*args); end
|
|
93
96
|
end
|
|
97
|
+
end
|
|
94
98
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
99
|
+
class Rubydex::AttrAccessorDefinition < Rubydex::Definition; end
|
|
100
|
+
class Rubydex::AttrReaderDefinition < Rubydex::Definition; end
|
|
101
|
+
class Rubydex::AttrWriterDefinition < Rubydex::Definition; end
|
|
102
|
+
class Rubydex::ClassDefinition < Rubydex::Definition; end
|
|
103
|
+
class Rubydex::ClassVariableDefinition < Rubydex::Definition; end
|
|
104
|
+
class Rubydex::ConstantAliasDefinition < Rubydex::Definition; end
|
|
105
|
+
class Rubydex::ConstantDefinition < Rubydex::Definition; end
|
|
106
|
+
class Rubydex::GlobalVariableAliasDefinition < Rubydex::Definition; end
|
|
107
|
+
class Rubydex::GlobalVariableDefinition < Rubydex::Definition; end
|
|
108
|
+
class Rubydex::InstanceVariableDefinition < Rubydex::Definition; end
|
|
109
|
+
class Rubydex::MethodAliasDefinition < Rubydex::Definition; end
|
|
110
|
+
class Rubydex::MethodDefinition < Rubydex::Definition; end
|
|
111
|
+
class Rubydex::ModuleDefinition < Rubydex::Definition; end
|
|
112
|
+
class Rubydex::SingletonClassDefinition < Rubydex::Definition; end
|
|
113
|
+
|
|
114
|
+
class Rubydex::Diagnostic
|
|
115
|
+
sig { params(rule: Symbol, message: String, location: Rubydex::Location).void }
|
|
116
|
+
def initialize(rule:, message:, location:); end
|
|
117
|
+
|
|
118
|
+
sig { returns(Rubydex::Location) }
|
|
119
|
+
def location; end
|
|
120
|
+
|
|
121
|
+
sig { returns(String) }
|
|
122
|
+
def message; end
|
|
123
|
+
|
|
124
|
+
sig { returns(Symbol) }
|
|
125
|
+
def rule; end
|
|
126
|
+
end
|
|
123
127
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
class Rubydex::Document
|
|
129
|
+
sig { returns(T::Enumerable[Rubydex::Definition]) }
|
|
130
|
+
def definitions; end
|
|
127
131
|
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
sig { returns(String) }
|
|
133
|
+
def uri; end
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
class << self
|
|
136
|
+
private
|
|
133
137
|
|
|
134
|
-
|
|
135
|
-
end
|
|
138
|
+
def new(*args); end
|
|
136
139
|
end
|
|
140
|
+
end
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
class Rubydex::Error < StandardError; end
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class Graph
|
|
144
|
-
IGNORED_DIRECTORIES = T.let(T.unsafe(nil), T::Array[String])
|
|
144
|
+
class Rubydex::Failure
|
|
145
|
+
sig { params(message: String).void }
|
|
146
|
+
def initialize(message); end
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
sig { returns(String) }
|
|
149
|
+
def message; end
|
|
150
|
+
end
|
|
148
151
|
|
|
149
|
-
|
|
150
|
-
def [](fully_qualified_name); end
|
|
152
|
+
class Rubydex::IntegrityFailure < Rubydex::Failure; end
|
|
151
153
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
class Rubydex::Graph
|
|
155
|
+
IGNORED_DIRECTORIES = T.let(T.unsafe(nil), T::Array[String])
|
|
154
156
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
sig { params(workspace_path: T.nilable(String)).void }
|
|
158
|
+
def initialize(workspace_path: nil); end
|
|
157
159
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
sig { params(fully_qualified_name: String).returns(T.nilable(Rubydex::Declaration)) }
|
|
161
|
+
def [](fully_qualified_name); end
|
|
160
162
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
sig { returns(T::Enumerable[Rubydex::ConstantReference]) }
|
|
164
|
+
def constant_references; end
|
|
163
165
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
sig { returns(T::Enumerable[Rubydex::Declaration]) }
|
|
167
|
+
def declarations; end
|
|
166
168
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
sig { params(uri: String).returns(T.nilable(Rubydex::Document)) }
|
|
170
|
+
def delete_document(uri); end
|
|
169
171
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
sig { returns(T::Array[Rubydex::Diagnostic]) }
|
|
173
|
+
def diagnostics; end
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
def index_workspace; end
|
|
175
|
+
sig { returns(T::Enumerable[Rubydex::Document]) }
|
|
176
|
+
def documents; end
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
sig { params(file_paths: T::Array[String]).returns(T::Array[String]) }
|
|
179
|
+
def index_all(file_paths); end
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
sig { params(uri: String, source: String, language_id: String).void }
|
|
182
|
+
def index_source(uri, source, language_id); end
|
|
182
183
|
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
# Index all files and dependencies of the workspace that exists in `@workspace_path`
|
|
185
|
+
sig { returns(T::Array[String]) }
|
|
186
|
+
def index_workspace; end
|
|
185
187
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
sig { returns(T::Enumerable[Rubydex::MethodReference]) }
|
|
189
|
+
def method_references; end
|
|
188
190
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
+
sig { params(load_paths: T::Array[String]).returns(T::Array[String]) }
|
|
192
|
+
def require_paths(load_paths); end
|
|
191
193
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
sig { returns(T.self_type) }
|
|
195
|
+
def resolve; end
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
sig { params(name: String, nesting: T::Array[String]).returns(T.nilable(Rubydex::Declaration)) }
|
|
198
|
+
def resolve_constant(name, nesting); end
|
|
197
199
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
sig { params(require_path: String, load_paths: T::Array[String]).returns(T.nilable(Rubydex::Document)) }
|
|
201
|
+
def resolve_require_path(require_path, load_paths); end
|
|
200
202
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
sig { params(query: String).returns(T::Enumerable[Rubydex::Declaration]) }
|
|
204
|
+
def search(query); end
|
|
203
205
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
sig { params(encoding: String).void }
|
|
207
|
+
def encoding=(encoding); end
|
|
206
208
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
sig { returns(String) }
|
|
210
|
+
def workspace_path; end
|
|
209
211
|
|
|
210
|
-
|
|
212
|
+
sig { params(workspace_path: String).returns(String) }
|
|
213
|
+
def workspace_path=(workspace_path); end
|
|
211
214
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
+
sig { returns(T::Array[String]) }
|
|
216
|
+
def workspace_paths; end
|
|
217
|
+
|
|
218
|
+
sig { returns(T::Array[Rubydex::Failure]) }
|
|
219
|
+
def check_integrity; end
|
|
220
|
+
|
|
221
|
+
private
|
|
222
|
+
|
|
223
|
+
sig { params(paths: T::Array[String]).void }
|
|
224
|
+
def add_core_rbs_definition_paths(paths); end
|
|
225
|
+
|
|
226
|
+
sig { params(paths: T::Array[String]).void }
|
|
227
|
+
def add_workspace_dependency_paths(paths); end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
class Rubydex::DisplayLocation < Rubydex::Location
|
|
231
|
+
sig { returns([String, Integer, Integer, Integer, Integer]) }
|
|
232
|
+
def comparable_values; end
|
|
233
|
+
|
|
234
|
+
sig { returns(Rubydex::DisplayLocation) }
|
|
235
|
+
def to_display; end
|
|
236
|
+
|
|
237
|
+
sig { returns(String) }
|
|
238
|
+
def to_s; end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
class Rubydex::Location
|
|
242
|
+
include ::Comparable
|
|
243
|
+
|
|
244
|
+
sig do
|
|
245
|
+
params(
|
|
246
|
+
uri: String,
|
|
247
|
+
start_line: Integer,
|
|
248
|
+
end_line: Integer,
|
|
249
|
+
start_column: Integer,
|
|
250
|
+
end_column: Integer,
|
|
251
|
+
).void
|
|
215
252
|
end
|
|
253
|
+
def initialize(uri:, start_line:, end_line:, start_column:, end_column:); end
|
|
216
254
|
|
|
217
|
-
|
|
218
|
-
|
|
255
|
+
sig { params(other: T.untyped).returns(T.nilable(Integer)) }
|
|
256
|
+
def <=>(other); end
|
|
219
257
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
uri: String,
|
|
223
|
-
start_line: Integer,
|
|
224
|
-
end_line: Integer,
|
|
225
|
-
start_column: Integer,
|
|
226
|
-
end_column: Integer,
|
|
227
|
-
).void
|
|
228
|
-
end
|
|
229
|
-
def initialize(uri:, start_line:, end_line:, start_column:, end_column:); end
|
|
258
|
+
sig { returns([String, Integer, Integer, Integer, Integer]) }
|
|
259
|
+
def comparable_values; end
|
|
230
260
|
|
|
231
|
-
|
|
232
|
-
|
|
261
|
+
sig { returns(Integer) }
|
|
262
|
+
def end_column; end
|
|
233
263
|
|
|
234
|
-
|
|
235
|
-
|
|
264
|
+
sig { returns(Integer) }
|
|
265
|
+
def end_line; end
|
|
236
266
|
|
|
237
|
-
|
|
238
|
-
|
|
267
|
+
sig { returns(String) }
|
|
268
|
+
def to_file_path; end
|
|
239
269
|
|
|
240
|
-
|
|
241
|
-
|
|
270
|
+
sig { returns(Integer) }
|
|
271
|
+
def start_column; end
|
|
242
272
|
|
|
243
|
-
|
|
244
|
-
|
|
273
|
+
sig { returns(Integer) }
|
|
274
|
+
def start_line; end
|
|
245
275
|
|
|
246
|
-
|
|
247
|
-
|
|
276
|
+
sig { returns(Rubydex::DisplayLocation) }
|
|
277
|
+
def to_display; end
|
|
248
278
|
|
|
249
|
-
|
|
250
|
-
|
|
279
|
+
sig { returns(String) }
|
|
280
|
+
def to_s; end
|
|
251
281
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
end
|
|
282
|
+
sig { returns(String) }
|
|
283
|
+
def uri; end
|
|
255
284
|
|
|
256
|
-
class
|
|
257
|
-
|
|
258
|
-
def location; end
|
|
285
|
+
class NotFileUriError < StandardError; end
|
|
286
|
+
end
|
|
259
287
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
end
|
|
288
|
+
class Rubydex::MethodReference < Rubydex::Reference
|
|
289
|
+
sig { returns(Rubydex::Location) }
|
|
290
|
+
def location; end
|
|
263
291
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
292
|
+
sig { returns(String) }
|
|
293
|
+
def name; end
|
|
294
|
+
end
|
|
267
295
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
296
|
+
class Rubydex::Reference
|
|
297
|
+
class << self
|
|
298
|
+
private
|
|
271
299
|
|
|
272
|
-
|
|
300
|
+
def new(*args); end
|
|
301
|
+
end
|
|
273
302
|
end
|
|
303
|
+
|
|
304
|
+
Rubydex::VERSION = T.let(T.unsafe(nil), String)
|
|
@@ -60,6 +60,7 @@ macro_rules! all_declarations {
|
|
|
60
60
|
Declaration::Namespace(Namespace::Class($var)) => $expr,
|
|
61
61
|
Declaration::Namespace(Namespace::Module($var)) => $expr,
|
|
62
62
|
Declaration::Namespace(Namespace::SingletonClass($var)) => $expr,
|
|
63
|
+
Declaration::Namespace(Namespace::Todo($var)) => $expr,
|
|
63
64
|
Declaration::Constant($var) => $expr,
|
|
64
65
|
Declaration::ConstantAlias($var) => $expr,
|
|
65
66
|
Declaration::Method($var) => $expr,
|
|
@@ -76,6 +77,7 @@ macro_rules! all_namespaces {
|
|
|
76
77
|
Namespace::Class($var) => $expr,
|
|
77
78
|
Namespace::Module($var) => $expr,
|
|
78
79
|
Namespace::SingletonClass($var) => $expr,
|
|
80
|
+
Namespace::Todo($var) => $expr,
|
|
79
81
|
}
|
|
80
82
|
};
|
|
81
83
|
}
|
|
@@ -378,6 +380,7 @@ pub enum Namespace {
|
|
|
378
380
|
Class(Box<ClassDeclaration>),
|
|
379
381
|
SingletonClass(Box<SingletonClassDeclaration>),
|
|
380
382
|
Module(Box<ModuleDeclaration>),
|
|
383
|
+
Todo(Box<TodoDeclaration>),
|
|
381
384
|
}
|
|
382
385
|
assert_mem_size!(Namespace, 16);
|
|
383
386
|
|
|
@@ -388,6 +391,7 @@ impl Namespace {
|
|
|
388
391
|
Namespace::Class(_) => "Class",
|
|
389
392
|
Namespace::SingletonClass(_) => "SingletonClass",
|
|
390
393
|
Namespace::Module(_) => "Module",
|
|
394
|
+
Namespace::Todo(_) => "<TODO>",
|
|
391
395
|
}
|
|
392
396
|
}
|
|
393
397
|
|
|
@@ -504,7 +508,8 @@ namespace_declaration!(Module, ModuleDeclaration);
|
|
|
504
508
|
assert_mem_size!(ModuleDeclaration, 224);
|
|
505
509
|
namespace_declaration!(SingletonClass, SingletonClassDeclaration);
|
|
506
510
|
assert_mem_size!(SingletonClassDeclaration, 224);
|
|
507
|
-
|
|
511
|
+
namespace_declaration!(Todo, TodoDeclaration);
|
|
512
|
+
assert_mem_size!(TodoDeclaration, 224);
|
|
508
513
|
simple_declaration!(ConstantDeclaration);
|
|
509
514
|
assert_mem_size!(ConstantDeclaration, 112);
|
|
510
515
|
simple_declaration!(MethodDeclaration);
|
|
@@ -84,14 +84,20 @@ impl Graph {
|
|
|
84
84
|
{
|
|
85
85
|
let declaration_id = DeclarationId::from(&fully_qualified_name);
|
|
86
86
|
|
|
87
|
-
let
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
let is_namespace_definition = matches!(
|
|
88
|
+
self.definitions.get(&definition_id),
|
|
89
|
+
Some(Definition::Class(_) | Definition::Module(_) | Definition::SingletonClass(_))
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
let should_promote = is_namespace_definition
|
|
93
|
+
&& self
|
|
94
|
+
.declarations
|
|
95
|
+
.get(&declaration_id)
|
|
96
|
+
.is_some_and(|existing| match existing {
|
|
97
|
+
Declaration::Constant(_) => self.all_definitions_promotable(existing),
|
|
98
|
+
Declaration::Namespace(Namespace::Todo(_)) => true,
|
|
99
|
+
_ => false,
|
|
100
|
+
});
|
|
95
101
|
|
|
96
102
|
match self.declarations.entry(declaration_id) {
|
|
97
103
|
Entry::Occupied(mut occupied_entry) => {
|
|
@@ -633,6 +639,10 @@ impl Graph {
|
|
|
633
639
|
Declaration::Namespace(Namespace::SingletonClass(it)) => {
|
|
634
640
|
it.add_member(member_str_id, member_declaration_id);
|
|
635
641
|
}
|
|
642
|
+
Declaration::Namespace(Namespace::Todo(it)) => it.add_member(member_str_id, member_declaration_id),
|
|
643
|
+
Declaration::Constant(_) => {
|
|
644
|
+
// TODO: temporary hack to avoid crashing on `Struct.new`, `Class.new` and `Module.new`
|
|
645
|
+
}
|
|
636
646
|
_ => panic!("Tried to add member to a declaration that isn't a namespace"),
|
|
637
647
|
}
|
|
638
648
|
}
|
|
@@ -7,7 +7,7 @@ use crate::model::{
|
|
|
7
7
|
declaration::{
|
|
8
8
|
Ancestor, Ancestors, ClassDeclaration, ClassVariableDeclaration, ConstantAliasDeclaration, ConstantDeclaration,
|
|
9
9
|
Declaration, GlobalVariableDeclaration, InstanceVariableDeclaration, MethodDeclaration, ModuleDeclaration,
|
|
10
|
-
Namespace, SingletonClassDeclaration,
|
|
10
|
+
Namespace, SingletonClassDeclaration, TodoDeclaration,
|
|
11
11
|
},
|
|
12
12
|
definitions::{Definition, Mixin, Receiver},
|
|
13
13
|
graph::{CLASS_ID, Graph, MODULE_ID, OBJECT_ID},
|
|
@@ -1057,12 +1057,60 @@ impl<'a> Resolver<'a> {
|
|
|
1057
1057
|
fn name_owner_id(&mut self, name_id: NameId) -> Outcome {
|
|
1058
1058
|
let name_ref = self.graph.names().get(&name_id).unwrap();
|
|
1059
1059
|
|
|
1060
|
-
if let Some(parent_scope) = name_ref.parent_scope().as_ref() {
|
|
1060
|
+
if let Some(&parent_scope) = name_ref.parent_scope().as_ref() {
|
|
1061
1061
|
// If we have `A::B`, the owner of `B` is whatever `A` resolves to.
|
|
1062
1062
|
// If `A` is an alias, resolve through to get the actual namespace.
|
|
1063
|
-
|
|
1063
|
+
// On `Retry`, we don't create a Todo: the parent may still resolve through inheritance once ancestors are
|
|
1064
|
+
// linearized. We only create Todos for `Unresolved` outcomes where the parent is genuinely unknown.
|
|
1065
|
+
match self.resolve_constant_internal(parent_scope) {
|
|
1064
1066
|
Outcome::Resolved(id, linearization) => self.resolve_to_primary_namespace(id, linearization),
|
|
1065
|
-
|
|
1067
|
+
// Retry or Unresolved(Some(_)) means we might find it later through ancestor linearization
|
|
1068
|
+
Outcome::Retry(id) => Outcome::Retry(id),
|
|
1069
|
+
Outcome::Unresolved(Some(id)) => Outcome::Unresolved(Some(id)),
|
|
1070
|
+
// Only create a Todo when genuinely unresolvable (no pending linearizations)
|
|
1071
|
+
Outcome::Unresolved(None) => {
|
|
1072
|
+
let parent_name = self.graph.names().get(&parent_scope).unwrap();
|
|
1073
|
+
let parent_str_id = *parent_name.str();
|
|
1074
|
+
let parent_has_explicit_prefix = parent_name.parent_scope().as_ref().is_some();
|
|
1075
|
+
// NLL: borrow of parent_name ends here
|
|
1076
|
+
|
|
1077
|
+
// For bare names (no explicit `::` prefix), always use OBJECT_ID as the owner.
|
|
1078
|
+
// Using nesting here would create "Nesting::Bar" instead of "Bar" for a bare `Bar`
|
|
1079
|
+
// reference, which is incorrect: if `Bar` can't be found anywhere, the placeholder
|
|
1080
|
+
// should live at the top level so it can be promoted when `module Bar` appears later.
|
|
1081
|
+
let parent_owner_id = if parent_has_explicit_prefix {
|
|
1082
|
+
match self.name_owner_id(parent_scope) {
|
|
1083
|
+
Outcome::Resolved(id, _) => id,
|
|
1084
|
+
_ => *OBJECT_ID,
|
|
1085
|
+
}
|
|
1086
|
+
} else {
|
|
1087
|
+
*OBJECT_ID
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
let fully_qualified_name = if parent_owner_id == *OBJECT_ID {
|
|
1091
|
+
self.graph.strings().get(&parent_str_id).unwrap().to_string()
|
|
1092
|
+
} else {
|
|
1093
|
+
format!(
|
|
1094
|
+
"{}::{}",
|
|
1095
|
+
self.graph.declarations().get(&parent_owner_id).unwrap().name(),
|
|
1096
|
+
self.graph.strings().get(&parent_str_id).unwrap().as_str()
|
|
1097
|
+
)
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
let declaration_id = DeclarationId::from(&fully_qualified_name);
|
|
1101
|
+
|
|
1102
|
+
if let std::collections::hash_map::Entry::Vacant(e) =
|
|
1103
|
+
self.graph.declarations_mut().entry(declaration_id)
|
|
1104
|
+
{
|
|
1105
|
+
e.insert(Declaration::Namespace(Namespace::Todo(Box::new(TodoDeclaration::new(
|
|
1106
|
+
fully_qualified_name,
|
|
1107
|
+
parent_owner_id,
|
|
1108
|
+
)))));
|
|
1109
|
+
self.graph.add_member(&parent_owner_id, declaration_id, parent_str_id);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
Outcome::Resolved(declaration_id, None)
|
|
1113
|
+
}
|
|
1066
1114
|
}
|
|
1067
1115
|
} else if let Some(nesting_id) = name_ref.nesting()
|
|
1068
1116
|
&& !name_ref.parent_scope().is_top_level()
|
|
@@ -1916,9 +1964,12 @@ mod tests {
|
|
|
1916
1964
|
|
|
1917
1965
|
assert_no_diagnostics!(&context);
|
|
1918
1966
|
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1967
|
+
assert_declaration_kind_eq!(context, "Foo", "<TODO>");
|
|
1968
|
+
|
|
1969
|
+
assert_members_eq!(context, "Object", vec!["Foo"]);
|
|
1970
|
+
assert_members_eq!(context, "Foo", vec!["Bar"]);
|
|
1971
|
+
assert_members_eq!(context, "Foo::Bar", vec!["Baz"]);
|
|
1972
|
+
assert_no_members!(context, "Foo::Bar::Baz");
|
|
1922
1973
|
}
|
|
1923
1974
|
|
|
1924
1975
|
#[test]
|
|
@@ -5194,6 +5245,9 @@ mod tests {
|
|
|
5194
5245
|
def initialize
|
|
5195
5246
|
@instance_ivar = 456
|
|
5196
5247
|
end
|
|
5248
|
+
|
|
5249
|
+
def bar; end
|
|
5250
|
+
alias new_bar bar
|
|
5197
5251
|
end
|
|
5198
5252
|
"
|
|
5199
5253
|
});
|
|
@@ -5206,6 +5260,7 @@ mod tests {
|
|
|
5206
5260
|
assert_declaration_exists!(context, "Foo#some_attr()");
|
|
5207
5261
|
assert_declaration_exists!(context, "Foo::<Foo>#class_method()");
|
|
5208
5262
|
assert_declaration_exists!(context, "Foo#initialize()");
|
|
5263
|
+
assert_declaration_exists!(context, "Foo#new_bar()");
|
|
5209
5264
|
}
|
|
5210
5265
|
|
|
5211
5266
|
#[test]
|
|
@@ -5261,4 +5316,151 @@ mod tests {
|
|
|
5261
5316
|
assert_declaration_does_not_exist!(context, "Foo::<Foo>");
|
|
5262
5317
|
assert_declaration_does_not_exist!(context, "Foo::<Foo>#bar()");
|
|
5263
5318
|
}
|
|
5319
|
+
|
|
5320
|
+
#[test]
|
|
5321
|
+
fn resolve_missing_declaration_to_todo() {
|
|
5322
|
+
let mut context = GraphTest::new();
|
|
5323
|
+
context.index_uri("file:///foo.rb", {
|
|
5324
|
+
r"
|
|
5325
|
+
class Foo::Bar
|
|
5326
|
+
include Foo::Baz
|
|
5327
|
+
|
|
5328
|
+
def bar; end
|
|
5329
|
+
end
|
|
5330
|
+
|
|
5331
|
+
module Foo::Baz
|
|
5332
|
+
def baz; end
|
|
5333
|
+
end
|
|
5334
|
+
"
|
|
5335
|
+
});
|
|
5336
|
+
context.resolve();
|
|
5337
|
+
|
|
5338
|
+
assert_no_diagnostics!(&context);
|
|
5339
|
+
|
|
5340
|
+
assert_declaration_kind_eq!(context, "Foo", "<TODO>");
|
|
5341
|
+
|
|
5342
|
+
assert_members_eq!(context, "Object", vec!["Foo"]);
|
|
5343
|
+
assert_members_eq!(context, "Foo", vec!["Bar", "Baz"]);
|
|
5344
|
+
assert_members_eq!(context, "Foo::Bar", vec!["bar()"]);
|
|
5345
|
+
assert_members_eq!(context, "Foo::Baz", vec!["baz()"]);
|
|
5346
|
+
}
|
|
5347
|
+
|
|
5348
|
+
#[test]
|
|
5349
|
+
fn todo_declaration_promoted_to_real_namespace() {
|
|
5350
|
+
let mut context = GraphTest::new();
|
|
5351
|
+
context.index_uri("file:///foo.rb", {
|
|
5352
|
+
r"
|
|
5353
|
+
class Foo::Bar
|
|
5354
|
+
def bar; end
|
|
5355
|
+
end
|
|
5356
|
+
|
|
5357
|
+
class Foo
|
|
5358
|
+
def foo; end
|
|
5359
|
+
end
|
|
5360
|
+
"
|
|
5361
|
+
});
|
|
5362
|
+
context.resolve();
|
|
5363
|
+
|
|
5364
|
+
assert_no_diagnostics!(&context);
|
|
5365
|
+
|
|
5366
|
+
// Foo was initially created as a Todo (from class Foo::Bar), then promoted to Class
|
|
5367
|
+
assert_declaration_kind_eq!(context, "Foo", "Class");
|
|
5368
|
+
|
|
5369
|
+
assert_members_eq!(context, "Object", vec!["Foo"]);
|
|
5370
|
+
assert_members_eq!(context, "Foo", vec!["Bar", "foo()"]);
|
|
5371
|
+
assert_members_eq!(context, "Foo::Bar", vec!["bar()"]);
|
|
5372
|
+
}
|
|
5373
|
+
|
|
5374
|
+
#[test]
|
|
5375
|
+
fn todo_declaration_promoted_to_real_namespace_incrementally() {
|
|
5376
|
+
let mut context = GraphTest::new();
|
|
5377
|
+
context.index_uri("file:///bar.rb", {
|
|
5378
|
+
r"
|
|
5379
|
+
class Foo::Bar
|
|
5380
|
+
def bar; end
|
|
5381
|
+
end
|
|
5382
|
+
"
|
|
5383
|
+
});
|
|
5384
|
+
context.resolve();
|
|
5385
|
+
|
|
5386
|
+
assert_no_diagnostics!(&context);
|
|
5387
|
+
assert_declaration_kind_eq!(context, "Foo", "<TODO>");
|
|
5388
|
+
|
|
5389
|
+
context.index_uri("file:///foo.rb", {
|
|
5390
|
+
r"
|
|
5391
|
+
class Foo
|
|
5392
|
+
def foo; end
|
|
5393
|
+
end
|
|
5394
|
+
"
|
|
5395
|
+
});
|
|
5396
|
+
context.resolve();
|
|
5397
|
+
|
|
5398
|
+
assert_no_diagnostics!(&context);
|
|
5399
|
+
|
|
5400
|
+
// Foo was promoted from Todo to Class after the second resolution
|
|
5401
|
+
assert_declaration_kind_eq!(context, "Foo", "Class");
|
|
5402
|
+
|
|
5403
|
+
assert_members_eq!(context, "Object", vec!["Foo"]);
|
|
5404
|
+
assert_members_eq!(context, "Foo", vec!["Bar", "foo()"]);
|
|
5405
|
+
assert_members_eq!(context, "Foo::Bar", vec!["bar()"]);
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
#[test]
|
|
5409
|
+
fn qualified_name_inside_nesting_resolves_to_top_level() {
|
|
5410
|
+
let mut context = GraphTest::new();
|
|
5411
|
+
context.index_uri("file:///foo.rb", {
|
|
5412
|
+
r"
|
|
5413
|
+
module Foo
|
|
5414
|
+
class Bar::Baz
|
|
5415
|
+
def qux; end
|
|
5416
|
+
end
|
|
5417
|
+
end
|
|
5418
|
+
|
|
5419
|
+
module Bar
|
|
5420
|
+
end
|
|
5421
|
+
"
|
|
5422
|
+
});
|
|
5423
|
+
context.resolve();
|
|
5424
|
+
|
|
5425
|
+
assert_no_diagnostics!(&context);
|
|
5426
|
+
assert_declaration_kind_eq!(context, "Bar", "Module");
|
|
5427
|
+
assert_members_eq!(context, "Bar", vec!["Baz"]);
|
|
5428
|
+
assert_declaration_exists!(context, "Bar::Baz");
|
|
5429
|
+
assert_members_eq!(context, "Bar::Baz", vec!["qux()"]);
|
|
5430
|
+
assert_declaration_does_not_exist!(context, "Foo::Bar");
|
|
5431
|
+
}
|
|
5432
|
+
|
|
5433
|
+
#[test]
|
|
5434
|
+
fn qualified_name_inside_nesting_resolves_when_discovered_incrementally() {
|
|
5435
|
+
let mut context = GraphTest::new();
|
|
5436
|
+
context.index_uri("file:///baz.rb", {
|
|
5437
|
+
r"
|
|
5438
|
+
module Foo
|
|
5439
|
+
class Bar::Baz
|
|
5440
|
+
def qux; end
|
|
5441
|
+
end
|
|
5442
|
+
end
|
|
5443
|
+
"
|
|
5444
|
+
});
|
|
5445
|
+
context.resolve();
|
|
5446
|
+
|
|
5447
|
+
// Bar is unknown — a Todo is created at the top level, not "Foo::Bar"
|
|
5448
|
+
assert_declaration_kind_eq!(context, "Bar", "<TODO>");
|
|
5449
|
+
assert_declaration_does_not_exist!(context, "Foo::Bar");
|
|
5450
|
+
|
|
5451
|
+
context.index_uri("file:///bar.rb", {
|
|
5452
|
+
r"
|
|
5453
|
+
module Bar
|
|
5454
|
+
end
|
|
5455
|
+
"
|
|
5456
|
+
});
|
|
5457
|
+
context.resolve();
|
|
5458
|
+
|
|
5459
|
+
// After discovering top-level Bar, the Todo should be promoted and Baz re-homed.
|
|
5460
|
+
assert_no_diagnostics!(&context);
|
|
5461
|
+
assert_declaration_kind_eq!(context, "Bar", "Module");
|
|
5462
|
+
assert_members_eq!(context, "Bar", vec!["Baz"]);
|
|
5463
|
+
assert_members_eq!(context, "Bar::Baz", vec!["qux()"]);
|
|
5464
|
+
assert_declaration_does_not_exist!(context, "Foo::Bar");
|
|
5465
|
+
}
|
|
5264
5466
|
}
|
|
@@ -7,6 +7,7 @@ use std::ptr;
|
|
|
7
7
|
|
|
8
8
|
use crate::definition_api::{DefinitionsIter, rdx_definitions_iter_new_from_ids};
|
|
9
9
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
10
|
+
use crate::reference_api::{CReference, ReferenceKind, ReferencesIter};
|
|
10
11
|
use crate::utils;
|
|
11
12
|
use rubydex::model::ids::{DeclarationId, StringId};
|
|
12
13
|
|
|
@@ -22,6 +23,7 @@ pub enum CDeclarationKind {
|
|
|
22
23
|
GlobalVariable = 6,
|
|
23
24
|
InstanceVariable = 7,
|
|
24
25
|
ClassVariable = 8,
|
|
26
|
+
Todo = 9,
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
#[repr(C)]
|
|
@@ -51,6 +53,7 @@ impl CDeclaration {
|
|
|
51
53
|
Declaration::Namespace(Namespace::Class(_)) => CDeclarationKind::Class,
|
|
52
54
|
Declaration::Namespace(Namespace::Module(_)) => CDeclarationKind::Module,
|
|
53
55
|
Declaration::Namespace(Namespace::SingletonClass(_)) => CDeclarationKind::SingletonClass,
|
|
56
|
+
Declaration::Namespace(Namespace::Todo(_)) => CDeclarationKind::Todo,
|
|
54
57
|
Declaration::Constant(_) => CDeclarationKind::Constant,
|
|
55
58
|
Declaration::ConstantAlias(_) => CDeclarationKind::ConstantAlias,
|
|
56
59
|
Declaration::Method(_) => CDeclarationKind::Method,
|
|
@@ -194,13 +197,15 @@ pub unsafe extern "C" fn rdx_declaration_find_member(
|
|
|
194
197
|
.iter()
|
|
195
198
|
.find_map(|ancestor| match ancestor {
|
|
196
199
|
Ancestor::Complete(ancestor_id) => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
// When only_inherited, skip self and prepended modules
|
|
201
|
+
if only_inherited {
|
|
202
|
+
let is_self = *ancestor_id == id;
|
|
203
|
+
if is_self {
|
|
204
|
+
found_main_namespace = true;
|
|
205
|
+
}
|
|
206
|
+
if is_self || !found_main_namespace {
|
|
207
|
+
return None;
|
|
208
|
+
}
|
|
204
209
|
}
|
|
205
210
|
|
|
206
211
|
let ancestor_decl = graph.declarations().get(ancestor_id).unwrap().as_namespace().unwrap();
|
|
@@ -397,3 +402,40 @@ pub unsafe extern "C" fn rdx_declaration_descendants(pointer: GraphPointer, decl
|
|
|
397
402
|
|
|
398
403
|
Box::into_raw(Box::new(DeclarationsIter::new(declarations.into_boxed_slice())))
|
|
399
404
|
}
|
|
405
|
+
|
|
406
|
+
/// Creates a new iterator over references for a given declaration by snapshotting the current set of IDs.
|
|
407
|
+
///
|
|
408
|
+
/// # Safety
|
|
409
|
+
///
|
|
410
|
+
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
411
|
+
/// - The returned pointer must be freed with `rdx_references_iter_free`.
|
|
412
|
+
#[unsafe(no_mangle)]
|
|
413
|
+
pub unsafe extern "C" fn rdx_declaration_references_iter_new(
|
|
414
|
+
pointer: GraphPointer,
|
|
415
|
+
decl_id: u64,
|
|
416
|
+
) -> *mut ReferencesIter {
|
|
417
|
+
with_graph(pointer, |graph| {
|
|
418
|
+
let decl_id = DeclarationId::new(decl_id);
|
|
419
|
+
|
|
420
|
+
let Some(decl) = graph.declarations().get(&decl_id) else {
|
|
421
|
+
return ReferencesIter::new(Vec::new().into_boxed_slice());
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
let kind = match decl {
|
|
425
|
+
Declaration::Namespace(_) | Declaration::Constant(_) | Declaration::ConstantAlias(_) => {
|
|
426
|
+
ReferenceKind::Constant
|
|
427
|
+
}
|
|
428
|
+
Declaration::Method(_) => ReferenceKind::Method,
|
|
429
|
+
Declaration::GlobalVariable(_) | Declaration::InstanceVariable(_) | Declaration::ClassVariable(_) => {
|
|
430
|
+
return ReferencesIter::new(Vec::new().into_boxed_slice());
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
let entries: Vec<_> = decl
|
|
435
|
+
.references()
|
|
436
|
+
.iter()
|
|
437
|
+
.map(|ref_id| CReference::new(**ref_id, kind))
|
|
438
|
+
.collect();
|
|
439
|
+
ReferencesIter::new(entries.into_boxed_slice())
|
|
440
|
+
})
|
|
441
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
use crate::declaration_api::CDeclaration;
|
|
4
4
|
use crate::declaration_api::DeclarationsIter;
|
|
5
|
-
use crate::reference_api::{ReferenceKind, ReferencesIter};
|
|
5
|
+
use crate::reference_api::{CReference, ReferenceKind, ReferencesIter};
|
|
6
6
|
use crate::{name_api, utils};
|
|
7
7
|
use libc::{c_char, c_void};
|
|
8
8
|
use rubydex::indexing::LanguageId;
|
|
@@ -452,7 +452,7 @@ pub unsafe extern "C" fn rdx_graph_constant_references_iter_new(pointer: GraphPo
|
|
|
452
452
|
let refs: Vec<_> = graph
|
|
453
453
|
.constant_references()
|
|
454
454
|
.keys()
|
|
455
|
-
.map(|id| (**id, ReferenceKind::Constant))
|
|
455
|
+
.map(|id| CReference::new(**id, ReferenceKind::Constant))
|
|
456
456
|
.collect();
|
|
457
457
|
|
|
458
458
|
ReferencesIter::new(refs.into_boxed_slice())
|
|
@@ -469,7 +469,7 @@ pub unsafe extern "C" fn rdx_graph_method_references_iter_new(pointer: GraphPoin
|
|
|
469
469
|
let refs: Vec<_> = graph
|
|
470
470
|
.method_references()
|
|
471
471
|
.keys()
|
|
472
|
-
.map(|id| (**id, ReferenceKind::Method))
|
|
472
|
+
.map(|id| CReference::new(**id, ReferenceKind::Method))
|
|
473
473
|
.collect();
|
|
474
474
|
|
|
475
475
|
ReferencesIter::new(refs.into_boxed_slice())
|
|
@@ -15,16 +15,29 @@ pub enum ReferenceKind {
|
|
|
15
15
|
Method = 1,
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
#[repr(C)]
|
|
19
|
+
#[derive(Debug, Clone, Copy)]
|
|
20
|
+
pub struct CReference {
|
|
21
|
+
id: u64,
|
|
22
|
+
kind: ReferenceKind,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl CReference {
|
|
26
|
+
#[must_use]
|
|
27
|
+
pub fn new(id: u64, kind: ReferenceKind) -> Self {
|
|
28
|
+
Self { id, kind }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
#[derive(Debug)]
|
|
20
33
|
pub struct ReferencesIter {
|
|
21
|
-
pub entries: Box<[
|
|
34
|
+
pub entries: Box<[CReference]>,
|
|
22
35
|
pub index: usize,
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
impl ReferencesIter {
|
|
26
39
|
#[must_use]
|
|
27
|
-
pub fn new(entries: Box<[
|
|
40
|
+
pub fn new(entries: Box<[CReference]>) -> *mut ReferencesIter {
|
|
28
41
|
Box::into_raw(Box::new(ReferencesIter { entries, index: 0 }))
|
|
29
42
|
}
|
|
30
43
|
}
|
|
@@ -41,23 +54,15 @@ pub unsafe extern "C" fn rdx_references_iter_len(iter: *const ReferencesIter) ->
|
|
|
41
54
|
unsafe { (&*iter).entries.len() }
|
|
42
55
|
}
|
|
43
56
|
|
|
44
|
-
/// Advances the iterator and writes the next entry into
|
|
57
|
+
/// Advances the iterator and writes the next entry into `out_ref`.
|
|
45
58
|
/// Returns `true` if an entry was written, or `false` if the iterator is exhausted or inputs are invalid.
|
|
46
59
|
///
|
|
47
60
|
/// # Safety
|
|
48
61
|
/// - `iter` must be a valid pointer previously returned by `ReferencesIter::new`.
|
|
49
|
-
/// - `
|
|
50
|
-
///
|
|
51
|
-
/// # Panics
|
|
52
|
-
/// - If the iterator is exhausted or inputs are invalid.
|
|
53
|
-
/// - If the name, URI, start, or end pointers are invalid.
|
|
62
|
+
/// - `out_ref` must be a valid, writable pointer.
|
|
54
63
|
#[unsafe(no_mangle)]
|
|
55
|
-
pub unsafe extern "C" fn rdx_references_iter_next(
|
|
56
|
-
iter
|
|
57
|
-
out_id: *mut u64,
|
|
58
|
-
out_kind: *mut ReferenceKind,
|
|
59
|
-
) -> bool {
|
|
60
|
-
if iter.is_null() || out_id.is_null() || out_kind.is_null() {
|
|
64
|
+
pub unsafe extern "C" fn rdx_references_iter_next(iter: *mut ReferencesIter, out_ref: *mut CReference) -> bool {
|
|
65
|
+
if iter.is_null() || out_ref.is_null() {
|
|
61
66
|
return false;
|
|
62
67
|
}
|
|
63
68
|
|
|
@@ -66,11 +71,10 @@ pub unsafe extern "C" fn rdx_references_iter_next(
|
|
|
66
71
|
return false;
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
let
|
|
74
|
+
let entry = it.entries[it.index];
|
|
70
75
|
it.index += 1;
|
|
71
76
|
unsafe {
|
|
72
|
-
*
|
|
73
|
-
*out_kind = kind;
|
|
77
|
+
*out_ref = entry;
|
|
74
78
|
}
|
|
75
79
|
true
|
|
76
80
|
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubydex
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.0.
|
|
4
|
+
version: 0.1.0.beta8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A high performance static analysis suite for Ruby, built in Rust with
|
|
14
14
|
Ruby APIs
|
|
@@ -48,7 +48,7 @@ files:
|
|
|
48
48
|
- lib/rubydex/diagnostic.rb
|
|
49
49
|
- lib/rubydex/failures.rb
|
|
50
50
|
- lib/rubydex/graph.rb
|
|
51
|
-
- lib/rubydex/librubydex_sys.
|
|
51
|
+
- lib/rubydex/librubydex_sys.so
|
|
52
52
|
- lib/rubydex/location.rb
|
|
53
53
|
- lib/rubydex/version.rb
|
|
54
54
|
- rbi/rubydex.rbi
|
|
@@ -125,7 +125,7 @@ metadata:
|
|
|
125
125
|
homepage_uri: https://github.com/Shopify/rubydex
|
|
126
126
|
source_code_uri: https://github.com/Shopify/rubydex
|
|
127
127
|
changelog_uri: https://github.com/Shopify/rubydex/releases
|
|
128
|
-
post_install_message:
|
|
128
|
+
post_install_message:
|
|
129
129
|
rdoc_options: []
|
|
130
130
|
require_paths:
|
|
131
131
|
- lib
|
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
141
|
version: 3.3.11
|
|
142
142
|
requirements: []
|
|
143
143
|
rubygems_version: 3.4.19
|
|
144
|
-
signing_key:
|
|
144
|
+
signing_key:
|
|
145
145
|
specification_version: 4
|
|
146
146
|
summary: A high performance static analysis suite for Ruby
|
|
147
147
|
test_files: []
|
|
Binary file
|