rubydex 0.3.0 → 0.4.1
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 +29 -7
- data/THIRD_PARTY_LICENSES.html +238 -2
- data/exe/rdx +2 -149
- data/ext/rubydex/config.c +140 -0
- data/ext/rubydex/config.h +16 -0
- data/ext/rubydex/definition.c +34 -0
- data/ext/rubydex/definition.h +3 -0
- data/ext/rubydex/diagnostic.c +28 -1
- data/ext/rubydex/diagnostic.h +2 -0
- data/ext/rubydex/extconf.rb +4 -2
- data/ext/rubydex/graph.c +71 -55
- data/ext/rubydex/graph.h +6 -0
- data/ext/rubydex/query.c +398 -16
- data/ext/rubydex/rubydex.c +2 -0
- data/ext/rubydex/utils.c +11 -4
- 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 +76 -0
- data/lib/rubydex/cli/command/lint.rb +208 -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/rules/dynamic_ancestor.rb +29 -0
- data/lib/rubydex/rules/dynamic_constant_reference.rb +25 -0
- data/lib/rubydex/rules/dynamic_singleton_definition.rb +30 -0
- data/lib/rubydex/rules/invalid_constant_visibility.rb +28 -0
- data/lib/rubydex/rules/invalid_method_visibility.rb +28 -0
- data/lib/rubydex/rules/parse_error.rb +25 -0
- data/lib/rubydex/rules/parse_warning.rb +28 -0
- data/lib/rubydex/rules/top_level_mixin_self.rb +27 -0
- data/lib/rubydex/rules/undefined_constant_visibility_target.rb +27 -0
- data/lib/rubydex/rules/undefined_method_visibility_target.rb +27 -0
- data/lib/rubydex/severity.rb +70 -0
- data/lib/rubydex/skill.rb +89 -0
- data/lib/rubydex/skill_registry.rb +62 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +8 -0
- data/lib/rubydex_linter/rules/rule_structure.rb +140 -0
- data/rbi/rubydex.rbi +464 -21
- data/rust/Cargo.lock +2 -2
- data/rust/rubydex/Cargo.toml +5 -1
- data/rust/rubydex/benches/graph_memory.rs +3 -5
- data/rust/rubydex/src/bin/generate_ruby_rules.rs +94 -0
- data/rust/rubydex/src/config.rs +538 -157
- data/rust/rubydex/src/diagnostic.rs +162 -45
- 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 +270 -6
- data/rust/rubydex/src/indexing/ruby_indexer.rs +10 -12
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +134 -81
- data/rust/rubydex/src/lib.rs +1 -0
- data/rust/rubydex/src/listing.rs +26 -1
- data/rust/rubydex/src/main.rs +7 -4
- data/rust/rubydex/src/model/declaration.rs +302 -219
- data/rust/rubydex/src/model/graph.rs +27 -40
- data/rust/rubydex/src/model/name.rs +58 -17
- data/rust/rubydex/src/operation/ruby_builder.rs +30 -45
- data/rust/rubydex/src/path_helpers.rs +77 -0
- data/rust/rubydex/src/query/cypher/schema.rs +63 -0
- data/rust/rubydex/src/query/cypher/tests.rs +26 -1
- data/rust/rubydex/src/query/cypher.rs +8 -11
- data/rust/rubydex/src/query.rs +314 -44
- data/rust/rubydex/src/resolution.rs +139 -187
- data/rust/rubydex/src/resolution_tests.rs +247 -19
- 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/definition_api.rs +68 -1
- data/rust/rubydex-sys/src/diagnostic_api.rs +42 -8
- data/rust/rubydex-sys/src/graph_api.rs +125 -205
- data/rust/rubydex-sys/src/lib.rs +2 -0
- data/rust/rubydex-sys/src/name_api.rs +49 -17
- data/rust/rubydex-sys/src/utils.rs +37 -0
- data/skills/send-private-method/SKILL.md +133 -0
- metadata +42 -2
|
@@ -8,7 +8,7 @@ use crate::{
|
|
|
8
8
|
assert_declaration_exists, assert_declaration_kind_eq, assert_declaration_references_count_eq, assert_descendants,
|
|
9
9
|
assert_diagnostics_eq, assert_instance_variables_eq, assert_members_eq, assert_no_constant_alias_target,
|
|
10
10
|
assert_no_diagnostics, assert_no_members, assert_owner_eq, assert_singleton_class_eq,
|
|
11
|
-
diagnostic::Rule,
|
|
11
|
+
diagnostic::{Rule, Severity},
|
|
12
12
|
model::{declaration::Ancestors, ids::DeclarationId, name::NameRef},
|
|
13
13
|
test_utils::GraphTest,
|
|
14
14
|
};
|
|
@@ -1494,6 +1494,43 @@ mod include_tests {
|
|
|
1494
1494
|
assert_descendants!(context, "Bar", ["Baz"]);
|
|
1495
1495
|
assert_descendants!(context, "Foo", ["Bar", "Baz"]);
|
|
1496
1496
|
}
|
|
1497
|
+
|
|
1498
|
+
#[test]
|
|
1499
|
+
fn unresolved_include_followed_by_resolved_include_stays_partial() {
|
|
1500
|
+
let mut context = graph_test();
|
|
1501
|
+
context.index_uri("file:///foo.rb", {
|
|
1502
|
+
r"
|
|
1503
|
+
module M
|
|
1504
|
+
end
|
|
1505
|
+
|
|
1506
|
+
class C
|
|
1507
|
+
include Missing
|
|
1508
|
+
include M
|
|
1509
|
+
end
|
|
1510
|
+
"
|
|
1511
|
+
});
|
|
1512
|
+
context.resolve();
|
|
1513
|
+
|
|
1514
|
+
assert_ancestors_eq!(
|
|
1515
|
+
context,
|
|
1516
|
+
"C",
|
|
1517
|
+
["C", "M", Partial("Missing"), "Object", "Kernel", "BasicObject"]
|
|
1518
|
+
);
|
|
1519
|
+
assert!(
|
|
1520
|
+
matches!(
|
|
1521
|
+
context
|
|
1522
|
+
.graph()
|
|
1523
|
+
.declarations()
|
|
1524
|
+
.get(&DeclarationId::from("C"))
|
|
1525
|
+
.unwrap()
|
|
1526
|
+
.as_namespace()
|
|
1527
|
+
.unwrap()
|
|
1528
|
+
.ancestors(),
|
|
1529
|
+
Ancestors::Partial(_)
|
|
1530
|
+
),
|
|
1531
|
+
"C should have a partial chain: the `Missing` include never resolves"
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1497
1534
|
}
|
|
1498
1535
|
|
|
1499
1536
|
mod prepend_tests {
|
|
@@ -2132,6 +2169,30 @@ mod object_ancestors_tests {
|
|
|
2132
2169
|
assert_constant_reference_to!(context, "Kernel::FOUND_ME", "file:///foo.rb:11:3-11:11");
|
|
2133
2170
|
assert_constant_reference_unresolved!(context, "FOUND_ME", "file:///foo.rb:14:6-14:14");
|
|
2134
2171
|
}
|
|
2172
|
+
|
|
2173
|
+
#[test]
|
|
2174
|
+
fn object_inherited_constant_inside_module_reordered() {
|
|
2175
|
+
let mut context = graph_test();
|
|
2176
|
+
context.index_uri("file:///foo.rb", {
|
|
2177
|
+
r"
|
|
2178
|
+
module Foo
|
|
2179
|
+
# Accessible via Object inheritance
|
|
2180
|
+
FOUND_ME
|
|
2181
|
+
end
|
|
2182
|
+
|
|
2183
|
+
module Kernel
|
|
2184
|
+
FOUND_ME = true
|
|
2185
|
+
end
|
|
2186
|
+
|
|
2187
|
+
class Object
|
|
2188
|
+
include Kernel
|
|
2189
|
+
end
|
|
2190
|
+
"
|
|
2191
|
+
});
|
|
2192
|
+
context.resolve();
|
|
2193
|
+
|
|
2194
|
+
assert_constant_reference_to!(context, "Kernel::FOUND_ME", "file:///foo.rb:3:3-3:11");
|
|
2195
|
+
}
|
|
2135
2196
|
}
|
|
2136
2197
|
|
|
2137
2198
|
mod singleton_ancestors_tests {
|
|
@@ -3033,7 +3094,7 @@ mod variable_tests {
|
|
|
3033
3094
|
|
|
3034
3095
|
assert_diagnostics_eq!(
|
|
3035
3096
|
&context,
|
|
3036
|
-
["
|
|
3097
|
+
["DynamicSingletonDefinition: Dynamic receiver for singleton method definition (2:3-4:6)",]
|
|
3037
3098
|
);
|
|
3038
3099
|
|
|
3039
3100
|
// Instance variable in method with unresolved receiver should not create a declaration
|
|
@@ -3922,6 +3983,41 @@ mod todo_tests {
|
|
|
3922
3983
|
assert_members_eq!(context, "A::B::D", vec!["d_method()"]);
|
|
3923
3984
|
}
|
|
3924
3985
|
|
|
3986
|
+
#[test]
|
|
3987
|
+
fn have_linearized_ancestors() {
|
|
3988
|
+
// Todos are namespaces, so they must be the first entry of their own ancestor chain. Member lookups walk that
|
|
3989
|
+
// chain, so an empty one makes every member of the Todo unreachable
|
|
3990
|
+
let mut context = graph_test();
|
|
3991
|
+
context.index_uri("file:///a.rb", {
|
|
3992
|
+
r"
|
|
3993
|
+
class A::B::C
|
|
3994
|
+
def foo; end
|
|
3995
|
+
end
|
|
3996
|
+
"
|
|
3997
|
+
});
|
|
3998
|
+
context.index_uri("file:///d.rb", "class A::B::D < A::B::C; end");
|
|
3999
|
+
context.resolve();
|
|
4000
|
+
|
|
4001
|
+
assert_declaration_kind_eq!(context, "A", "<TODO>");
|
|
4002
|
+
assert_declaration_kind_eq!(context, "A::B", "<TODO>");
|
|
4003
|
+
assert_ancestors_eq!(context, "A", ["A"]);
|
|
4004
|
+
assert_ancestors_eq!(context, "A::B", ["A::B"]);
|
|
4005
|
+
|
|
4006
|
+
// Every member of a Todo is only reachable because the Todo lists itself in its own chain
|
|
4007
|
+
assert_members_eq!(context, "A", ["B"]);
|
|
4008
|
+
assert_members_eq!(context, "A::B", ["C", "D"]);
|
|
4009
|
+
|
|
4010
|
+
// Classes nested in a Todo still inherit from each other. Both the superclass path `A::B::C` and `D`'s own
|
|
4011
|
+
// owner chain go through the Todos
|
|
4012
|
+
assert_ancestors_eq!(
|
|
4013
|
+
context,
|
|
4014
|
+
"A::B::D",
|
|
4015
|
+
["A::B::D", "A::B::C", "Object", "Kernel", "BasicObject"]
|
|
4016
|
+
);
|
|
4017
|
+
assert_owner_eq!(context, "A::B::D", "A::B");
|
|
4018
|
+
assert_descendants!(context, "A::B::C", ["A::B::D"]);
|
|
4019
|
+
}
|
|
4020
|
+
|
|
3925
4021
|
#[test]
|
|
3926
4022
|
fn promoted_incrementally() {
|
|
3927
4023
|
// Index class A::B::C first (creates Todos), then provide real definitions.
|
|
@@ -4652,6 +4748,104 @@ mod promotability_tests {
|
|
|
4652
4748
|
assert_eq!(*receiver.declaration_id(), DeclarationId::from("ENV::<ENV>"));
|
|
4653
4749
|
}
|
|
4654
4750
|
|
|
4751
|
+
#[test]
|
|
4752
|
+
fn singleton_on_todo_is_preserved_and_relinearized_when_promoted_to_class() {
|
|
4753
|
+
let mut context = graph_test();
|
|
4754
|
+
context.index_uri("file:///placeholder.rb", "class Foo::Placeholder; end");
|
|
4755
|
+
context.resolve();
|
|
4756
|
+
|
|
4757
|
+
assert_declaration_kind_eq!(context, "Foo", "<TODO>");
|
|
4758
|
+
|
|
4759
|
+
context.index_uri("file:///value.rb", "Foo.call");
|
|
4760
|
+
context.resolve();
|
|
4761
|
+
|
|
4762
|
+
assert_singleton_class_eq!(context, "Foo", "Foo::<Foo>");
|
|
4763
|
+
|
|
4764
|
+
context.index_uri("file:///class.rb", "class Foo; end");
|
|
4765
|
+
context.resolve();
|
|
4766
|
+
|
|
4767
|
+
assert_declaration_kind_eq!(context, "Foo", "Class");
|
|
4768
|
+
assert_singleton_class_eq!(context, "Foo", "Foo::<Foo>");
|
|
4769
|
+
assert_ancestors_eq!(
|
|
4770
|
+
context,
|
|
4771
|
+
"Foo::<Foo>",
|
|
4772
|
+
[
|
|
4773
|
+
"Foo::<Foo>",
|
|
4774
|
+
"Object::<Object>",
|
|
4775
|
+
"BasicObject::<BasicObject>",
|
|
4776
|
+
"Class",
|
|
4777
|
+
"Module",
|
|
4778
|
+
"Object",
|
|
4779
|
+
"Kernel",
|
|
4780
|
+
"BasicObject"
|
|
4781
|
+
]
|
|
4782
|
+
);
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
#[test]
|
|
4786
|
+
fn singleton_on_todo_is_preserved_when_promoted_to_module() {
|
|
4787
|
+
let mut context = graph_test();
|
|
4788
|
+
context.index_uri("file:///placeholder.rb", "class Bar::Placeholder; end");
|
|
4789
|
+
context.resolve();
|
|
4790
|
+
|
|
4791
|
+
assert_declaration_kind_eq!(context, "Bar", "<TODO>");
|
|
4792
|
+
|
|
4793
|
+
context.index_uri("file:///value.rb", "Bar.call");
|
|
4794
|
+
context.resolve();
|
|
4795
|
+
|
|
4796
|
+
assert_singleton_class_eq!(context, "Bar", "Bar::<Bar>");
|
|
4797
|
+
|
|
4798
|
+
context.index_uri("file:///module.rb", "module Bar; end");
|
|
4799
|
+
context.resolve();
|
|
4800
|
+
|
|
4801
|
+
assert_declaration_kind_eq!(context, "Bar", "Module");
|
|
4802
|
+
assert_singleton_class_eq!(context, "Bar", "Bar::<Bar>");
|
|
4803
|
+
assert_ancestors_eq!(
|
|
4804
|
+
context,
|
|
4805
|
+
"Bar::<Bar>",
|
|
4806
|
+
["Bar::<Bar>", "Module", "Object", "Kernel", "BasicObject"]
|
|
4807
|
+
);
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4810
|
+
#[test]
|
|
4811
|
+
fn higher_order_singleton_on_todo_is_relinearized_when_promoted_to_class() {
|
|
4812
|
+
let mut context = graph_test();
|
|
4813
|
+
context.index_uri("file:///placeholder.rb", "class Foo::Placeholder; end");
|
|
4814
|
+
context.resolve();
|
|
4815
|
+
|
|
4816
|
+
context.index_uri("file:///value.rb", {
|
|
4817
|
+
r"
|
|
4818
|
+
class << Foo
|
|
4819
|
+
class << self
|
|
4820
|
+
end
|
|
4821
|
+
end
|
|
4822
|
+
"
|
|
4823
|
+
});
|
|
4824
|
+
context.resolve();
|
|
4825
|
+
|
|
4826
|
+
context.index_uri("file:///class.rb", "class Foo; end");
|
|
4827
|
+
context.resolve();
|
|
4828
|
+
|
|
4829
|
+
assert_ancestors_eq!(
|
|
4830
|
+
context,
|
|
4831
|
+
"Foo::<Foo>::<<Foo>>",
|
|
4832
|
+
[
|
|
4833
|
+
"Foo::<Foo>::<<Foo>>",
|
|
4834
|
+
"Object::<Object>::<<Object>>",
|
|
4835
|
+
"BasicObject::<BasicObject>::<<BasicObject>>",
|
|
4836
|
+
"Class::<Class>",
|
|
4837
|
+
"Module::<Module>",
|
|
4838
|
+
"Object::<Object>",
|
|
4839
|
+
"BasicObject::<BasicObject>",
|
|
4840
|
+
"Class",
|
|
4841
|
+
"Module",
|
|
4842
|
+
"Object",
|
|
4843
|
+
"Kernel",
|
|
4844
|
+
"BasicObject"
|
|
4845
|
+
]
|
|
4846
|
+
);
|
|
4847
|
+
}
|
|
4848
|
+
|
|
4655
4849
|
#[test]
|
|
4656
4850
|
fn ivar_defined_inside_of_undefined_alias_namespace() {
|
|
4657
4851
|
let mut context = graph_test();
|
|
@@ -5024,6 +5218,38 @@ mod rbs_tests {
|
|
|
5024
5218
|
);
|
|
5025
5219
|
}
|
|
5026
5220
|
|
|
5221
|
+
#[test]
|
|
5222
|
+
fn rbs_attributes_create_method_declarations_without_instance_variable_declarations() {
|
|
5223
|
+
let mut context = graph_test();
|
|
5224
|
+
context.index_rbs_uri("file:///attributes.rbs", {
|
|
5225
|
+
r"
|
|
5226
|
+
class Foo
|
|
5227
|
+
attr_reader reader: String
|
|
5228
|
+
attr_writer writer (@writer): Integer
|
|
5229
|
+
attr_accessor accessor(): bool
|
|
5230
|
+
private attr_accessor self.class_value (@class_value): Symbol
|
|
5231
|
+
end
|
|
5232
|
+
"
|
|
5233
|
+
});
|
|
5234
|
+
context.resolve();
|
|
5235
|
+
|
|
5236
|
+
assert_no_diagnostics!(&context);
|
|
5237
|
+
for method in [
|
|
5238
|
+
"Foo#reader()",
|
|
5239
|
+
"Foo#writer=()",
|
|
5240
|
+
"Foo#accessor()",
|
|
5241
|
+
"Foo#accessor=()",
|
|
5242
|
+
"Foo::<Foo>#class_value()",
|
|
5243
|
+
"Foo::<Foo>#class_value=()",
|
|
5244
|
+
] {
|
|
5245
|
+
assert_declaration_exists!(context, method);
|
|
5246
|
+
assert_declaration_kind_eq!(context, method, "Method");
|
|
5247
|
+
}
|
|
5248
|
+
for instance_variable in ["Foo#@reader", "Foo#@writer", "Foo::<Foo>#@class_value"] {
|
|
5249
|
+
assert_declaration_does_not_exist!(context, instance_variable);
|
|
5250
|
+
}
|
|
5251
|
+
}
|
|
5252
|
+
|
|
5027
5253
|
#[test]
|
|
5028
5254
|
fn rbs_mixin_resolution() {
|
|
5029
5255
|
let mut context = graph_test();
|
|
@@ -5263,8 +5489,9 @@ mod visibility_resolution_tests {
|
|
|
5263
5489
|
assert_diagnostics_eq!(
|
|
5264
5490
|
context,
|
|
5265
5491
|
&[
|
|
5266
|
-
"
|
|
5267
|
-
]
|
|
5492
|
+
"UndefinedMethodVisibilityTarget: undefined method `Foo#nonexistent()` for visibility change (2:12-2:23)"
|
|
5493
|
+
],
|
|
5494
|
+
severity: Severity::Warning
|
|
5268
5495
|
);
|
|
5269
5496
|
}
|
|
5270
5497
|
|
|
@@ -5398,9 +5625,10 @@ mod visibility_resolution_tests {
|
|
|
5398
5625
|
assert_diagnostics_eq!(
|
|
5399
5626
|
context,
|
|
5400
5627
|
&[
|
|
5401
|
-
"
|
|
5402
|
-
"
|
|
5403
|
-
]
|
|
5628
|
+
"UndefinedConstantVisibilityTarget: undefined constant `NOPE_ONE` for visibility change in `Foo` (2:21-2:29)",
|
|
5629
|
+
"UndefinedConstantVisibilityTarget: undefined constant `NOPE_TWO` for visibility change in `Foo` (2:32-2:40)",
|
|
5630
|
+
],
|
|
5631
|
+
severity: Severity::Warning
|
|
5404
5632
|
);
|
|
5405
5633
|
}
|
|
5406
5634
|
|
|
@@ -5424,7 +5652,7 @@ mod visibility_resolution_tests {
|
|
|
5424
5652
|
assert_diagnostics_eq!(
|
|
5425
5653
|
context,
|
|
5426
5654
|
&[
|
|
5427
|
-
"
|
|
5655
|
+
"UndefinedConstantVisibilityTarget: undefined constant `CONST` for visibility change in `Child` (6:21-6:26)"
|
|
5428
5656
|
]
|
|
5429
5657
|
);
|
|
5430
5658
|
assert_visibility_eq!(context, "Parent::CONST", Visibility::Public);
|
|
@@ -5566,7 +5794,7 @@ mod visibility_resolution_tests {
|
|
|
5566
5794
|
assert_diagnostics_eq!(
|
|
5567
5795
|
context,
|
|
5568
5796
|
&[
|
|
5569
|
-
"
|
|
5797
|
+
"UndefinedMethodVisibilityTarget: undefined method `Foo::<Foo>#nonexistent()` for visibility change (2:25-2:36)"
|
|
5570
5798
|
]
|
|
5571
5799
|
);
|
|
5572
5800
|
}
|
|
@@ -5594,7 +5822,7 @@ mod visibility_resolution_tests {
|
|
|
5594
5822
|
assert_diagnostics_eq!(
|
|
5595
5823
|
context,
|
|
5596
5824
|
&[
|
|
5597
|
-
"
|
|
5825
|
+
"UndefinedMethodVisibilityTarget: undefined method `Foo::<Foo>#missing()` for visibility change (2:25-2:32)"
|
|
5598
5826
|
]
|
|
5599
5827
|
);
|
|
5600
5828
|
|
|
@@ -5620,7 +5848,7 @@ mod visibility_resolution_tests {
|
|
|
5620
5848
|
assert_diagnostics_eq!(
|
|
5621
5849
|
context,
|
|
5622
5850
|
&[
|
|
5623
|
-
"
|
|
5851
|
+
"UndefinedMethodVisibilityTarget: undefined method `Foo::<Foo>#missing()` for visibility change (2:25-2:32)"
|
|
5624
5852
|
]
|
|
5625
5853
|
);
|
|
5626
5854
|
|
|
@@ -5641,7 +5869,7 @@ mod visibility_resolution_tests {
|
|
|
5641
5869
|
|
|
5642
5870
|
#[test]
|
|
5643
5871
|
fn retroactive_singleton_method_visibility_inline_def() {
|
|
5644
|
-
let mut context =
|
|
5872
|
+
let mut context = graph_test();
|
|
5645
5873
|
context.index_uri(
|
|
5646
5874
|
"file:///foo.rb",
|
|
5647
5875
|
r"
|
|
@@ -5658,7 +5886,7 @@ mod visibility_resolution_tests {
|
|
|
5658
5886
|
|
|
5659
5887
|
#[test]
|
|
5660
5888
|
fn retroactive_singleton_method_visibility_array_form() {
|
|
5661
|
-
let mut context =
|
|
5889
|
+
let mut context = graph_test();
|
|
5662
5890
|
context.index_uri(
|
|
5663
5891
|
"file:///foo.rb",
|
|
5664
5892
|
r#"
|
|
@@ -5682,7 +5910,7 @@ mod visibility_resolution_tests {
|
|
|
5682
5910
|
|
|
5683
5911
|
#[test]
|
|
5684
5912
|
fn inline_module_function() {
|
|
5685
|
-
let mut context =
|
|
5913
|
+
let mut context = graph_test();
|
|
5686
5914
|
context.index_uri(
|
|
5687
5915
|
"file:///foo.rb",
|
|
5688
5916
|
r"
|
|
@@ -5722,7 +5950,7 @@ mod visibility_resolution_tests {
|
|
|
5722
5950
|
|
|
5723
5951
|
#[test]
|
|
5724
5952
|
fn retroactive_module_function() {
|
|
5725
|
-
let mut context =
|
|
5953
|
+
let mut context = graph_test();
|
|
5726
5954
|
context.index_uri(
|
|
5727
5955
|
"file:///foo.rb",
|
|
5728
5956
|
r"
|
|
@@ -5746,7 +5974,7 @@ mod visibility_resolution_tests {
|
|
|
5746
5974
|
|
|
5747
5975
|
#[test]
|
|
5748
5976
|
fn retroactive_module_function_undefined_target_emits_single_diagnostic() {
|
|
5749
|
-
let mut context =
|
|
5977
|
+
let mut context = graph_test();
|
|
5750
5978
|
context.index_uri(
|
|
5751
5979
|
"file:///foo.rb",
|
|
5752
5980
|
r"
|
|
@@ -5760,7 +5988,7 @@ mod visibility_resolution_tests {
|
|
|
5760
5988
|
// The singleton-side def stays silent; only the instance-side def emits.
|
|
5761
5989
|
assert_diagnostics_eq!(
|
|
5762
5990
|
context,
|
|
5763
|
-
&["
|
|
5991
|
+
&["UndefinedMethodVisibilityTarget: undefined method `Foo#missing()` for visibility change (2:20-2:27)"]
|
|
5764
5992
|
);
|
|
5765
5993
|
assert_declaration_does_not_exist!(context, "Foo::<Foo>#missing()");
|
|
5766
5994
|
assert_declaration_does_not_exist!(context, "Foo::<Foo>");
|
|
@@ -5768,7 +5996,7 @@ mod visibility_resolution_tests {
|
|
|
5768
5996
|
|
|
5769
5997
|
#[test]
|
|
5770
5998
|
fn retroactive_module_function_singleton_companion_cleared_when_removed_multi_file() {
|
|
5771
|
-
let mut context =
|
|
5999
|
+
let mut context = graph_test();
|
|
5772
6000
|
context.index_uri(
|
|
5773
6001
|
"file:///a.rb",
|
|
5774
6002
|
r"
|
|
@@ -5810,7 +6038,7 @@ mod visibility_resolution_tests {
|
|
|
5810
6038
|
|
|
5811
6039
|
#[test]
|
|
5812
6040
|
fn retroactive_module_function_singleton_companion_cleared_when_removed() {
|
|
5813
|
-
let mut context =
|
|
6041
|
+
let mut context = graph_test();
|
|
5814
6042
|
context.index_uri(
|
|
5815
6043
|
"file:///foo.rb",
|
|
5816
6044
|
r"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use super::normalize_indentation;
|
|
2
|
+
use crate::path_helpers;
|
|
2
3
|
use std::fs;
|
|
3
4
|
use std::path::{Path, PathBuf};
|
|
4
5
|
use tempfile::TempDir;
|
|
@@ -37,7 +38,7 @@ impl Context {
|
|
|
37
38
|
#[must_use]
|
|
38
39
|
pub fn new() -> Self {
|
|
39
40
|
let root = tempfile::tempdir().expect("failed to create temp dir");
|
|
40
|
-
let absolute_path =
|
|
41
|
+
let absolute_path = path_helpers::resolved(root.path()).unwrap();
|
|
41
42
|
Self {
|
|
42
43
|
_root: root,
|
|
43
44
|
absolute_path,
|
|
@@ -540,18 +540,13 @@ macro_rules! assert_descendants {
|
|
|
540
540
|
.declarations()
|
|
541
541
|
.get(&$crate::model::ids::DeclarationId::from($parent))
|
|
542
542
|
.unwrap();
|
|
543
|
-
let actual =
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
$crate::model::declaration::Declaration::Namespace(
|
|
551
|
-
$crate::model::declaration::Namespace::SingletonClass(singleton),
|
|
552
|
-
) => singleton.descendants().iter().cloned().collect::<Vec<_>>(),
|
|
553
|
-
_ => panic!("Tried to get descendants for a declaration that isn't a namespace"),
|
|
554
|
-
};
|
|
543
|
+
let actual = parent
|
|
544
|
+
.as_namespace()
|
|
545
|
+
.expect("Tried to get descendants for a declaration that isn't a namespace")
|
|
546
|
+
.descendants()
|
|
547
|
+
.iter()
|
|
548
|
+
.cloned()
|
|
549
|
+
.collect::<Vec<_>>();
|
|
555
550
|
|
|
556
551
|
for descendant in &$descendants {
|
|
557
552
|
let descendant_id = $crate::model::ids::DeclarationId::from(*descendant);
|
|
@@ -667,6 +662,25 @@ macro_rules! assert_instance_variables_eq {
|
|
|
667
662
|
#[cfg(test)]
|
|
668
663
|
#[macro_export]
|
|
669
664
|
macro_rules! assert_diagnostics_eq {
|
|
665
|
+
($context:expr, $expected_diagnostics:expr, severity: $expected_severity:expr) => {{
|
|
666
|
+
let context = &$context;
|
|
667
|
+
$crate::assert_diagnostics_eq!(context, $expected_diagnostics);
|
|
668
|
+
|
|
669
|
+
let expected_severity = $expected_severity;
|
|
670
|
+
let actual_severities = context
|
|
671
|
+
.graph()
|
|
672
|
+
.all_diagnostics()
|
|
673
|
+
.iter()
|
|
674
|
+
.map(|diagnostic| diagnostic.rule().default_severity())
|
|
675
|
+
.collect::<Vec<_>>();
|
|
676
|
+
assert_eq!(
|
|
677
|
+
vec![expected_severity; actual_severities.len()],
|
|
678
|
+
actual_severities,
|
|
679
|
+
"diagnostic severities mismatch: expected all `{:?}`, got `{:?}`",
|
|
680
|
+
expected_severity,
|
|
681
|
+
actual_severities
|
|
682
|
+
);
|
|
683
|
+
}};
|
|
670
684
|
($context:expr, $expected_diagnostics:expr) => {{
|
|
671
685
|
assert_eq!($expected_diagnostics, $context.format_diagnostics(&[]).as_slice());
|
|
672
686
|
}};
|
|
@@ -557,6 +557,25 @@ macro_rules! assert_method_has_receiver {
|
|
|
557
557
|
#[cfg(test)]
|
|
558
558
|
#[macro_export]
|
|
559
559
|
macro_rules! assert_local_diagnostics_eq {
|
|
560
|
+
($context:expr, $expected_diagnostics:expr, severity: $expected_severity:expr) => {{
|
|
561
|
+
let context = &$context;
|
|
562
|
+
$crate::assert_local_diagnostics_eq!(context, $expected_diagnostics);
|
|
563
|
+
|
|
564
|
+
let expected_severity = $expected_severity;
|
|
565
|
+
let actual_severities = context
|
|
566
|
+
.graph()
|
|
567
|
+
.diagnostics()
|
|
568
|
+
.iter()
|
|
569
|
+
.map(|diagnostic| diagnostic.rule().default_severity())
|
|
570
|
+
.collect::<Vec<_>>();
|
|
571
|
+
assert_eq!(
|
|
572
|
+
vec![expected_severity; actual_severities.len()],
|
|
573
|
+
actual_severities,
|
|
574
|
+
"diagnostic severities mismatch: expected all `{:?}`, got `{:?}`",
|
|
575
|
+
expected_severity,
|
|
576
|
+
actual_severities
|
|
577
|
+
);
|
|
578
|
+
}};
|
|
560
579
|
($context:expr, $expected_diagnostics:expr) => {{
|
|
561
580
|
let mut diagnostics = $context.graph().diagnostics().iter().collect::<Vec<_>>();
|
|
562
581
|
diagnostics.sort_by_key(|d| d.offset());
|
data/rust/rubydex/tests/cli.rs
CHANGED
|
@@ -60,7 +60,7 @@ fn single_directory_argument_is_workspace_root_for_config() {
|
|
|
60
60
|
with_context(|context| {
|
|
61
61
|
context.write("included.rb", "class Included\nend\n");
|
|
62
62
|
context.write("excluded/skipped.rb", "class Skipped\nend\n");
|
|
63
|
-
context.write("rubydex.toml", "
|
|
63
|
+
context.write("rubydex.toml", "[graph]\nexclude = [\"excluded\"]\n");
|
|
64
64
|
|
|
65
65
|
rdx(&[context.absolute_path().to_str().unwrap()])
|
|
66
66
|
.success()
|
|
@@ -74,7 +74,7 @@ fn first_directory_argument_is_workspace_root_for_config() {
|
|
|
74
74
|
with_context(|context| {
|
|
75
75
|
context.write("included/kept.rb", "class Included\nend\n");
|
|
76
76
|
context.write("excluded/skipped.rb", "class Skipped\nend\n");
|
|
77
|
-
context.write("rubydex.toml", "
|
|
77
|
+
context.write("rubydex.toml", "[graph]\nexclude = [\"excluded\"]\n");
|
|
78
78
|
|
|
79
79
|
rdx(&[
|
|
80
80
|
context.absolute_path().to_str().unwrap(),
|
|
@@ -92,7 +92,7 @@ fn single_file_argument_is_not_used_as_workspace_root() {
|
|
|
92
92
|
with_context(|context| {
|
|
93
93
|
context.write("included.rb", "class Included\nend\n");
|
|
94
94
|
context.write("excluded/skipped.rb", "class Skipped\nend\n");
|
|
95
|
-
context.write("rubydex.toml", "
|
|
95
|
+
context.write("rubydex.toml", "[graph]\nexclude = [\"excluded\"]\n");
|
|
96
96
|
|
|
97
97
|
rdx(&[context.absolute_path_to("excluded/skipped.rb").to_str().unwrap()])
|
|
98
98
|
.success()
|
|
@@ -106,7 +106,7 @@ fn first_file_argument_is_not_used_as_workspace_root() {
|
|
|
106
106
|
with_context(|context| {
|
|
107
107
|
context.write("included.rb", "class Included\nend\n");
|
|
108
108
|
context.write("excluded/skipped.rb", "class Skipped\nend\n");
|
|
109
|
-
context.write("rubydex.toml", "
|
|
109
|
+
context.write("rubydex.toml", "[graph]\nexclude = [\"excluded\"]\n");
|
|
110
110
|
|
|
111
111
|
rdx(&[
|
|
112
112
|
context.absolute_path_to("included.rb").to_str().unwrap(),
|