rubydex 0.2.9 → 0.4.0
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/README.md +110 -6
- data/THIRD_PARTY_LICENSES.html +271 -2
- data/exe/rdx +2 -73
- data/ext/rubydex/config.c +140 -0
- data/ext/rubydex/config.h +16 -0
- data/ext/rubydex/declaration.c +1 -1
- data/ext/rubydex/definition.c +32 -4
- data/ext/rubydex/diagnostic.c +75 -1
- data/ext/rubydex/diagnostic.h +2 -0
- data/ext/rubydex/graph.c +27 -48
- data/ext/rubydex/graph.h +6 -0
- data/ext/rubydex/query.c +487 -0
- data/ext/rubydex/query.h +8 -0
- data/ext/rubydex/reference.c +60 -0
- data/ext/rubydex/rubydex.c +4 -0
- data/ext/rubydex/utils.c +23 -4
- data/ext/rubydex/utils.h +5 -0
- data/lib/ruby_lsp/rubydex/addon.rb +211 -0
- data/lib/rubydex/cli/command/console.rb +55 -0
- data/lib/rubydex/cli/command/lint/explain.rb +74 -0
- data/lib/rubydex/cli/command/lint.rb +202 -0
- data/lib/rubydex/cli/command/mcp.rb +30 -0
- data/lib/rubydex/cli/command/query.rb +70 -0
- data/lib/rubydex/cli/command/skill.rb +69 -0
- data/lib/rubydex/cli/command.rb +168 -0
- data/lib/rubydex/cli.rb +93 -0
- data/lib/rubydex/config.rb +59 -0
- data/lib/rubydex/diagnostic.rb +12 -3
- data/lib/rubydex/errors.rb +42 -1
- data/lib/rubydex/graph.rb +10 -3
- data/lib/rubydex/linter/custom_rule.rb +97 -0
- data/lib/rubydex/linter/helpers/path_helpers.rb +78 -0
- data/lib/rubydex/linter/helpers/source_access_helpers.rb +31 -0
- data/lib/rubydex/linter/rule_loader.rb +36 -0
- data/lib/rubydex/linter/rule_test_case.rb +343 -0
- data/lib/rubydex/linter/runner.rb +56 -0
- data/lib/rubydex/linter.rb +19 -0
- data/lib/rubydex/location.rb +3 -0
- data/lib/rubydex/mcp_server.rb +1 -2
- data/lib/rubydex/related_information.rb +17 -0
- data/lib/rubydex/rule.rb +33 -0
- data/lib/rubydex/severity.rb +70 -0
- data/lib/rubydex/skill.rb +88 -0
- data/lib/rubydex/skill_registry.rb +62 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +6 -0
- data/lib/rubydex_linter/rules/rule_structure.rb +125 -0
- data/rbi/rubydex.rbi +578 -15
- data/rust/Cargo.lock +7 -0
- data/rust/rubydex/Cargo.toml +1 -0
- data/rust/rubydex/benches/graph_memory.rs +20 -4
- data/rust/rubydex/src/compile_assertions.rs +15 -0
- data/rust/rubydex/src/config.rs +538 -157
- data/rust/rubydex/src/diagnostic.rs +66 -40
- data/rust/rubydex/src/errors.rs +0 -1
- data/rust/rubydex/src/indexing/local_graph.rs +6 -5
- data/rust/rubydex/src/indexing/rbs_indexer.rs +284 -8
- data/rust/rubydex/src/indexing/ruby_indexer.rs +59 -70
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +195 -86
- data/rust/rubydex/src/lib.rs +1 -0
- data/rust/rubydex/src/listing.rs +26 -1
- data/rust/rubydex/src/main.rs +9 -128
- data/rust/rubydex/src/model/declaration.rs +301 -229
- data/rust/rubydex/src/model/definitions.rs +27 -26
- data/rust/rubydex/src/model/document.rs +43 -7
- data/rust/rubydex/src/model/graph.rs +67 -68
- data/rust/rubydex/src/model/id.rs +55 -0
- data/rust/rubydex/src/model/ids.rs +21 -9
- data/rust/rubydex/src/model/name.rs +88 -19
- data/rust/rubydex/src/model/references.rs +16 -13
- data/rust/rubydex/src/operation/ruby_builder.rs +78 -104
- data/rust/rubydex/src/path_helpers.rs +77 -0
- data/rust/rubydex/src/query/cypher/schema.rs +853 -0
- data/rust/rubydex/src/query/cypher/schema_info.rs +161 -0
- data/rust/rubydex/src/query/cypher/tests.rs +253 -0
- data/rust/rubydex/src/query/cypher.rs +54 -0
- data/rust/rubydex/src/query.rs +125 -43
- data/rust/rubydex/src/resolution.rs +368 -395
- data/rust/rubydex/src/resolution_tests.rs +504 -78
- data/rust/rubydex/src/test_utils/context.rs +2 -1
- data/rust/rubydex/src/test_utils/graph_test.rs +26 -12
- data/rust/rubydex/src/test_utils/local_graph_test.rs +19 -0
- data/rust/rubydex/tests/cli.rs +4 -4
- data/rust/rubydex-sys/src/config_api.rs +205 -0
- data/rust/rubydex-sys/src/cypher_api.rs +791 -0
- data/rust/rubydex-sys/src/declaration_api.rs +6 -3
- data/rust/rubydex-sys/src/definition_api.rs +27 -7
- data/rust/rubydex-sys/src/diagnostic_api.rs +77 -8
- data/rust/rubydex-sys/src/graph_api.rs +31 -68
- data/rust/rubydex-sys/src/lib.rs +2 -0
- data/rust/rubydex-sys/src/name_api.rs +2 -6
- data/rust/rubydex-sys/src/reference_api.rs +58 -12
- data/rust/rubydex-sys/src/utils.rs +37 -0
- data/skills/send-private-method/SKILL.md +133 -0
- metadata +37 -2
|
@@ -12,7 +12,7 @@ use crate::model::definitions::{
|
|
|
12
12
|
};
|
|
13
13
|
use crate::model::document::Document;
|
|
14
14
|
use crate::model::ids::{DefinitionId, NameId, StringId, UriId};
|
|
15
|
-
use crate::model::name::
|
|
15
|
+
use crate::model::name::ParentScope;
|
|
16
16
|
use crate::model::references::{ConstantReference, MethodRef};
|
|
17
17
|
use crate::model::visibility::Visibility;
|
|
18
18
|
use crate::offset::Offset;
|
|
@@ -386,21 +386,8 @@ impl<'a> RubyIndexer<'a> {
|
|
|
386
386
|
{
|
|
387
387
|
if let Some(arguments) = node.arguments() {
|
|
388
388
|
for argument in &arguments.arguments() {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
let symbol = argument.as_symbol_node().unwrap();
|
|
392
|
-
|
|
393
|
-
if let Some(value_loc) = symbol.value_loc() {
|
|
394
|
-
let name = Self::location_to_string(&value_loc);
|
|
395
|
-
f(name, value_loc);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
ruby_prism::Node::StringNode { .. } => {
|
|
399
|
-
let string = argument.as_string_node().unwrap();
|
|
400
|
-
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
401
|
-
f(name, argument.location());
|
|
402
|
-
}
|
|
403
|
-
_ => {}
|
|
389
|
+
if let Some((name, location)) = Self::extract_literal_name(&argument) {
|
|
390
|
+
f(name, location);
|
|
404
391
|
}
|
|
405
392
|
}
|
|
406
393
|
}
|
|
@@ -495,11 +482,9 @@ impl<'a> RubyIndexer<'a> {
|
|
|
495
482
|
let offset = Offset::from_prism_location(&location);
|
|
496
483
|
let name = Self::location_to_string(&location);
|
|
497
484
|
let string_id = self.local_graph.intern_string(name);
|
|
498
|
-
let name_id = self
|
|
499
|
-
|
|
500
|
-
parent_scope_id,
|
|
501
|
-
self.current_lexical_scope_name_id(),
|
|
502
|
-
));
|
|
485
|
+
let name_id = self
|
|
486
|
+
.local_graph
|
|
487
|
+
.add_name(string_id, parent_scope_id, self.current_lexical_scope_name_id());
|
|
503
488
|
|
|
504
489
|
if push_final_reference {
|
|
505
490
|
self.local_graph
|
|
@@ -700,7 +685,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
700
685
|
.intern_string(format!("{}:{}<anonymous>", self.uri_id, offset.start()));
|
|
701
686
|
|
|
702
687
|
(
|
|
703
|
-
Some(self.local_graph.add_name(
|
|
688
|
+
Some(self.local_graph.add_name(string_id, ParentScope::None, None)),
|
|
704
689
|
offset.clone(),
|
|
705
690
|
)
|
|
706
691
|
};
|
|
@@ -761,7 +746,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
761
746
|
.intern_string(format!("{}:{}<anonymous>", self.uri_id, offset.start()));
|
|
762
747
|
|
|
763
748
|
(
|
|
764
|
-
Some(self.local_graph.add_name(
|
|
749
|
+
Some(self.local_graph.add_name(string_id, ParentScope::None, None)),
|
|
765
750
|
offset.clone(),
|
|
766
751
|
)
|
|
767
752
|
};
|
|
@@ -982,7 +967,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
982
967
|
}
|
|
983
968
|
|
|
984
969
|
Some((
|
|
985
|
-
self.
|
|
970
|
+
self.current_owner_name_id().unwrap(),
|
|
986
971
|
Offset::from_prism_location(&arg.location()),
|
|
987
972
|
))
|
|
988
973
|
} else if let Some(name_id) = self.index_constant_reference(&arg, false) {
|
|
@@ -1138,7 +1123,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1138
1123
|
}
|
|
1139
1124
|
None => {
|
|
1140
1125
|
let str_id = self.local_graph.intern_string("Object".into());
|
|
1141
|
-
Some(self.local_graph.add_name(
|
|
1126
|
+
Some(self.local_graph.add_name(str_id, ParentScope::None, None))
|
|
1142
1127
|
}
|
|
1143
1128
|
}
|
|
1144
1129
|
}
|
|
@@ -1182,7 +1167,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1182
1167
|
let string_id = self.local_graph.intern_string(singleton_class_name);
|
|
1183
1168
|
let new_name_id = self
|
|
1184
1169
|
.local_graph
|
|
1185
|
-
.add_name(
|
|
1170
|
+
.add_name(string_id, ParentScope::Attached(name_id), None);
|
|
1186
1171
|
|
|
1187
1172
|
let location = receiver.map_or(fallback_location, ruby_prism::Node::location);
|
|
1188
1173
|
let offset = Offset::from_prism_location(&location);
|
|
@@ -1193,10 +1178,11 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1193
1178
|
|
|
1194
1179
|
fn handle_constant_visibility(&mut self, node: &ruby_prism::CallNode, visibility: Visibility) {
|
|
1195
1180
|
let receiver = node.receiver();
|
|
1181
|
+
let call_name = String::from_utf8_lossy(node.name().as_slice());
|
|
1196
1182
|
|
|
1197
|
-
let receiver_name_id = match receiver {
|
|
1183
|
+
let receiver_name_id = match &receiver {
|
|
1198
1184
|
Some(ruby_prism::Node::ConstantPathNode { .. } | ruby_prism::Node::ConstantReadNode { .. }) => {
|
|
1199
|
-
self.index_constant_reference(
|
|
1185
|
+
self.index_constant_reference(receiver.as_ref().unwrap(), true)
|
|
1200
1186
|
}
|
|
1201
1187
|
Some(ruby_prism::Node::SelfNode { .. }) | None => match self.nesting_stack.last() {
|
|
1202
1188
|
Some(Nesting::Method(_)) => {
|
|
@@ -1205,20 +1191,20 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1205
1191
|
}
|
|
1206
1192
|
None => {
|
|
1207
1193
|
self.local_graph.add_diagnostic(
|
|
1208
|
-
Rule::
|
|
1194
|
+
Rule::InvalidConstantVisibility,
|
|
1209
1195
|
Offset::from_prism_location(&node.location()),
|
|
1210
|
-
"
|
|
1196
|
+
format!("`{call_name}` called at top level"),
|
|
1211
1197
|
);
|
|
1212
1198
|
self.visit_call_node_parts(node);
|
|
1213
1199
|
return;
|
|
1214
1200
|
}
|
|
1215
1201
|
_ => None,
|
|
1216
1202
|
},
|
|
1217
|
-
|
|
1203
|
+
Some(other) => {
|
|
1218
1204
|
self.local_graph.add_diagnostic(
|
|
1219
|
-
Rule::
|
|
1220
|
-
Offset::from_prism_location(&
|
|
1221
|
-
"Dynamic receiver for
|
|
1205
|
+
Rule::InvalidConstantVisibility,
|
|
1206
|
+
Offset::from_prism_location(&other.location()),
|
|
1207
|
+
format!("Dynamic receiver for `{call_name}`"),
|
|
1222
1208
|
);
|
|
1223
1209
|
self.visit_call_node_parts(node);
|
|
1224
1210
|
return;
|
|
@@ -1230,29 +1216,14 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1230
1216
|
};
|
|
1231
1217
|
|
|
1232
1218
|
for argument in &arguments.arguments() {
|
|
1233
|
-
let (name, location) =
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
}
|
|
1242
|
-
ruby_prism::Node::StringNode { .. } => {
|
|
1243
|
-
let string = argument.as_string_node().unwrap();
|
|
1244
|
-
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
1245
|
-
(name, argument.location())
|
|
1246
|
-
}
|
|
1247
|
-
_ => {
|
|
1248
|
-
self.local_graph.add_diagnostic(
|
|
1249
|
-
Rule::InvalidPrivateConstant,
|
|
1250
|
-
Offset::from_prism_location(&argument.location()),
|
|
1251
|
-
"Private constant called with non-symbol argument".to_string(),
|
|
1252
|
-
);
|
|
1253
|
-
self.visit(&argument);
|
|
1254
|
-
continue;
|
|
1255
|
-
}
|
|
1219
|
+
let Some((name, location)) = Self::extract_literal_name(&argument) else {
|
|
1220
|
+
self.local_graph.add_diagnostic(
|
|
1221
|
+
Rule::InvalidConstantVisibility,
|
|
1222
|
+
Offset::from_prism_location(&argument.location()),
|
|
1223
|
+
format!("`{call_name}` called with a non-literal argument"),
|
|
1224
|
+
);
|
|
1225
|
+
self.visit(&argument);
|
|
1226
|
+
continue;
|
|
1256
1227
|
};
|
|
1257
1228
|
|
|
1258
1229
|
let str_id = self.local_graph.intern_string(name);
|
|
@@ -1414,6 +1385,22 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1414
1385
|
}
|
|
1415
1386
|
}
|
|
1416
1387
|
|
|
1388
|
+
fn extract_literal_name<'b>(arg: &ruby_prism::Node<'b>) -> Option<(String, ruby_prism::Location<'b>)> {
|
|
1389
|
+
match arg {
|
|
1390
|
+
ruby_prism::Node::SymbolNode { .. } => {
|
|
1391
|
+
let symbol = arg.as_symbol_node().unwrap();
|
|
1392
|
+
let value_loc = symbol.value_loc()?;
|
|
1393
|
+
Some((Self::location_to_string(&value_loc), value_loc))
|
|
1394
|
+
}
|
|
1395
|
+
ruby_prism::Node::StringNode { .. } => {
|
|
1396
|
+
let string = arg.as_string_node().unwrap();
|
|
1397
|
+
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
1398
|
+
Some((name, arg.location()))
|
|
1399
|
+
}
|
|
1400
|
+
_ => None,
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1417
1404
|
fn is_attr_call(arg: &ruby_prism::Node) -> bool {
|
|
1418
1405
|
arg.as_call_node().is_some_and(|call| {
|
|
1419
1406
|
let receiver = call.receiver();
|
|
@@ -1452,6 +1439,18 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1452
1439
|
ruby_prism::Node::SymbolNode { .. } | ruby_prism::Node::StringNode { .. }
|
|
1453
1440
|
) {
|
|
1454
1441
|
self.create_method_visibility_definition(&arg, visibility, DefinitionFlags::empty());
|
|
1442
|
+
if visibility == Visibility::ModuleFunction {
|
|
1443
|
+
// `module_function` also creates a public singleton method, so we emit a
|
|
1444
|
+
// second def for the singleton side. The two defs stay separate (rather than
|
|
1445
|
+
// shared) so reverse-lookup invalidation can detach `Foo#bar` and
|
|
1446
|
+
// `Foo::<Foo>#bar` independently. The `SINGLETON_METHOD_VISIBILITY` flag
|
|
1447
|
+
// routes this one to the singleton class.
|
|
1448
|
+
self.create_method_visibility_definition(
|
|
1449
|
+
&arg,
|
|
1450
|
+
visibility,
|
|
1451
|
+
DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1455
1454
|
} else {
|
|
1456
1455
|
// Unsupported arg — diagnostic + visit for side effects.
|
|
1457
1456
|
let arg_offset = Offset::from_prism_location(&arg.location());
|
|
@@ -1473,18 +1472,8 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1473
1472
|
visibility: Visibility,
|
|
1474
1473
|
flags: DefinitionFlags,
|
|
1475
1474
|
) {
|
|
1476
|
-
let (name, location) =
|
|
1477
|
-
|
|
1478
|
-
let symbol = arg.as_symbol_node().unwrap();
|
|
1479
|
-
let Some(value_loc) = symbol.value_loc() else { return };
|
|
1480
|
-
(Self::location_to_string(&value_loc), value_loc)
|
|
1481
|
-
}
|
|
1482
|
-
ruby_prism::Node::StringNode { .. } => {
|
|
1483
|
-
let string = arg.as_string_node().unwrap();
|
|
1484
|
-
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
1485
|
-
(name, arg.location())
|
|
1486
|
-
}
|
|
1487
|
-
_ => return,
|
|
1475
|
+
let Some((name, location)) = Self::extract_literal_name(arg) else {
|
|
1476
|
+
return;
|
|
1488
1477
|
};
|
|
1489
1478
|
|
|
1490
1479
|
self.create_method_visibility_definition_from_name(&name, &location, visibility, flags);
|
|
@@ -1659,7 +1648,7 @@ impl Visit<'_> for RubyIndexer<'_> {
|
|
|
1659
1648
|
let nesting = self.current_lexical_scope_name_id();
|
|
1660
1649
|
let name_id = self
|
|
1661
1650
|
.local_graph
|
|
1662
|
-
.add_name(
|
|
1651
|
+
.add_name(string_id, ParentScope::Attached(attached_target), nesting);
|
|
1663
1652
|
|
|
1664
1653
|
let definition = Definition::SingletonClass(Box::new(SingletonClassDefinition::new(
|
|
1665
1654
|
name_id,
|