rubydex 0.2.2-aarch64-linux → 0.2.4-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 +4 -4
- data/THIRD_PARTY_LICENSES.html +2 -2
- data/ext/rubydex/definition.c +24 -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/declaration.rb +12 -0
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/reference.rb +10 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +1 -0
- data/rbi/rubydex.rbi +23 -1
- data/rust/Cargo.lock +4 -4
- data/rust/rubydex/src/indexing/ruby_indexer.rs +100 -7
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +158 -0
- data/rust/rubydex/src/model/graph.rs +21 -4
- data/rust/rubydex/src/resolution_tests.rs +41 -0
- data/rust/rubydex-mcp/Cargo.toml +1 -1
- data/rust/rubydex-mcp/src/server.rs +5 -6
- data/rust/rubydex-sys/src/definition_api.rs +26 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 49147264143f618ef7d2b5bbfa983e511b86123dc01548c2a4176e686a44b57e
|
|
4
|
+
data.tar.gz: cbd51f1380330f85dde7861c7df96cbc1db4117458952c561164eef9c511901e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5daa009adaef78d504f2710aac72ec36875a3a7ae169048b36e7220d984ddaf7dd562431a460a44b95530bb030a341887ccf300d14646051f722ba0cc941e9bb
|
|
7
|
+
data.tar.gz: adf4c9a9faf405356b64e6de927a7aa4b8499164c9cf48918683b45ab0e7825668f5505d50e0b29305292bae3db511ae6ffb6ab2e96628c1b1ecdc2076fb8b3b
|
data/THIRD_PARTY_LICENSES.html
CHANGED
|
@@ -2957,10 +2957,10 @@ limitations under the License.
|
|
|
2957
2957
|
1.0.25</a></li>
|
|
2958
2958
|
<li><a
|
|
2959
2959
|
href=" https://github.com/modelcontextprotocol/rust-sdk/ ">rmcp-macros
|
|
2960
|
-
|
|
2960
|
+
1.6.0</a></li>
|
|
2961
2961
|
<li><a
|
|
2962
2962
|
href=" https://github.com/modelcontextprotocol/rust-sdk/ ">rmcp
|
|
2963
|
-
|
|
2963
|
+
1.4.0</a></li>
|
|
2964
2964
|
<li><a
|
|
2965
2965
|
href=" https://github.com/rust-lang/rustc-hash ">rustc-hash
|
|
2966
2966
|
2.1.1</a></li>
|
data/ext/rubydex/definition.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "definition.h"
|
|
2
|
+
#include "declaration.h"
|
|
2
3
|
#include "graph.h"
|
|
3
4
|
#include "handle.h"
|
|
4
5
|
#include "location.h"
|
|
@@ -172,6 +173,28 @@ static VALUE rdxr_definition_name_location(VALUE self) {
|
|
|
172
173
|
return location;
|
|
173
174
|
}
|
|
174
175
|
|
|
176
|
+
// Definition#declaration -> Rubydex::Declaration?
|
|
177
|
+
// Returns the declaration this definition belongs to or nil when it cannot be located (for example, before
|
|
178
|
+
// `Graph#resolve` has run).
|
|
179
|
+
static VALUE rdxr_definition_declaration(VALUE self) {
|
|
180
|
+
HandleData *data;
|
|
181
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
182
|
+
|
|
183
|
+
void *graph;
|
|
184
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
185
|
+
|
|
186
|
+
const struct CDeclaration *decl = rdx_definition_declaration(graph, data->id);
|
|
187
|
+
if (decl == NULL) {
|
|
188
|
+
return Qnil;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
VALUE decl_class = rdxi_declaration_class_for_kind(decl->kind);
|
|
192
|
+
VALUE argv[] = {data->graph_obj, ULL2NUM(decl->id)};
|
|
193
|
+
free_c_declaration(decl);
|
|
194
|
+
|
|
195
|
+
return rb_class_new_instance(2, argv, decl_class);
|
|
196
|
+
}
|
|
197
|
+
|
|
175
198
|
static VALUE rdxi_build_constant_reference(VALUE graph_obj, const CConstantReference *cref) {
|
|
176
199
|
VALUE ref_class = (cref->declaration_id == 0)
|
|
177
200
|
? cUnresolvedConstantReference
|
|
@@ -282,6 +305,7 @@ void rdxi_initialize_definition(VALUE mod) {
|
|
|
282
305
|
rb_define_method(cDefinition, "name", rdxr_definition_name, 0);
|
|
283
306
|
rb_define_method(cDefinition, "deprecated?", rdxr_definition_deprecated, 0);
|
|
284
307
|
rb_define_method(cDefinition, "name_location", rdxr_definition_name_location, 0);
|
|
308
|
+
rb_define_method(cDefinition, "declaration", rdxr_definition_declaration, 0);
|
|
285
309
|
|
|
286
310
|
cClassDefinition = rb_define_class_under(mRubydex, "ClassDefinition", cDefinition);
|
|
287
311
|
rb_define_method(cClassDefinition, "superclass", rdxr_class_definition_superclass, 0);
|
data/lib/rubydex/3.2/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/3.3/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/3.4/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/4.0/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/declaration.rb
CHANGED
|
@@ -20,6 +20,13 @@ module Rubydex
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
class Namespace < Declaration
|
|
24
|
+
#: (String ancestor_name) -> bool
|
|
25
|
+
def has_ancestor?(ancestor_name)
|
|
26
|
+
ancestors.any? { |ancestor| ancestor.name == ancestor_name }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
23
30
|
class Class < Namespace
|
|
24
31
|
include Visibility
|
|
25
32
|
end
|
|
@@ -28,6 +35,11 @@ module Rubydex
|
|
|
28
35
|
include Visibility
|
|
29
36
|
end
|
|
30
37
|
|
|
38
|
+
class SingletonClass < Namespace
|
|
39
|
+
#: () -> Declaration
|
|
40
|
+
alias_method :attached_class, :owner
|
|
41
|
+
end
|
|
42
|
+
|
|
31
43
|
class Constant < Declaration
|
|
32
44
|
include Visibility
|
|
33
45
|
end
|
|
Binary file
|
data/lib/rubydex/version.rb
CHANGED
data/lib/rubydex.rb
CHANGED
data/rbi/rubydex.rbi
CHANGED
|
@@ -15,6 +15,8 @@ class Rubydex::Comment
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
class Rubydex::ConstantReference < Rubydex::Reference
|
|
18
|
+
abstract!
|
|
19
|
+
|
|
18
20
|
sig { returns(Rubydex::Location) }
|
|
19
21
|
def location; end
|
|
20
22
|
|
|
@@ -36,6 +38,8 @@ class Rubydex::ResolvedConstantReference < Rubydex::ConstantReference
|
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
class Rubydex::Declaration
|
|
41
|
+
abstract!
|
|
42
|
+
|
|
39
43
|
sig { returns(T::Enumerable[Rubydex::Definition]) }
|
|
40
44
|
def definitions; end
|
|
41
45
|
|
|
@@ -92,12 +96,17 @@ class Rubydex::Method < Rubydex::Declaration
|
|
|
92
96
|
end
|
|
93
97
|
|
|
94
98
|
class Rubydex::Namespace < Rubydex::Declaration
|
|
99
|
+
abstract!
|
|
100
|
+
|
|
95
101
|
sig { returns(T::Enumerable[Rubydex::ConstantReference]) }
|
|
96
102
|
def references; end
|
|
97
103
|
|
|
98
104
|
sig { returns(T::Enumerable[Rubydex::Namespace]) }
|
|
99
105
|
def ancestors; end
|
|
100
106
|
|
|
107
|
+
sig { params(ancestor_name: String).returns(T::Boolean) }
|
|
108
|
+
def has_ancestor?(ancestor_name); end
|
|
109
|
+
|
|
101
110
|
sig { returns(T::Enumerable[Rubydex::Namespace]) }
|
|
102
111
|
def descendants; end
|
|
103
112
|
|
|
@@ -116,9 +125,15 @@ end
|
|
|
116
125
|
|
|
117
126
|
class Rubydex::Class < Rubydex::Namespace; end
|
|
118
127
|
class Rubydex::Module < Rubydex::Namespace; end
|
|
119
|
-
|
|
128
|
+
|
|
129
|
+
class Rubydex::SingletonClass < Rubydex::Namespace
|
|
130
|
+
sig { returns(Rubydex::Declaration) }
|
|
131
|
+
def attached_class; end
|
|
132
|
+
end
|
|
120
133
|
|
|
121
134
|
class Rubydex::Definition
|
|
135
|
+
abstract!
|
|
136
|
+
|
|
122
137
|
sig { returns(T::Array[Rubydex::Comment]) }
|
|
123
138
|
def comments; end
|
|
124
139
|
|
|
@@ -134,6 +149,9 @@ class Rubydex::Definition
|
|
|
134
149
|
sig { returns(T.nilable(Rubydex::Location)) }
|
|
135
150
|
def name_location; end
|
|
136
151
|
|
|
152
|
+
sig { returns(T.nilable(Rubydex::Declaration)) }
|
|
153
|
+
def declaration; end
|
|
154
|
+
|
|
137
155
|
class << self
|
|
138
156
|
private
|
|
139
157
|
|
|
@@ -172,6 +190,8 @@ class Rubydex::ClassDefinition < Rubydex::Definition
|
|
|
172
190
|
end
|
|
173
191
|
|
|
174
192
|
class Rubydex::Mixin
|
|
193
|
+
abstract!
|
|
194
|
+
|
|
175
195
|
sig { returns(Rubydex::ConstantReference) }
|
|
176
196
|
attr_reader :constant_reference
|
|
177
197
|
|
|
@@ -454,6 +474,8 @@ class Rubydex::MethodReference < Rubydex::Reference
|
|
|
454
474
|
end
|
|
455
475
|
|
|
456
476
|
class Rubydex::Reference
|
|
477
|
+
abstract!
|
|
478
|
+
|
|
457
479
|
class << self
|
|
458
480
|
private
|
|
459
481
|
|
data/rust/Cargo.lock
CHANGED
|
@@ -971,9 +971,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
|
|
971
971
|
|
|
972
972
|
[[package]]
|
|
973
973
|
name = "rmcp"
|
|
974
|
-
version = "
|
|
974
|
+
version = "1.4.0"
|
|
975
975
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
976
|
-
checksum = "
|
|
976
|
+
checksum = "f542f74cf247da16f19bbc87e298cd201e912314f4083e88cdd671f44f5fcb53"
|
|
977
977
|
dependencies = [
|
|
978
978
|
"async-trait",
|
|
979
979
|
"base64",
|
|
@@ -993,9 +993,9 @@ dependencies = [
|
|
|
993
993
|
|
|
994
994
|
[[package]]
|
|
995
995
|
name = "rmcp-macros"
|
|
996
|
-
version = "
|
|
996
|
+
version = "1.6.0"
|
|
997
997
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
998
|
-
checksum = "
|
|
998
|
+
checksum = "7caa6743cc0888e433105fe1bc551a7f607940b126a37bc97b478e86064627eb"
|
|
999
999
|
dependencies = [
|
|
1000
1000
|
"darling",
|
|
1001
1001
|
"proc-macro2",
|
|
@@ -1274,6 +1274,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1274
1274
|
}
|
|
1275
1275
|
}
|
|
1276
1276
|
|
|
1277
|
+
#[allow(clippy::too_many_lines)]
|
|
1277
1278
|
fn handle_singleton_method_visibility(
|
|
1278
1279
|
&mut self,
|
|
1279
1280
|
node: &ruby_prism::CallNode,
|
|
@@ -1307,7 +1308,10 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1307
1308
|
return;
|
|
1308
1309
|
};
|
|
1309
1310
|
|
|
1310
|
-
|
|
1311
|
+
let args = arguments.arguments();
|
|
1312
|
+
let arg_count = args.len();
|
|
1313
|
+
|
|
1314
|
+
for argument in &args {
|
|
1311
1315
|
match argument {
|
|
1312
1316
|
ruby_prism::Node::SymbolNode { .. } | ruby_prism::Node::StringNode { .. } => {
|
|
1313
1317
|
self.create_method_visibility_definition(
|
|
@@ -1316,6 +1320,88 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1316
1320
|
DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
|
|
1317
1321
|
);
|
|
1318
1322
|
}
|
|
1323
|
+
ruby_prism::Node::ArrayNode { .. } if arg_count == 1 => {
|
|
1324
|
+
let array = argument.as_array_node().unwrap();
|
|
1325
|
+
for element in &array.elements() {
|
|
1326
|
+
match element {
|
|
1327
|
+
ruby_prism::Node::SymbolNode { .. } | ruby_prism::Node::StringNode { .. } => {
|
|
1328
|
+
self.create_method_visibility_definition(
|
|
1329
|
+
&element,
|
|
1330
|
+
visibility,
|
|
1331
|
+
DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
ruby_prism::Node::DefNode { .. } => {
|
|
1335
|
+
let def_node = element.as_def_node().unwrap();
|
|
1336
|
+
if def_node.receiver().is_none() {
|
|
1337
|
+
self.local_graph.add_diagnostic(
|
|
1338
|
+
Rule::InvalidMethodVisibility,
|
|
1339
|
+
Offset::from_prism_location(&element.location()),
|
|
1340
|
+
format!("`{call_name}` requires a singleton method definition"),
|
|
1341
|
+
);
|
|
1342
|
+
self.visit(&element);
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
let name_loc = def_node.name_loc();
|
|
1346
|
+
let name = Self::location_to_string(&name_loc);
|
|
1347
|
+
self.create_method_visibility_definition_from_name(
|
|
1348
|
+
&name,
|
|
1349
|
+
&name_loc,
|
|
1350
|
+
visibility,
|
|
1351
|
+
DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
|
|
1352
|
+
);
|
|
1353
|
+
self.visit(&element);
|
|
1354
|
+
}
|
|
1355
|
+
_ => {
|
|
1356
|
+
self.local_graph.add_diagnostic(
|
|
1357
|
+
Rule::InvalidMethodVisibility,
|
|
1358
|
+
Offset::from_prism_location(&element.location()),
|
|
1359
|
+
format!(
|
|
1360
|
+
"`{call_name}` array element must be a Symbol, String, or method definition"
|
|
1361
|
+
),
|
|
1362
|
+
);
|
|
1363
|
+
self.visit(&element);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
ruby_prism::Node::DefNode { .. } => {
|
|
1369
|
+
let def_node = argument.as_def_node().unwrap();
|
|
1370
|
+
if def_node.receiver().is_none() {
|
|
1371
|
+
self.local_graph.add_diagnostic(
|
|
1372
|
+
Rule::InvalidMethodVisibility,
|
|
1373
|
+
Offset::from_prism_location(&argument.location()),
|
|
1374
|
+
format!("`{call_name}` requires a singleton method definition"),
|
|
1375
|
+
);
|
|
1376
|
+
self.visit(&argument);
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
let name_loc = def_node.name_loc();
|
|
1380
|
+
let name = Self::location_to_string(&name_loc);
|
|
1381
|
+
self.create_method_visibility_definition_from_name(
|
|
1382
|
+
&name,
|
|
1383
|
+
&name_loc,
|
|
1384
|
+
visibility,
|
|
1385
|
+
DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
|
|
1386
|
+
);
|
|
1387
|
+
self.visit(&argument);
|
|
1388
|
+
}
|
|
1389
|
+
arg if Self::is_attr_call(&arg) => {
|
|
1390
|
+
self.local_graph.add_diagnostic(
|
|
1391
|
+
Rule::InvalidMethodVisibility,
|
|
1392
|
+
Offset::from_prism_location(&arg.location()),
|
|
1393
|
+
format!("`{call_name}` does not accept `attr_*` arguments"),
|
|
1394
|
+
);
|
|
1395
|
+
self.visit(&arg);
|
|
1396
|
+
}
|
|
1397
|
+
ruby_prism::Node::ArrayNode { .. } => {
|
|
1398
|
+
self.local_graph.add_diagnostic(
|
|
1399
|
+
Rule::InvalidMethodVisibility,
|
|
1400
|
+
Offset::from_prism_location(&argument.location()),
|
|
1401
|
+
format!("`{call_name}` array argument must be the only argument"),
|
|
1402
|
+
);
|
|
1403
|
+
self.visit(&argument);
|
|
1404
|
+
}
|
|
1319
1405
|
_ => {
|
|
1320
1406
|
self.local_graph.add_diagnostic(
|
|
1321
1407
|
Rule::InvalidMethodVisibility,
|
|
@@ -1390,11 +1476,8 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1390
1476
|
let (name, location) = match arg {
|
|
1391
1477
|
ruby_prism::Node::SymbolNode { .. } => {
|
|
1392
1478
|
let symbol = arg.as_symbol_node().unwrap();
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
} else {
|
|
1396
|
-
return;
|
|
1397
|
-
}
|
|
1479
|
+
let Some(value_loc) = symbol.value_loc() else { return };
|
|
1480
|
+
(Self::location_to_string(&value_loc), value_loc)
|
|
1398
1481
|
}
|
|
1399
1482
|
ruby_prism::Node::StringNode { .. } => {
|
|
1400
1483
|
let string = arg.as_string_node().unwrap();
|
|
@@ -1404,8 +1487,18 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1404
1487
|
_ => return,
|
|
1405
1488
|
};
|
|
1406
1489
|
|
|
1490
|
+
self.create_method_visibility_definition_from_name(&name, &location, visibility, flags);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
fn create_method_visibility_definition_from_name(
|
|
1494
|
+
&mut self,
|
|
1495
|
+
name: &str,
|
|
1496
|
+
location: &ruby_prism::Location,
|
|
1497
|
+
visibility: Visibility,
|
|
1498
|
+
flags: DefinitionFlags,
|
|
1499
|
+
) {
|
|
1407
1500
|
let str_id = self.local_graph.intern_string(format!("{name}()"));
|
|
1408
|
-
let arg_offset = Offset::from_prism_location(
|
|
1501
|
+
let arg_offset = Offset::from_prism_location(location);
|
|
1409
1502
|
let definition = Definition::MethodVisibility(Box::new(MethodVisibilityDefinition::new(
|
|
1410
1503
|
str_id,
|
|
1411
1504
|
visibility,
|
|
@@ -2237,6 +2237,9 @@ mod visibility_tests {
|
|
|
2237
2237
|
|
|
2238
2238
|
module Foo
|
|
2239
2239
|
private_class_method NOT_INDEXED
|
|
2240
|
+
attr_reader :a_attr_target
|
|
2241
|
+
private_class_method attr_reader(:bad)
|
|
2242
|
+
private_class_method def inline; end
|
|
2240
2243
|
end
|
|
2241
2244
|
",
|
|
2242
2245
|
);
|
|
@@ -2247,6 +2250,8 @@ mod visibility_tests {
|
|
|
2247
2250
|
"invalid-method-visibility: `private_class_method` called at top level (1:1-1:34)",
|
|
2248
2251
|
"invalid-method-visibility: `private_class_method` called at top level (2:1-2:39)",
|
|
2249
2252
|
"invalid-method-visibility: `private_class_method` called with a non-literal argument (6:24-6:35)",
|
|
2253
|
+
"invalid-method-visibility: `private_class_method` does not accept `attr_*` arguments (8:24-8:41)",
|
|
2254
|
+
"invalid-method-visibility: `private_class_method` requires a singleton method definition (9:24-9:39)",
|
|
2250
2255
|
]
|
|
2251
2256
|
);
|
|
2252
2257
|
}
|
|
@@ -2306,6 +2311,159 @@ mod visibility_tests {
|
|
|
2306
2311
|
);
|
|
2307
2312
|
assert_constant_references_eq!(&context, ["NESTED_REF"]);
|
|
2308
2313
|
}
|
|
2314
|
+
|
|
2315
|
+
#[test]
|
|
2316
|
+
fn index_private_class_method_inline_def() {
|
|
2317
|
+
let context = index_source(
|
|
2318
|
+
r"
|
|
2319
|
+
class Foo
|
|
2320
|
+
private_class_method def self.inline; end
|
|
2321
|
+
end
|
|
2322
|
+
",
|
|
2323
|
+
);
|
|
2324
|
+
|
|
2325
|
+
assert_no_local_diagnostics!(&context);
|
|
2326
|
+
|
|
2327
|
+
assert_definition_at!(&context, "2:33-2:39", MethodVisibility, |def| {
|
|
2328
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2329
|
+
assert_string_eq!(&context, def.str_id(), "inline()");
|
|
2330
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
#[test]
|
|
2335
|
+
fn index_private_class_method_array_form() {
|
|
2336
|
+
let context = index_source(
|
|
2337
|
+
r#"
|
|
2338
|
+
class Foo
|
|
2339
|
+
def self.flat; end
|
|
2340
|
+
def self.flat2; end
|
|
2341
|
+
def self.mixed; end
|
|
2342
|
+
|
|
2343
|
+
private_class_method [:flat, :flat2]
|
|
2344
|
+
public_class_method [:mixed, "flat"]
|
|
2345
|
+
private_class_method [def self.dyn; end]
|
|
2346
|
+
end
|
|
2347
|
+
"#,
|
|
2348
|
+
);
|
|
2349
|
+
|
|
2350
|
+
assert_no_local_diagnostics!(&context);
|
|
2351
|
+
|
|
2352
|
+
assert_definition_at!(&context, "6:26-6:30", MethodVisibility, |def| {
|
|
2353
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2354
|
+
assert_string_eq!(&context, def.str_id(), "flat()");
|
|
2355
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2356
|
+
});
|
|
2357
|
+
assert_definition_at!(&context, "6:33-6:38", MethodVisibility, |def| {
|
|
2358
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2359
|
+
assert_string_eq!(&context, def.str_id(), "flat2()");
|
|
2360
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2361
|
+
});
|
|
2362
|
+
assert_definition_at!(&context, "7:25-7:30", MethodVisibility, |def| {
|
|
2363
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2364
|
+
assert_string_eq!(&context, def.str_id(), "mixed()");
|
|
2365
|
+
assert_eq!(def.visibility(), &Visibility::Public);
|
|
2366
|
+
});
|
|
2367
|
+
assert_definition_at!(&context, "7:32-7:38", MethodVisibility, |def| {
|
|
2368
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2369
|
+
assert_string_eq!(&context, def.str_id(), "flat()");
|
|
2370
|
+
assert_eq!(def.visibility(), &Visibility::Public);
|
|
2371
|
+
});
|
|
2372
|
+
assert_definition_at!(&context, "8:34-8:37", MethodVisibility, |def| {
|
|
2373
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2374
|
+
assert_string_eq!(&context, def.str_id(), "dyn()");
|
|
2375
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
#[test]
|
|
2380
|
+
fn index_private_class_method_array_continues_past_invalid_element() {
|
|
2381
|
+
let context = index_source(
|
|
2382
|
+
r"
|
|
2383
|
+
class Foo
|
|
2384
|
+
def self.flat; end
|
|
2385
|
+
def self.later; end
|
|
2386
|
+
|
|
2387
|
+
private_class_method [:flat, SOME_CONST, :later]
|
|
2388
|
+
end
|
|
2389
|
+
",
|
|
2390
|
+
);
|
|
2391
|
+
|
|
2392
|
+
assert_local_diagnostics_eq!(
|
|
2393
|
+
&context,
|
|
2394
|
+
vec![
|
|
2395
|
+
"invalid-method-visibility: `private_class_method` array element must be a Symbol, String, or method definition (5:32-5:42)"
|
|
2396
|
+
]
|
|
2397
|
+
);
|
|
2398
|
+
|
|
2399
|
+
assert_definition_at!(&context, "5:26-5:30", MethodVisibility, |def| {
|
|
2400
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2401
|
+
assert_string_eq!(&context, def.str_id(), "flat()");
|
|
2402
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2403
|
+
});
|
|
2404
|
+
assert_definition_at!(&context, "5:45-5:50", MethodVisibility, |def| {
|
|
2405
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2406
|
+
assert_string_eq!(&context, def.str_id(), "later()");
|
|
2407
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
#[test]
|
|
2412
|
+
fn index_private_class_method_array_rejects_receiverless_def() {
|
|
2413
|
+
let context = index_source(
|
|
2414
|
+
r"
|
|
2415
|
+
class Foo
|
|
2416
|
+
private_class_method [def instance_method; end]
|
|
2417
|
+
end
|
|
2418
|
+
",
|
|
2419
|
+
);
|
|
2420
|
+
|
|
2421
|
+
assert_local_diagnostics_eq!(
|
|
2422
|
+
&context,
|
|
2423
|
+
vec![
|
|
2424
|
+
"invalid-method-visibility: `private_class_method` requires a singleton method definition (2:25-2:49)"
|
|
2425
|
+
]
|
|
2426
|
+
);
|
|
2427
|
+
|
|
2428
|
+
for def in context.graph().definitions().values() {
|
|
2429
|
+
assert!(
|
|
2430
|
+
!matches!(def, Definition::MethodVisibility(d) if d.flags().is_singleton_method_visibility()),
|
|
2431
|
+
"should not record visibility for receiverless def in array"
|
|
2432
|
+
);
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
assert_definition_at!(&context, "2:25-2:49", Method, |def| {
|
|
2436
|
+
assert_def_str_eq!(&context, def, "instance_method()");
|
|
2437
|
+
assert!(def.receiver().is_none());
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
#[test]
|
|
2442
|
+
fn index_private_class_method_array_not_sole_arg_diagnostic() {
|
|
2443
|
+
let context = index_source(
|
|
2444
|
+
r"
|
|
2445
|
+
class Foo
|
|
2446
|
+
def self.a; end
|
|
2447
|
+
def self.b; end
|
|
2448
|
+
|
|
2449
|
+
private_class_method [:a], :b
|
|
2450
|
+
end
|
|
2451
|
+
",
|
|
2452
|
+
);
|
|
2453
|
+
|
|
2454
|
+
assert_local_diagnostics_eq!(
|
|
2455
|
+
&context,
|
|
2456
|
+
vec![
|
|
2457
|
+
"invalid-method-visibility: `private_class_method` array argument must be the only argument (5:24-5:28)"
|
|
2458
|
+
]
|
|
2459
|
+
);
|
|
2460
|
+
|
|
2461
|
+
assert_definition_at!(&context, "5:31-5:32", MethodVisibility, |def| {
|
|
2462
|
+
assert!(def.flags().is_singleton_method_visibility());
|
|
2463
|
+
assert_string_eq!(&context, def.str_id(), "b()");
|
|
2464
|
+
assert_eq!(def.visibility(), &Visibility::Private);
|
|
2465
|
+
});
|
|
2466
|
+
}
|
|
2309
2467
|
}
|
|
2310
2468
|
|
|
2311
2469
|
mod attr_accessor_tests {
|
|
@@ -15,7 +15,7 @@ use crate::model::name::{Name, NameRef, ParentScope, ResolvedName};
|
|
|
15
15
|
use crate::model::references::{ConstantReference, MethodRef};
|
|
16
16
|
use crate::model::string_ref::StringRef;
|
|
17
17
|
use crate::model::visibility::Visibility;
|
|
18
|
-
use crate::stats;
|
|
18
|
+
use crate::{query, stats};
|
|
19
19
|
|
|
20
20
|
/// An entity whose validity depends on a particular `NameId`.
|
|
21
21
|
/// Used as the value type in the `name_dependents` reverse index.
|
|
@@ -650,7 +650,7 @@ impl Graph {
|
|
|
650
650
|
let definitions = declaration.definitions();
|
|
651
651
|
|
|
652
652
|
match declaration {
|
|
653
|
-
Declaration::Namespace(Namespace::Class(_) | Namespace::Module(_))
|
|
653
|
+
Declaration::Namespace(Namespace::Class(_) | Namespace::Module(_) | Namespace::Todo(_))
|
|
654
654
|
| Declaration::Constant(_)
|
|
655
655
|
| Declaration::ConstantAlias(_) => {
|
|
656
656
|
for def_id in definitions.iter().rev() {
|
|
@@ -661,25 +661,42 @@ impl Graph {
|
|
|
661
661
|
Some(Visibility::Public)
|
|
662
662
|
}
|
|
663
663
|
Declaration::Method(_) => {
|
|
664
|
+
let mut latest_alias: Option<DefinitionId> = None;
|
|
665
|
+
|
|
664
666
|
for def_id in definitions.iter().rev() {
|
|
665
667
|
let Some(definition) = self.definitions.get(def_id) else {
|
|
666
668
|
continue;
|
|
667
669
|
};
|
|
670
|
+
|
|
668
671
|
let visibility = match definition {
|
|
669
672
|
Definition::MethodVisibility(vis) => Some(*vis.visibility()),
|
|
670
673
|
Definition::Method(method) => Some(*method.visibility()),
|
|
671
674
|
Definition::AttrAccessor(attr) => Some(*attr.visibility()),
|
|
672
675
|
Definition::AttrReader(attr) => Some(*attr.visibility()),
|
|
673
676
|
Definition::AttrWriter(attr) => Some(*attr.visibility()),
|
|
677
|
+
Definition::MethodAlias(_) => {
|
|
678
|
+
if latest_alias.is_none() {
|
|
679
|
+
latest_alias = Some(*def_id);
|
|
680
|
+
}
|
|
681
|
+
None
|
|
682
|
+
}
|
|
674
683
|
_ => None,
|
|
675
684
|
};
|
|
685
|
+
|
|
676
686
|
if visibility.is_some() {
|
|
677
687
|
return visibility;
|
|
678
688
|
}
|
|
679
689
|
}
|
|
680
|
-
|
|
690
|
+
|
|
691
|
+
if let Some(alias_def_id) = latest_alias
|
|
692
|
+
&& let Ok(target_id) = query::follow_method_alias(self, alias_def_id)
|
|
693
|
+
{
|
|
694
|
+
return self.visibility(&target_id);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
Some(Visibility::Public)
|
|
681
698
|
}
|
|
682
|
-
Declaration::Namespace(Namespace::SingletonClass(_)
|
|
699
|
+
Declaration::Namespace(Namespace::SingletonClass(_))
|
|
683
700
|
| Declaration::GlobalVariable(_)
|
|
684
701
|
| Declaration::InstanceVariable(_)
|
|
685
702
|
| Declaration::ClassVariable(_) => None,
|
|
@@ -5460,4 +5460,45 @@ mod visibility_resolution_tests {
|
|
|
5460
5460
|
assert_no_diagnostics!(&context);
|
|
5461
5461
|
assert_visibility_eq!(context, "Foo::<Foo>#missing()", Visibility::Private);
|
|
5462
5462
|
}
|
|
5463
|
+
|
|
5464
|
+
#[test]
|
|
5465
|
+
fn retroactive_singleton_method_visibility_inline_def() {
|
|
5466
|
+
let mut context = GraphTest::new();
|
|
5467
|
+
context.index_uri(
|
|
5468
|
+
"file:///foo.rb",
|
|
5469
|
+
r"
|
|
5470
|
+
class Foo
|
|
5471
|
+
private_class_method def self.bar; end
|
|
5472
|
+
end
|
|
5473
|
+
",
|
|
5474
|
+
);
|
|
5475
|
+
context.resolve();
|
|
5476
|
+
|
|
5477
|
+
assert_no_diagnostics!(&context);
|
|
5478
|
+
assert_visibility_eq!(context, "Foo::<Foo>#bar()", Visibility::Private);
|
|
5479
|
+
}
|
|
5480
|
+
|
|
5481
|
+
#[test]
|
|
5482
|
+
fn retroactive_singleton_method_visibility_array_form() {
|
|
5483
|
+
let mut context = GraphTest::new();
|
|
5484
|
+
context.index_uri(
|
|
5485
|
+
"file:///foo.rb",
|
|
5486
|
+
r#"
|
|
5487
|
+
class Foo
|
|
5488
|
+
def self.a; end
|
|
5489
|
+
def self.b; end
|
|
5490
|
+
def self.c; end
|
|
5491
|
+
|
|
5492
|
+
private_class_method [:a, "b"]
|
|
5493
|
+
public_class_method [:c]
|
|
5494
|
+
end
|
|
5495
|
+
"#,
|
|
5496
|
+
);
|
|
5497
|
+
context.resolve();
|
|
5498
|
+
|
|
5499
|
+
assert_no_diagnostics!(&context);
|
|
5500
|
+
assert_visibility_eq!(context, "Foo::<Foo>#a()", Visibility::Private);
|
|
5501
|
+
assert_visibility_eq!(context, "Foo::<Foo>#b()", Visibility::Private);
|
|
5502
|
+
assert_visibility_eq!(context, "Foo::<Foo>#c()", Visibility::Public);
|
|
5503
|
+
}
|
|
5463
5504
|
}
|
data/rust/rubydex-mcp/Cargo.toml
CHANGED
|
@@ -12,7 +12,7 @@ path = "src/main.rs"
|
|
|
12
12
|
[dependencies]
|
|
13
13
|
rubydex = { path = "../rubydex" }
|
|
14
14
|
clap = { version = "4.5.16", features = ["derive"] }
|
|
15
|
-
rmcp = { version = "
|
|
15
|
+
rmcp = { version = "1.4", features = ["server", "macros", "transport-io", "schemars"] }
|
|
16
16
|
tokio = { version = "1", features = ["macros", "rt", "io-std"] }
|
|
17
17
|
serde = { version = "1", features = ["derive"] }
|
|
18
18
|
serde_json = "1"
|
|
@@ -565,14 +565,13 @@ Pagination: tools that may return a high number of results include `total` for p
|
|
|
565
565
|
|
|
566
566
|
Use Grep instead for: literal string search, log messages, comments, non-Ruby files, or content search rather than structural queries."#;
|
|
567
567
|
|
|
568
|
-
#[tool_handler]
|
|
568
|
+
#[tool_handler(router = self.tool_router)]
|
|
569
569
|
impl ServerHandler for RubydexServer {
|
|
570
570
|
fn get_info(&self) -> ServerInfo {
|
|
571
|
-
ServerInfo
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
571
|
+
let mut info = ServerInfo::default();
|
|
572
|
+
info.instructions = Some(SERVER_INSTRUCTIONS.into());
|
|
573
|
+
info.capabilities = ServerCapabilities::builder().enable_tools().build();
|
|
574
|
+
info
|
|
576
575
|
}
|
|
577
576
|
}
|
|
578
577
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//! This file provides the C API for Definition accessors
|
|
2
2
|
|
|
3
|
+
use crate::declaration_api::CDeclaration;
|
|
3
4
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
4
5
|
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
5
6
|
use crate::reference_api::CConstantReference;
|
|
@@ -250,6 +251,31 @@ pub unsafe extern "C" fn rdx_definition_location(pointer: GraphPointer, definiti
|
|
|
250
251
|
})
|
|
251
252
|
}
|
|
252
253
|
|
|
254
|
+
/// Returns the declaration that the given definition belongs to. Returns NULL when the definition has no associated
|
|
255
|
+
/// declaration (for example, before resolution has run or when the declaration cannot be located). Caller must free
|
|
256
|
+
/// with `free_c_declaration`.
|
|
257
|
+
///
|
|
258
|
+
/// # Safety
|
|
259
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
260
|
+
/// - `definition_id` must be a valid definition id.
|
|
261
|
+
///
|
|
262
|
+
/// # Panics
|
|
263
|
+
/// This function will panic if the definition cannot be found.
|
|
264
|
+
#[unsafe(no_mangle)]
|
|
265
|
+
pub unsafe extern "C" fn rdx_definition_declaration(pointer: GraphPointer, definition_id: u64) -> *const CDeclaration {
|
|
266
|
+
with_graph(pointer, |graph| {
|
|
267
|
+
let def_id = DefinitionId::new(definition_id);
|
|
268
|
+
let Some(decl_id) = graph.definition_id_to_declaration_id(def_id) else {
|
|
269
|
+
return ptr::null();
|
|
270
|
+
};
|
|
271
|
+
let Some(decl) = graph.declarations().get(decl_id) else {
|
|
272
|
+
return ptr::null();
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
Box::into_raw(Box::new(CDeclaration::from_declaration(*decl_id, decl))).cast_const()
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
|
|
253
279
|
/// Creates a new iterator over definition IDs for a given declaration by snapshotting the current set of IDs.
|
|
254
280
|
///
|
|
255
281
|
/// # Panics
|
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.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-26 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
|
|
@@ -59,6 +59,7 @@ files:
|
|
|
59
59
|
- lib/rubydex/librubydex_sys.so
|
|
60
60
|
- lib/rubydex/location.rb
|
|
61
61
|
- lib/rubydex/mixin.rb
|
|
62
|
+
- lib/rubydex/reference.rb
|
|
62
63
|
- lib/rubydex/signature.rb
|
|
63
64
|
- lib/rubydex/version.rb
|
|
64
65
|
- rbi/rubydex.rbi
|