rubydex 0.1.0.beta12-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +125 -0
- data/THIRD_PARTY_LICENSES.html +4562 -0
- data/exe/rdx +47 -0
- data/ext/rubydex/declaration.c +453 -0
- data/ext/rubydex/declaration.h +23 -0
- data/ext/rubydex/definition.c +284 -0
- data/ext/rubydex/definition.h +28 -0
- data/ext/rubydex/diagnostic.c +6 -0
- data/ext/rubydex/diagnostic.h +11 -0
- data/ext/rubydex/document.c +97 -0
- data/ext/rubydex/document.h +10 -0
- data/ext/rubydex/extconf.rb +138 -0
- data/ext/rubydex/graph.c +681 -0
- data/ext/rubydex/graph.h +10 -0
- data/ext/rubydex/handle.h +44 -0
- data/ext/rubydex/location.c +22 -0
- data/ext/rubydex/location.h +15 -0
- data/ext/rubydex/reference.c +123 -0
- data/ext/rubydex/reference.h +15 -0
- data/ext/rubydex/rubydex.c +22 -0
- data/ext/rubydex/utils.c +108 -0
- data/ext/rubydex/utils.h +34 -0
- data/lib/rubydex/3.2/rubydex.so +0 -0
- data/lib/rubydex/3.3/rubydex.so +0 -0
- data/lib/rubydex/3.4/rubydex.so +0 -0
- data/lib/rubydex/4.0/rubydex.so +0 -0
- data/lib/rubydex/comment.rb +17 -0
- data/lib/rubydex/diagnostic.rb +21 -0
- data/lib/rubydex/failures.rb +15 -0
- data/lib/rubydex/graph.rb +98 -0
- data/lib/rubydex/keyword.rb +17 -0
- data/lib/rubydex/keyword_parameter.rb +13 -0
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/location.rb +90 -0
- data/lib/rubydex/mixin.rb +22 -0
- data/lib/rubydex/version.rb +5 -0
- data/lib/rubydex.rb +23 -0
- data/rbi/rubydex.rbi +422 -0
- data/rust/Cargo.lock +1851 -0
- data/rust/Cargo.toml +29 -0
- data/rust/about.hbs +78 -0
- data/rust/about.toml +10 -0
- data/rust/rubydex/Cargo.toml +42 -0
- data/rust/rubydex/src/compile_assertions.rs +13 -0
- data/rust/rubydex/src/diagnostic.rs +110 -0
- data/rust/rubydex/src/errors.rs +28 -0
- data/rust/rubydex/src/indexing/local_graph.rs +224 -0
- data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -0
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
- data/rust/rubydex/src/indexing.rs +210 -0
- data/rust/rubydex/src/integrity.rs +279 -0
- data/rust/rubydex/src/job_queue.rs +205 -0
- data/rust/rubydex/src/lib.rs +17 -0
- data/rust/rubydex/src/listing.rs +371 -0
- data/rust/rubydex/src/main.rs +160 -0
- data/rust/rubydex/src/model/built_in.rs +83 -0
- data/rust/rubydex/src/model/comment.rs +24 -0
- data/rust/rubydex/src/model/declaration.rs +671 -0
- data/rust/rubydex/src/model/definitions.rs +1682 -0
- data/rust/rubydex/src/model/document.rs +222 -0
- data/rust/rubydex/src/model/encoding.rs +22 -0
- data/rust/rubydex/src/model/graph.rs +3754 -0
- data/rust/rubydex/src/model/id.rs +110 -0
- data/rust/rubydex/src/model/identity_maps.rs +58 -0
- data/rust/rubydex/src/model/ids.rs +60 -0
- data/rust/rubydex/src/model/keywords.rs +256 -0
- data/rust/rubydex/src/model/name.rs +298 -0
- data/rust/rubydex/src/model/references.rs +111 -0
- data/rust/rubydex/src/model/string_ref.rs +50 -0
- data/rust/rubydex/src/model/visibility.rs +41 -0
- data/rust/rubydex/src/model.rs +15 -0
- data/rust/rubydex/src/offset.rs +147 -0
- data/rust/rubydex/src/position.rs +6 -0
- data/rust/rubydex/src/query.rs +1841 -0
- data/rust/rubydex/src/resolution.rs +6517 -0
- data/rust/rubydex/src/stats/memory.rs +71 -0
- data/rust/rubydex/src/stats/orphan_report.rs +264 -0
- data/rust/rubydex/src/stats/timer.rs +127 -0
- data/rust/rubydex/src/stats.rs +11 -0
- data/rust/rubydex/src/test_utils/context.rs +226 -0
- data/rust/rubydex/src/test_utils/graph_test.rs +730 -0
- data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -0
- data/rust/rubydex/src/test_utils.rs +52 -0
- data/rust/rubydex/src/visualization/dot.rs +192 -0
- data/rust/rubydex/src/visualization.rs +6 -0
- data/rust/rubydex/tests/cli.rs +185 -0
- data/rust/rubydex-mcp/Cargo.toml +28 -0
- data/rust/rubydex-mcp/src/main.rs +48 -0
- data/rust/rubydex-mcp/src/server.rs +1145 -0
- data/rust/rubydex-mcp/src/tools.rs +49 -0
- data/rust/rubydex-mcp/tests/mcp.rs +302 -0
- data/rust/rubydex-sys/Cargo.toml +20 -0
- data/rust/rubydex-sys/build.rs +14 -0
- data/rust/rubydex-sys/cbindgen.toml +12 -0
- data/rust/rubydex-sys/src/declaration_api.rs +485 -0
- data/rust/rubydex-sys/src/definition_api.rs +443 -0
- data/rust/rubydex-sys/src/diagnostic_api.rs +99 -0
- data/rust/rubydex-sys/src/document_api.rs +85 -0
- data/rust/rubydex-sys/src/graph_api.rs +948 -0
- data/rust/rubydex-sys/src/lib.rs +79 -0
- data/rust/rubydex-sys/src/location_api.rs +79 -0
- data/rust/rubydex-sys/src/name_api.rs +135 -0
- data/rust/rubydex-sys/src/reference_api.rs +267 -0
- data/rust/rubydex-sys/src/utils.rs +70 -0
- data/rust/rustfmt.toml +2 -0
- metadata +159 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#ifndef RUBYDEX_HANDLE_H
|
|
2
|
+
#define RUBYDEX_HANDLE_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
|
|
6
|
+
typedef struct {
|
|
7
|
+
VALUE graph_obj; // Ruby Graph object to keep it alive
|
|
8
|
+
uint64_t id; // Canonical ID mapping to a DeclarationId, DefinitionId, UriId, etc. See `ids.rs`.
|
|
9
|
+
} HandleData;
|
|
10
|
+
|
|
11
|
+
static void handle_mark(void *ptr) {
|
|
12
|
+
if (ptr) {
|
|
13
|
+
HandleData *data = (HandleData *)ptr;
|
|
14
|
+
rb_gc_mark(data->graph_obj);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static void handle_free(void *ptr) {
|
|
19
|
+
if (ptr) {
|
|
20
|
+
xfree(ptr);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static const rb_data_type_t handle_type = {
|
|
25
|
+
"RubydexHandle", {handle_mark, handle_free, 0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY};
|
|
26
|
+
|
|
27
|
+
static VALUE rdxr_handle_alloc(VALUE klass) {
|
|
28
|
+
HandleData *data = ALLOC(HandleData);
|
|
29
|
+
data->graph_obj = Qnil;
|
|
30
|
+
data->id = 0;
|
|
31
|
+
|
|
32
|
+
return TypedData_Wrap_Struct(klass, &handle_type, data);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static VALUE rdxr_handle_initialize(VALUE self, VALUE graph_obj, VALUE id_val) {
|
|
36
|
+
HandleData *data;
|
|
37
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
38
|
+
data->graph_obj = graph_obj;
|
|
39
|
+
data->id = NUM2ULL(id_val);
|
|
40
|
+
|
|
41
|
+
return self;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#endif // RUBYDEX_HANDLE_H
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#include "location.h"
|
|
2
|
+
|
|
3
|
+
VALUE cLocation;
|
|
4
|
+
|
|
5
|
+
VALUE rdxi_build_location_value(Location *loc) {
|
|
6
|
+
if (loc == NULL) {
|
|
7
|
+
return Qnil;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
VALUE uri = rb_utf8_str_new_cstr(loc->uri);
|
|
11
|
+
|
|
12
|
+
VALUE kwargs = rb_hash_new_capa(5);
|
|
13
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("uri")), uri);
|
|
14
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("start_line")), UINT2NUM(loc->start_line));
|
|
15
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("end_line")), UINT2NUM(loc->end_line));
|
|
16
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("start_column")), UINT2NUM(loc->start_column));
|
|
17
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("end_column")), UINT2NUM(loc->end_column));
|
|
18
|
+
|
|
19
|
+
return rb_class_new_instance_kw(1, &kwargs, cLocation, RB_PASS_KEYWORDS);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void rdxi_initialize_location(VALUE mRubydex) { cLocation = rb_define_class_under(mRubydex, "Location", rb_cObject); }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifndef RUBYDEX_LOCATION_H
|
|
2
|
+
#define RUBYDEX_LOCATION_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
#include "rustbindings.h"
|
|
6
|
+
|
|
7
|
+
extern VALUE cLocation;
|
|
8
|
+
|
|
9
|
+
void rdxi_initialize_location(VALUE mRubydex);
|
|
10
|
+
|
|
11
|
+
// Helper to build a Ruby Rubydex::Location from a C Location pointer.
|
|
12
|
+
// Does not take ownership; caller remains responsible for freeing the C Location on the Rust side.
|
|
13
|
+
VALUE rdxi_build_location_value(Location *loc);
|
|
14
|
+
|
|
15
|
+
#endif // RUBYDEX_LOCATION_H
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#include "reference.h"
|
|
2
|
+
#include "declaration.h"
|
|
3
|
+
#include "graph.h"
|
|
4
|
+
#include "handle.h"
|
|
5
|
+
#include "location.h"
|
|
6
|
+
#include "rustbindings.h"
|
|
7
|
+
|
|
8
|
+
VALUE cReference;
|
|
9
|
+
VALUE cConstantReference;
|
|
10
|
+
VALUE cUnresolvedConstantReference;
|
|
11
|
+
VALUE cResolvedConstantReference;
|
|
12
|
+
VALUE cMethodReference;
|
|
13
|
+
|
|
14
|
+
// ConstantReference#name -> String
|
|
15
|
+
static VALUE rdxr_constant_reference_name(VALUE self) {
|
|
16
|
+
HandleData *data;
|
|
17
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
18
|
+
|
|
19
|
+
void *graph;
|
|
20
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
21
|
+
|
|
22
|
+
const char *name = rdx_constant_reference_name(graph, data->id);
|
|
23
|
+
if (name == NULL) {
|
|
24
|
+
return Qnil;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
VALUE str = rb_utf8_str_new_cstr(name);
|
|
28
|
+
free_c_string(name);
|
|
29
|
+
return str;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ConstantReference#location -> Rubydex::Location
|
|
33
|
+
static VALUE rdxr_constant_reference_location(VALUE self) {
|
|
34
|
+
HandleData *data;
|
|
35
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
36
|
+
|
|
37
|
+
void *graph;
|
|
38
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
39
|
+
|
|
40
|
+
Location *loc = rdx_constant_reference_location(graph, data->id);
|
|
41
|
+
VALUE location = rdxi_build_location_value(loc);
|
|
42
|
+
rdx_location_free(loc);
|
|
43
|
+
return location;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// MethodReference#name -> String
|
|
47
|
+
static VALUE rdxr_method_reference_name(VALUE self) {
|
|
48
|
+
HandleData *data;
|
|
49
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
50
|
+
|
|
51
|
+
void *graph;
|
|
52
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
53
|
+
|
|
54
|
+
const char *name = rdx_method_reference_name(graph, data->id);
|
|
55
|
+
if (name == NULL) {
|
|
56
|
+
return Qnil;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
VALUE str = rb_utf8_str_new_cstr(name);
|
|
60
|
+
free_c_string(name);
|
|
61
|
+
return str;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// MethodReference#location -> Rubydex::Location
|
|
65
|
+
static VALUE rdxr_method_reference_location(VALUE self) {
|
|
66
|
+
HandleData *data;
|
|
67
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
68
|
+
|
|
69
|
+
void *graph;
|
|
70
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
71
|
+
|
|
72
|
+
Location *loc = rdx_method_reference_location(graph, data->id);
|
|
73
|
+
VALUE location = rdxi_build_location_value(loc);
|
|
74
|
+
rdx_location_free(loc);
|
|
75
|
+
return location;
|
|
76
|
+
}
|
|
77
|
+
|
|
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");
|
|
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);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
void rdxi_initialize_reference(VALUE mRubydex) {
|
|
99
|
+
cReference = rb_define_class_under(mRubydex, "Reference", rb_cObject);
|
|
100
|
+
rb_define_alloc_func(cReference, rdxr_handle_alloc);
|
|
101
|
+
rb_define_method(cReference, "initialize", rdxr_handle_initialize, 2);
|
|
102
|
+
rb_funcall(rb_singleton_class(cReference), rb_intern("private"), 1, ID2SYM(rb_intern("new")));
|
|
103
|
+
|
|
104
|
+
cConstantReference = rb_define_class_under(mRubydex, "ConstantReference", cReference);
|
|
105
|
+
rb_define_alloc_func(cConstantReference, rdxr_handle_alloc);
|
|
106
|
+
rb_define_method(cConstantReference, "initialize", rdxr_handle_initialize, 2);
|
|
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);
|
|
117
|
+
|
|
118
|
+
cMethodReference = rb_define_class_under(mRubydex, "MethodReference", cReference);
|
|
119
|
+
rb_define_alloc_func(cMethodReference, rdxr_handle_alloc);
|
|
120
|
+
rb_define_method(cMethodReference, "initialize", rdxr_handle_initialize, 2);
|
|
121
|
+
rb_define_method(cMethodReference, "name", rdxr_method_reference_name, 0);
|
|
122
|
+
rb_define_method(cMethodReference, "location", rdxr_method_reference_location, 0);
|
|
123
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifndef RUBYDEX_REFERENCE_H
|
|
2
|
+
#define RUBYDEX_REFERENCE_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
#include "rustbindings.h"
|
|
6
|
+
|
|
7
|
+
extern VALUE cReference;
|
|
8
|
+
extern VALUE cConstantReference;
|
|
9
|
+
extern VALUE cUnresolvedConstantReference;
|
|
10
|
+
extern VALUE cResolvedConstantReference;
|
|
11
|
+
extern VALUE cMethodReference;
|
|
12
|
+
|
|
13
|
+
void rdxi_initialize_reference(VALUE mRubydex);
|
|
14
|
+
|
|
15
|
+
#endif // RUBYDEX_REFERENCE_H
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#include "declaration.h"
|
|
2
|
+
#include "definition.h"
|
|
3
|
+
#include "diagnostic.h"
|
|
4
|
+
#include "document.h"
|
|
5
|
+
#include "graph.h"
|
|
6
|
+
#include "location.h"
|
|
7
|
+
#include "reference.h"
|
|
8
|
+
|
|
9
|
+
VALUE mRubydex;
|
|
10
|
+
|
|
11
|
+
void Init_rubydex(void) {
|
|
12
|
+
rb_ext_ractor_safe(true);
|
|
13
|
+
|
|
14
|
+
mRubydex = rb_define_module("Rubydex");
|
|
15
|
+
rdxi_initialize_graph(mRubydex);
|
|
16
|
+
rdxi_initialize_declaration(mRubydex);
|
|
17
|
+
rdxi_initialize_document(mRubydex);
|
|
18
|
+
rdxi_initialize_definition(mRubydex);
|
|
19
|
+
rdxi_initialize_location(mRubydex);
|
|
20
|
+
rdxi_initialize_diagnostic(mRubydex);
|
|
21
|
+
rdxi_initialize_reference(mRubydex);
|
|
22
|
+
}
|
data/ext/rubydex/utils.c
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#include "utils.h"
|
|
2
|
+
#include "declaration.h"
|
|
3
|
+
#include "reference.h"
|
|
4
|
+
#include "rustbindings.h"
|
|
5
|
+
|
|
6
|
+
// Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
|
|
7
|
+
// This copies the data so it must be freed
|
|
8
|
+
char **rdxi_str_array_to_char(VALUE array, size_t length) {
|
|
9
|
+
char **converted_array = malloc(length * sizeof(char *));
|
|
10
|
+
|
|
11
|
+
for (size_t i = 0; i < length; i++) {
|
|
12
|
+
VALUE item = rb_ary_entry(array, i);
|
|
13
|
+
const char *string = StringValueCStr(item);
|
|
14
|
+
|
|
15
|
+
converted_array[i] = malloc(strlen(string) + 1);
|
|
16
|
+
strcpy(converted_array[i], string);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return converted_array;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Free a char** array allocated by rdxi_str_array_to_char
|
|
23
|
+
void rdxi_free_str_array(char **array, size_t length) {
|
|
24
|
+
if (array != NULL) {
|
|
25
|
+
for (size_t i = 0; i < length; i++) {
|
|
26
|
+
free(array[i]);
|
|
27
|
+
}
|
|
28
|
+
free(array);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Verify that the Ruby object is an array of strings or raise `TypeError`
|
|
33
|
+
void rdxi_check_array_of_strings(VALUE array) {
|
|
34
|
+
Check_Type(array, T_ARRAY);
|
|
35
|
+
|
|
36
|
+
for (long i = 0; i < RARRAY_LEN(array); i++) {
|
|
37
|
+
VALUE item = rb_ary_entry(array, i);
|
|
38
|
+
Check_Type(item, T_STRING);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Yield body for iterating over declarations
|
|
43
|
+
VALUE rdxi_declarations_yield(VALUE args) {
|
|
44
|
+
VALUE self = rb_ary_entry(args, 0);
|
|
45
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
46
|
+
|
|
47
|
+
CDeclaration decl;
|
|
48
|
+
while (rdx_graph_declarations_iter_next(iter, &decl)) {
|
|
49
|
+
VALUE decl_class = rdxi_declaration_class_for_kind(decl.kind);
|
|
50
|
+
VALUE argv[] = {self, ULL2NUM(decl.id)};
|
|
51
|
+
VALUE handle = rb_class_new_instance(2, argv, decl_class);
|
|
52
|
+
rb_yield(handle);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return Qnil;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Ensure function for iterating over declarations to always free the iterator
|
|
59
|
+
VALUE rdxi_declarations_ensure(VALUE args) {
|
|
60
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
61
|
+
rdx_graph_declarations_iter_free(iter);
|
|
62
|
+
return Qnil;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Yield body for iterating over constant references
|
|
66
|
+
VALUE rdxi_constant_references_yield(VALUE args) {
|
|
67
|
+
VALUE graph_obj = rb_ary_entry(args, 0);
|
|
68
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
69
|
+
|
|
70
|
+
CConstantReference cref;
|
|
71
|
+
while (rdx_constant_references_iter_next(iter, &cref)) {
|
|
72
|
+
VALUE ref_class = (cref.declaration_id == 0)
|
|
73
|
+
? cUnresolvedConstantReference
|
|
74
|
+
: cResolvedConstantReference;
|
|
75
|
+
VALUE argv[] = {graph_obj, ULL2NUM(cref.id)};
|
|
76
|
+
VALUE obj = rb_class_new_instance(2, argv, ref_class);
|
|
77
|
+
rb_yield(obj);
|
|
78
|
+
}
|
|
79
|
+
return Qnil;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Ensure function for iterating over constant references to always free the iterator
|
|
83
|
+
VALUE rdxi_constant_references_ensure(VALUE args) {
|
|
84
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
85
|
+
rdx_constant_references_iter_free(iter);
|
|
86
|
+
return Qnil;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Yield body for iterating over method references
|
|
90
|
+
VALUE rdxi_method_references_yield(VALUE args) {
|
|
91
|
+
VALUE graph_obj = rb_ary_entry(args, 0);
|
|
92
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
93
|
+
|
|
94
|
+
CMethodReference cref;
|
|
95
|
+
while (rdx_method_references_iter_next(iter, &cref)) {
|
|
96
|
+
VALUE argv[] = {graph_obj, ULL2NUM(cref.id)};
|
|
97
|
+
VALUE obj = rb_class_new_instance(2, argv, cMethodReference);
|
|
98
|
+
rb_yield(obj);
|
|
99
|
+
}
|
|
100
|
+
return Qnil;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Ensure function for iterating over method references to always free the iterator
|
|
104
|
+
VALUE rdxi_method_references_ensure(VALUE args) {
|
|
105
|
+
void *iter = (void *)(uintptr_t)NUM2ULL(rb_ary_entry(args, 1));
|
|
106
|
+
rdx_method_references_iter_free(iter);
|
|
107
|
+
return Qnil;
|
|
108
|
+
}
|
data/ext/rubydex/utils.h
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#ifndef RUBYDEX_UTILS_H
|
|
2
|
+
#define RUBYDEX_UTILS_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
|
|
6
|
+
// Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
|
|
7
|
+
// This copies the data so it must be freed with rdxi_free_str_array
|
|
8
|
+
char **rdxi_str_array_to_char(VALUE array, size_t length);
|
|
9
|
+
|
|
10
|
+
// Free a char** array allocated by rdxi_str_array_to_char
|
|
11
|
+
void rdxi_free_str_array(char **array, size_t length);
|
|
12
|
+
|
|
13
|
+
// Verify that the Ruby object is an array of strings or raise `TypeError`
|
|
14
|
+
void rdxi_check_array_of_strings(VALUE array);
|
|
15
|
+
|
|
16
|
+
// Yield body for iterating over declarations
|
|
17
|
+
VALUE rdxi_declarations_yield(VALUE args);
|
|
18
|
+
|
|
19
|
+
// Ensure function for iterating over declarations to always free the iterator
|
|
20
|
+
VALUE rdxi_declarations_ensure(VALUE args);
|
|
21
|
+
|
|
22
|
+
// Yield body for iterating over constant references
|
|
23
|
+
VALUE rdxi_constant_references_yield(VALUE args);
|
|
24
|
+
|
|
25
|
+
// Ensure function for iterating over constant references
|
|
26
|
+
VALUE rdxi_constant_references_ensure(VALUE args);
|
|
27
|
+
|
|
28
|
+
// Yield body for iterating over method references
|
|
29
|
+
VALUE rdxi_method_references_yield(VALUE args);
|
|
30
|
+
|
|
31
|
+
// Ensure function for iterating over method references
|
|
32
|
+
VALUE rdxi_method_references_ensure(VALUE args);
|
|
33
|
+
|
|
34
|
+
#endif // RUBYDEX_UTILS_H
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubydex
|
|
4
|
+
class Comment
|
|
5
|
+
#: String
|
|
6
|
+
attr_reader :string
|
|
7
|
+
|
|
8
|
+
#: Location
|
|
9
|
+
attr_reader :location
|
|
10
|
+
|
|
11
|
+
#: (?string: String, ?location: Location) -> void
|
|
12
|
+
def initialize(string:, location:)
|
|
13
|
+
@string = string
|
|
14
|
+
@location = location
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubydex
|
|
4
|
+
class Diagnostic
|
|
5
|
+
#: Symbol
|
|
6
|
+
attr_reader :rule
|
|
7
|
+
|
|
8
|
+
#: String
|
|
9
|
+
attr_reader :message
|
|
10
|
+
|
|
11
|
+
#: Location
|
|
12
|
+
attr_reader :location
|
|
13
|
+
|
|
14
|
+
#: (rule: Symbol, message: String, location: Location) -> void
|
|
15
|
+
def initialize(rule:, message:, location:)
|
|
16
|
+
@rule = rule
|
|
17
|
+
@message = message
|
|
18
|
+
@location = location
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubydex
|
|
4
|
+
# The global graph representing all declarations and their relationships for the workspace
|
|
5
|
+
#
|
|
6
|
+
# Note: this class is partially defined in C to integrate with the Rust backend
|
|
7
|
+
class Graph
|
|
8
|
+
IGNORED_DIRECTORIES = [
|
|
9
|
+
".bundle",
|
|
10
|
+
".claude",
|
|
11
|
+
".git",
|
|
12
|
+
".github",
|
|
13
|
+
".ruby-lsp",
|
|
14
|
+
".vscode",
|
|
15
|
+
"log",
|
|
16
|
+
"node_modules",
|
|
17
|
+
"tmp",
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
#: String
|
|
21
|
+
attr_accessor :workspace_path
|
|
22
|
+
|
|
23
|
+
#: (?workspace_path: String) -> void
|
|
24
|
+
def initialize(workspace_path: Dir.pwd)
|
|
25
|
+
@workspace_path = workspace_path
|
|
26
|
+
|
|
27
|
+
exclude_paths(IGNORED_DIRECTORIES.map { |dir| File.join(@workspace_path, dir) })
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Index all files and dependencies of the workspace that exists in `@workspace_path`
|
|
31
|
+
#: -> Array[String]
|
|
32
|
+
def index_workspace
|
|
33
|
+
index_all(workspace_paths)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns all workspace paths that should be indexed, excluding directories that we don't need to descend into such
|
|
37
|
+
# as `.git`, `node_modules`. Also includes any top level Ruby files
|
|
38
|
+
#
|
|
39
|
+
#: -> Array[String]
|
|
40
|
+
def workspace_paths
|
|
41
|
+
paths = []
|
|
42
|
+
|
|
43
|
+
Dir.each_child(@workspace_path) do |entry|
|
|
44
|
+
full_path = File.join(@workspace_path, entry)
|
|
45
|
+
|
|
46
|
+
if File.directory?(full_path)
|
|
47
|
+
paths << full_path unless IGNORED_DIRECTORIES.include?(entry)
|
|
48
|
+
elsif File.extname(entry) == ".rb"
|
|
49
|
+
paths << full_path
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
add_workspace_dependency_paths(paths)
|
|
54
|
+
add_core_rbs_definition_paths(paths)
|
|
55
|
+
paths.uniq!
|
|
56
|
+
paths
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
# Gathers the paths we have to index for all workspace dependencies
|
|
62
|
+
#: (Array[String]) -> void
|
|
63
|
+
def add_workspace_dependency_paths(paths)
|
|
64
|
+
specs = Bundler.locked_gems&.specs
|
|
65
|
+
return unless specs
|
|
66
|
+
|
|
67
|
+
specs.each do |lazy_spec|
|
|
68
|
+
spec = Gem::Specification.find_by_name(lazy_spec.name)
|
|
69
|
+
spec.require_paths.each do |path|
|
|
70
|
+
# For native extensions, RubyGems inserts an absolute require path pointing to
|
|
71
|
+
# `gems/some-gem-1.0.0/extensions`. Those paths don't actually include any Ruby files inside, so we can skip
|
|
72
|
+
# descending them
|
|
73
|
+
next if File.absolute_path?(path)
|
|
74
|
+
|
|
75
|
+
paths << File.join(spec.full_gem_path, path)
|
|
76
|
+
end
|
|
77
|
+
rescue Gem::MissingSpecError
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Searches for the latest installation of the `rbs` gem and adds the paths for the core and stdlib RBS definitions
|
|
83
|
+
# to the list of paths. This method does not require `rbs` to be a part of the bundle. It searches for whatever
|
|
84
|
+
# latest installation of `rbs` exists in the system and fails silently if we can't find one
|
|
85
|
+
#
|
|
86
|
+
#: (Array[String]) -> void
|
|
87
|
+
def add_core_rbs_definition_paths(paths)
|
|
88
|
+
rbs_gem_path = Gem.path
|
|
89
|
+
.flat_map { |path| Dir.glob(File.join(path, "gems", "rbs-[0-9]*/")) }
|
|
90
|
+
.max_by { |path| Gem::Version.new(File.basename(path).delete_prefix("rbs-")) }
|
|
91
|
+
|
|
92
|
+
return unless rbs_gem_path
|
|
93
|
+
|
|
94
|
+
paths << File.join(rbs_gem_path, "core")
|
|
95
|
+
paths << File.join(rbs_gem_path, "stdlib")
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubydex
|
|
4
|
+
class Keyword
|
|
5
|
+
#: String
|
|
6
|
+
attr_reader :name
|
|
7
|
+
|
|
8
|
+
#: String
|
|
9
|
+
attr_reader :documentation
|
|
10
|
+
|
|
11
|
+
#: (String name, String documentation) -> void
|
|
12
|
+
def initialize(name, documentation)
|
|
13
|
+
@name = name
|
|
14
|
+
@documentation = documentation
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubydex
|
|
4
|
+
# A zero based internal location. Intended to be used for tool-to-tool communication, such as a language server
|
|
5
|
+
# communicating with an editor.
|
|
6
|
+
class Location
|
|
7
|
+
class NotFileUriError < StandardError; end
|
|
8
|
+
|
|
9
|
+
include Comparable
|
|
10
|
+
|
|
11
|
+
#: String
|
|
12
|
+
attr_reader :uri
|
|
13
|
+
|
|
14
|
+
#: Integer
|
|
15
|
+
attr_reader :start_line, :end_line, :start_column, :end_column
|
|
16
|
+
|
|
17
|
+
#: (?uri: String, ?start_line: Integer, ?end_line: Integer, ?start_column: Integer, ?end_column: Integer) -> void
|
|
18
|
+
def initialize(uri:, start_line:, end_line:, start_column:, end_column:)
|
|
19
|
+
@uri = uri
|
|
20
|
+
@start_line = start_line
|
|
21
|
+
@end_line = end_line
|
|
22
|
+
@start_column = start_column
|
|
23
|
+
@end_column = end_column
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#: () -> String
|
|
27
|
+
def to_file_path
|
|
28
|
+
uri = URI(@uri)
|
|
29
|
+
raise NotFileUriError, "URI is not a file:// URI: #{@uri}" unless uri.scheme == "file"
|
|
30
|
+
|
|
31
|
+
path = uri.path
|
|
32
|
+
# TODO: This has to go away once we have a proper URI abstraction
|
|
33
|
+
path.delete_prefix!("/") if Gem.win_platform?
|
|
34
|
+
path
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#: (other: BasicObject) -> Integer
|
|
38
|
+
def <=>(other)
|
|
39
|
+
return -1 unless other.is_a?(Location)
|
|
40
|
+
|
|
41
|
+
comparable_values <=> other.comparable_values
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
#: () -> [String, Integer, Integer, Integer, Integer]
|
|
45
|
+
def comparable_values
|
|
46
|
+
[@uri, @start_line, @start_column, @end_line, @end_column]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Turns this zero based location into a one based location for display purposes.
|
|
50
|
+
#
|
|
51
|
+
#: () -> DisplayLocation
|
|
52
|
+
def to_display
|
|
53
|
+
DisplayLocation.new(
|
|
54
|
+
uri: @uri,
|
|
55
|
+
start_line: @start_line + 1,
|
|
56
|
+
end_line: @end_line + 1,
|
|
57
|
+
start_column: @start_column + 1,
|
|
58
|
+
end_column: @end_column + 1,
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#: -> String
|
|
63
|
+
def to_s
|
|
64
|
+
"#{to_file_path}:#{@start_line + 1}:#{@start_column + 1}-#{@end_line + 1}:#{@end_column + 1}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# A one based location intended for display purposes. This is what should be used when displaying a location to users,
|
|
69
|
+
# like in CLIs
|
|
70
|
+
class DisplayLocation < Location
|
|
71
|
+
# Returns itself
|
|
72
|
+
#
|
|
73
|
+
#: () -> DisplayLocation
|
|
74
|
+
def to_display
|
|
75
|
+
self
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Normalize to zero-based for comparison with Location
|
|
79
|
+
#
|
|
80
|
+
#: () -> [String, Integer, Integer, Integer, Integer]
|
|
81
|
+
def comparable_values
|
|
82
|
+
[@uri, @start_line - 1, @start_column - 1, @end_line - 1, @end_column - 1]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#: -> String
|
|
86
|
+
def to_s
|
|
87
|
+
"#{to_file_path}:#{@start_line}:#{@start_column}-#{@end_line}:#{@end_column}"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|