rubydex 0.2.2 → 0.2.3
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/definition.c +24 -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 +15 -0
- 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/resolution_tests.rs +41 -0
- 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: cb240699882969380cbd997fcdb934a8e1c69748d4089b3f99b1acd5b00f3833
|
|
4
|
+
data.tar.gz: 59cdb290dde9ba776080d43d462cce6f560ed38170015b5c0c94895168b283b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6297309256004581c2ace60666b3338f338f4ee7f634d745681f8301f6f4229d193fd03525cea3e36c8f55e9cb46aa8899c535c42d62561879781fb8b62f751f
|
|
7
|
+
data.tar.gz: b8282acdce41d58cfa479060542c93cc00976a96851d87b30c108b8aa1196b545d717296b77bda2053376f668d63ff059b23b70d90892761a18d7ec885e87547
|
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/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,6 +96,8 @@ 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
|
|
|
@@ -119,6 +125,8 @@ class Rubydex::Module < Rubydex::Namespace; end
|
|
|
119
125
|
class Rubydex::SingletonClass < Rubydex::Namespace; end
|
|
120
126
|
|
|
121
127
|
class Rubydex::Definition
|
|
128
|
+
abstract!
|
|
129
|
+
|
|
122
130
|
sig { returns(T::Array[Rubydex::Comment]) }
|
|
123
131
|
def comments; end
|
|
124
132
|
|
|
@@ -134,6 +142,9 @@ class Rubydex::Definition
|
|
|
134
142
|
sig { returns(T.nilable(Rubydex::Location)) }
|
|
135
143
|
def name_location; end
|
|
136
144
|
|
|
145
|
+
sig { returns(T.nilable(Rubydex::Declaration)) }
|
|
146
|
+
def declaration; end
|
|
147
|
+
|
|
137
148
|
class << self
|
|
138
149
|
private
|
|
139
150
|
|
|
@@ -172,6 +183,8 @@ class Rubydex::ClassDefinition < Rubydex::Definition
|
|
|
172
183
|
end
|
|
173
184
|
|
|
174
185
|
class Rubydex::Mixin
|
|
186
|
+
abstract!
|
|
187
|
+
|
|
175
188
|
sig { returns(Rubydex::ConstantReference) }
|
|
176
189
|
attr_reader :constant_reference
|
|
177
190
|
|
|
@@ -454,6 +467,8 @@ class Rubydex::MethodReference < Rubydex::Reference
|
|
|
454
467
|
end
|
|
455
468
|
|
|
456
469
|
class Rubydex::Reference
|
|
470
|
+
abstract!
|
|
471
|
+
|
|
457
472
|
class << self
|
|
458
473
|
private
|
|
459
474
|
|
|
@@ -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 {
|
|
@@ -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
|
}
|
|
@@ -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.3
|
|
5
5
|
platform: ruby
|
|
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-11 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
|
|
@@ -55,6 +55,7 @@ files:
|
|
|
55
55
|
- lib/rubydex/keyword_parameter.rb
|
|
56
56
|
- lib/rubydex/location.rb
|
|
57
57
|
- lib/rubydex/mixin.rb
|
|
58
|
+
- lib/rubydex/reference.rb
|
|
58
59
|
- lib/rubydex/signature.rb
|
|
59
60
|
- lib/rubydex/version.rb
|
|
60
61
|
- rbi/rubydex.rbi
|