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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 220a0eb3de71608c1daa45286224aa1f11ebd03b893564e60cfd9e7db66124c2
4
- data.tar.gz: 747ef3a246e405c236b9efcc6b2d592033025b154cdf5e9afa03006732a10303
3
+ metadata.gz: 49147264143f618ef7d2b5bbfa983e511b86123dc01548c2a4176e686a44b57e
4
+ data.tar.gz: cbd51f1380330f85dde7861c7df96cbc1db4117458952c561164eef9c511901e
5
5
  SHA512:
6
- metadata.gz: 4afa9fef910c50747666dbb3b464d86ba791e13e1a260041b9c845b32786a049b02da55a76583c98c749a4deabaa412e35fc71c45cb7da476b6058c88199fd08
7
- data.tar.gz: 851d2924ff4d895866b5663e1f144960823fe57375a20511a08378840d013f9c6bf4f7de4a1303f9a1da2ea28ee4c2376aceb848d702f41175e933ccd98c7f8f
6
+ metadata.gz: 5daa009adaef78d504f2710aac72ec36875a3a7ae169048b36e7220d984ddaf7dd562431a460a44b95530bb030a341887ccf300d14646051f722ba0cc941e9bb
7
+ data.tar.gz: adf4c9a9faf405356b64e6de927a7aa4b8499164c9cf48918683b45ab0e7825668f5505d50e0b29305292bae3db511ae6ffb6ab2e96628c1b1ecdc2076fb8b3b
@@ -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
- 0.15.0</a></li>
2960
+ 1.6.0</a></li>
2961
2961
  <li><a
2962
2962
  href=" https://github.com/modelcontextprotocol/rust-sdk/ ">rmcp
2963
- 0.15.0</a></li>
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>
@@ -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);
Binary file
Binary file
Binary file
Binary file
@@ -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
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubydex
4
+ class Reference
5
+ #: () -> Location
6
+ def location
7
+ raise NotImplementedError, "Subclasses must implement the #location method"
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubydex
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.4"
5
5
  end
data/lib/rubydex.rb CHANGED
@@ -23,3 +23,4 @@ require "rubydex/keyword_parameter"
23
23
  require "rubydex/graph"
24
24
  require "rubydex/declaration"
25
25
  require "rubydex/signature"
26
+ require "rubydex/reference"
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
- class Rubydex::SingletonClass < Rubydex::Namespace; end
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 = "0.15.0"
974
+ version = "1.4.0"
975
975
  source = "registry+https://github.com/rust-lang/crates.io-index"
976
- checksum = "1bef41ebc9ebed2c1b1d90203e9d1756091e8a00bbc3107676151f39868ca0ee"
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 = "0.15.0"
996
+ version = "1.6.0"
997
997
  source = "registry+https://github.com/rust-lang/crates.io-index"
998
- checksum = "0e88ad84b8b6237a934534a62b379a5be6388915663c0cc598ceb9b3292bbbfe"
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
- for argument in &arguments.arguments() {
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
- if let Some(value_loc) = symbol.value_loc() {
1394
- (Self::location_to_string(&value_loc), value_loc)
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(&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
- None
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(_) | Namespace::Todo(_))
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
  }
@@ -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 = "0.15", features = ["server", "macros", "transport-io", "schemars"] }
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
- instructions: Some(SERVER_INSTRUCTIONS.into()),
573
- capabilities: ServerCapabilities::builder().enable_tools().build(),
574
- ..Default::default()
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.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-08 00:00:00.000000000 Z
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