rubydex 0.3.0 → 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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -7
  3. data/THIRD_PARTY_LICENSES.html +238 -2
  4. data/exe/rdx +2 -149
  5. data/ext/rubydex/config.c +140 -0
  6. data/ext/rubydex/config.h +16 -0
  7. data/ext/rubydex/diagnostic.c +75 -1
  8. data/ext/rubydex/diagnostic.h +2 -0
  9. data/ext/rubydex/graph.c +13 -45
  10. data/ext/rubydex/graph.h +6 -0
  11. data/ext/rubydex/query.c +398 -16
  12. data/ext/rubydex/rubydex.c +2 -0
  13. data/ext/rubydex/utils.c +11 -4
  14. data/lib/ruby_lsp/rubydex/addon.rb +211 -0
  15. data/lib/rubydex/cli/command/console.rb +55 -0
  16. data/lib/rubydex/cli/command/lint/explain.rb +74 -0
  17. data/lib/rubydex/cli/command/lint.rb +202 -0
  18. data/lib/rubydex/cli/command/mcp.rb +30 -0
  19. data/lib/rubydex/cli/command/query.rb +70 -0
  20. data/lib/rubydex/cli/command/skill.rb +69 -0
  21. data/lib/rubydex/cli/command.rb +168 -0
  22. data/lib/rubydex/cli.rb +93 -0
  23. data/lib/rubydex/config.rb +59 -0
  24. data/lib/rubydex/diagnostic.rb +12 -3
  25. data/lib/rubydex/errors.rb +42 -1
  26. data/lib/rubydex/graph.rb +10 -3
  27. data/lib/rubydex/linter/custom_rule.rb +97 -0
  28. data/lib/rubydex/linter/helpers/path_helpers.rb +78 -0
  29. data/lib/rubydex/linter/helpers/source_access_helpers.rb +31 -0
  30. data/lib/rubydex/linter/rule_loader.rb +36 -0
  31. data/lib/rubydex/linter/rule_test_case.rb +343 -0
  32. data/lib/rubydex/linter/runner.rb +56 -0
  33. data/lib/rubydex/linter.rb +19 -0
  34. data/lib/rubydex/location.rb +3 -0
  35. data/lib/rubydex/mcp_server.rb +1 -2
  36. data/lib/rubydex/related_information.rb +17 -0
  37. data/lib/rubydex/rule.rb +33 -0
  38. data/lib/rubydex/severity.rb +70 -0
  39. data/lib/rubydex/skill.rb +88 -0
  40. data/lib/rubydex/skill_registry.rb +62 -0
  41. data/lib/rubydex/version.rb +1 -1
  42. data/lib/rubydex.rb +6 -0
  43. data/lib/rubydex_linter/rules/rule_structure.rb +125 -0
  44. data/rbi/rubydex.rbi +558 -17
  45. data/rust/Cargo.lock +2 -2
  46. data/rust/rubydex/Cargo.toml +1 -1
  47. data/rust/rubydex/benches/graph_memory.rs +3 -5
  48. data/rust/rubydex/src/config.rs +538 -157
  49. data/rust/rubydex/src/diagnostic.rs +66 -40
  50. data/rust/rubydex/src/errors.rs +0 -1
  51. data/rust/rubydex/src/indexing/local_graph.rs +6 -5
  52. data/rust/rubydex/src/indexing/rbs_indexer.rs +270 -6
  53. data/rust/rubydex/src/indexing/ruby_indexer.rs +10 -12
  54. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +134 -81
  55. data/rust/rubydex/src/lib.rs +1 -0
  56. data/rust/rubydex/src/listing.rs +26 -1
  57. data/rust/rubydex/src/main.rs +7 -4
  58. data/rust/rubydex/src/model/declaration.rs +302 -219
  59. data/rust/rubydex/src/model/graph.rs +27 -40
  60. data/rust/rubydex/src/model/name.rs +58 -17
  61. data/rust/rubydex/src/operation/ruby_builder.rs +30 -45
  62. data/rust/rubydex/src/path_helpers.rs +77 -0
  63. data/rust/rubydex/src/query/cypher/schema.rs +63 -0
  64. data/rust/rubydex/src/query/cypher/tests.rs +26 -1
  65. data/rust/rubydex/src/query/cypher.rs +8 -11
  66. data/rust/rubydex/src/query.rs +123 -43
  67. data/rust/rubydex/src/resolution.rs +139 -187
  68. data/rust/rubydex/src/resolution_tests.rs +247 -19
  69. data/rust/rubydex/src/test_utils/context.rs +2 -1
  70. data/rust/rubydex/src/test_utils/graph_test.rs +26 -12
  71. data/rust/rubydex/src/test_utils/local_graph_test.rs +19 -0
  72. data/rust/rubydex/tests/cli.rs +4 -4
  73. data/rust/rubydex-sys/src/config_api.rs +205 -0
  74. data/rust/rubydex-sys/src/cypher_api.rs +791 -0
  75. data/rust/rubydex-sys/src/diagnostic_api.rs +77 -8
  76. data/rust/rubydex-sys/src/graph_api.rs +13 -194
  77. data/rust/rubydex-sys/src/lib.rs +2 -0
  78. data/rust/rubydex-sys/src/name_api.rs +2 -6
  79. data/rust/rubydex-sys/src/utils.rs +37 -0
  80. data/skills/send-private-method/SKILL.md +133 -0
  81. metadata +31 -2
@@ -6,6 +6,7 @@ use crate::{
6
6
  assert_def_comments_eq, assert_def_mixins_eq, assert_def_name_eq, assert_def_name_offset_eq, assert_def_str_eq,
7
7
  assert_def_superclass_ref_eq, assert_definition_at, assert_dependents, assert_local_diagnostics_eq,
8
8
  assert_method_has_receiver, assert_name_path_eq, assert_no_local_diagnostics, assert_string_eq,
9
+ diagnostic::Severity,
9
10
  model::{
10
11
  definitions::{Definition, Parameter, Receiver, Signatures},
11
12
  ids::{StringId, UriId},
@@ -967,7 +968,8 @@ mod class_and_module_tests {
967
968
 
968
969
  assert_local_diagnostics_eq!(
969
970
  &context,
970
- ["dynamic-constant-reference: Dynamic constant reference (1:7-1:10)"]
971
+ ["DynamicConstantReference: Dynamic constant reference (1:7-1:10)"],
972
+ severity: Severity::Information
971
973
  );
972
974
  assert!(context.graph().definitions().is_empty());
973
975
  }
@@ -1071,7 +1073,7 @@ mod class_and_module_tests {
1071
1073
 
1072
1074
  assert_local_diagnostics_eq!(
1073
1075
  &context,
1074
- ["dynamic-constant-reference: Dynamic constant reference (1:8-1:11)"]
1076
+ ["DynamicConstantReference: Dynamic constant reference (1:8-1:11)"]
1075
1077
  );
1076
1078
  assert!(context.graph().definitions().is_empty());
1077
1079
  }
@@ -1173,7 +1175,7 @@ mod method_tests {
1173
1175
 
1174
1176
  assert_local_diagnostics_eq!(
1175
1177
  &context,
1176
- ["dynamic-singleton-definition: Dynamic receiver for singleton method definition (1:1-1:17)"]
1178
+ ["DynamicSingletonDefinition: Dynamic receiver for singleton method definition (1:1-1:17)"]
1177
1179
  );
1178
1180
  assert_eq!(context.graph().definitions().len(), 0);
1179
1181
  assert_method_references_eq!(&context, ["foo"]);
@@ -1416,7 +1418,7 @@ mod singleton_class_tests {
1416
1418
 
1417
1419
  assert_local_diagnostics_eq!(
1418
1420
  &context,
1419
- ["dynamic-singleton-definition: Dynamic singleton class definition (1:1-3:4)"]
1421
+ ["DynamicSingletonDefinition: Dynamic singleton class definition (1:1-3:4)"]
1420
1422
  );
1421
1423
  assert_eq!(context.graph().definitions().len(), 0);
1422
1424
  }
@@ -1557,6 +1559,34 @@ mod visibility_tests {
1557
1559
  });
1558
1560
  }
1559
1561
 
1562
+ #[test]
1563
+ fn index_module_function_with_body() {
1564
+ let context = index_source({
1565
+ "
1566
+ module Foo
1567
+ module_function
1568
+
1569
+ def bar
1570
+ @value = CONST
1571
+ baz(1)
1572
+ end
1573
+ end
1574
+ "
1575
+ });
1576
+
1577
+ assert_no_local_diagnostics!(&context);
1578
+ assert_eq!(context.graph().definitions().len(), 4);
1579
+ assert_eq!(context.graph().document().definitions().len(), 4);
1580
+ assert_eq!(context.graph().document().constant_references().len(), 1);
1581
+ assert_eq!(context.graph().document().method_references().len(), 1);
1582
+ assert_constant_references_eq!(&context, ["CONST"]);
1583
+ assert_method_references_eq!(&context, ["baz"]);
1584
+
1585
+ let methods = context.all_definitions_at("4:3-7:6");
1586
+ assert_eq!(methods.len(), 2);
1587
+ assert_definition_at!(&context, "5:5-5:11", InstanceVariable);
1588
+ }
1589
+
1560
1590
  #[test]
1561
1591
  fn index_def_node_with_visibility_nested() {
1562
1592
  let context = index_source({
@@ -1772,12 +1802,13 @@ mod visibility_tests {
1772
1802
  assert_local_diagnostics_eq!(
1773
1803
  &context,
1774
1804
  vec![
1775
- "invalid-constant-visibility: `private_constant` called at top level (1:1-1:22)",
1776
- "invalid-constant-visibility: `private_constant` called at top level (2:1-2:27)",
1777
- "invalid-constant-visibility: Dynamic receiver for `private_constant` (3:1-3:4)",
1778
- "invalid-constant-visibility: `private_constant` called with a non-literal argument (6:20-6:29)",
1779
- "invalid-constant-visibility: `private_constant` called with a non-literal argument (6:31-6:42)",
1780
- ]
1805
+ "InvalidConstantVisibility: `private_constant` called at top level (1:1-1:22)",
1806
+ "InvalidConstantVisibility: `private_constant` called at top level (2:1-2:27)",
1807
+ "InvalidConstantVisibility: Dynamic receiver for `private_constant` (3:1-3:4)",
1808
+ "InvalidConstantVisibility: `private_constant` called with a non-literal argument (6:20-6:29)",
1809
+ "InvalidConstantVisibility: `private_constant` called with a non-literal argument (6:31-6:42)",
1810
+ ],
1811
+ severity: Severity::Warning
1781
1812
  );
1782
1813
 
1783
1814
  assert_eq!(context.graph().definitions().len(), 3); // Foo, Foo.qux, Foo#foo
@@ -1809,11 +1840,11 @@ mod visibility_tests {
1809
1840
  assert_local_diagnostics_eq!(
1810
1841
  &context,
1811
1842
  vec![
1812
- "invalid-constant-visibility: `public_constant` called at top level (1:1-1:21)",
1813
- "invalid-constant-visibility: `public_constant` called at top level (2:1-2:26)",
1814
- "invalid-constant-visibility: Dynamic receiver for `public_constant` (3:1-3:4)",
1815
- "invalid-constant-visibility: `public_constant` called with a non-literal argument (6:19-6:28)",
1816
- "invalid-constant-visibility: `public_constant` called with a non-literal argument (6:30-6:41)",
1843
+ "InvalidConstantVisibility: `public_constant` called at top level (1:1-1:21)",
1844
+ "InvalidConstantVisibility: `public_constant` called at top level (2:1-2:26)",
1845
+ "InvalidConstantVisibility: Dynamic receiver for `public_constant` (3:1-3:4)",
1846
+ "InvalidConstantVisibility: `public_constant` called with a non-literal argument (6:19-6:28)",
1847
+ "InvalidConstantVisibility: `public_constant` called with a non-literal argument (6:30-6:41)",
1817
1848
  ]
1818
1849
  );
1819
1850
 
@@ -1890,7 +1921,7 @@ mod visibility_tests {
1890
1921
 
1891
1922
  assert_local_diagnostics_eq!(
1892
1923
  &context,
1893
- vec!["invalid-method-visibility: `private` called with a non-literal argument (4:17-4:27)"]
1924
+ vec!["InvalidMethodVisibility: `private` called with a non-literal argument (4:17-4:27)"]
1894
1925
  );
1895
1926
 
1896
1927
  // :foo is a literal arg, so visibility is still applied
@@ -1916,7 +1947,7 @@ mod visibility_tests {
1916
1947
 
1917
1948
  assert_local_diagnostics_eq!(
1918
1949
  &context,
1919
- vec!["invalid-method-visibility: `private` cannot be called with an explicit receiver (4:3-4:19)"]
1950
+ vec!["InvalidMethodVisibility: `private` cannot be called with an explicit receiver (4:3-4:19)"]
1920
1951
  );
1921
1952
 
1922
1953
  for def in context.graph().definitions().values() {
@@ -1941,7 +1972,7 @@ mod visibility_tests {
1941
1972
 
1942
1973
  assert_local_diagnostics_eq!(
1943
1974
  &context,
1944
- vec!["invalid-method-visibility: `private` called with a non-literal argument (4:11-4:21)"]
1975
+ vec!["InvalidMethodVisibility: `private` called with a non-literal argument (4:11-4:21)"]
1945
1976
  );
1946
1977
 
1947
1978
  // No MethodVisibilityDefinition created
@@ -1965,7 +1996,7 @@ mod visibility_tests {
1965
1996
 
1966
1997
  assert_local_diagnostics_eq!(
1967
1998
  &context,
1968
- vec!["invalid-method-visibility: `private` called with a non-literal argument (2:11-2:23)"]
1999
+ vec!["InvalidMethodVisibility: `private` called with a non-literal argument (2:11-2:23)"]
1969
2000
  );
1970
2001
 
1971
2002
  // No MethodVisibilityDefinition created
@@ -1989,7 +2020,7 @@ mod visibility_tests {
1989
2020
 
1990
2021
  assert_local_diagnostics_eq!(
1991
2022
  &context,
1992
- vec!["invalid-method-visibility: `private` called with a non-literal argument (2:11-2:35)"]
2023
+ vec!["InvalidMethodVisibility: `private` called with a non-literal argument (2:11-2:35)"]
1993
2024
  );
1994
2025
 
1995
2026
  // No MethodVisibilityDefinition or AttrReader created from that call
@@ -2032,9 +2063,7 @@ mod visibility_tests {
2032
2063
  // attr_reader(:foo) returns an array in multi-arg context, invalid for `private`
2033
2064
  assert_local_diagnostics_eq!(
2034
2065
  &context,
2035
- vec![
2036
- "invalid-method-visibility: `private` with `attr_*` is only supported as a single argument (2:11-2:28)"
2037
- ]
2066
+ vec!["InvalidMethodVisibility: `private` with `attr_*` is only supported as a single argument (2:11-2:28)"]
2038
2067
  );
2039
2068
 
2040
2069
  // foo reader still defined via side effects, but public
@@ -2097,7 +2126,7 @@ mod visibility_tests {
2097
2126
 
2098
2127
  assert_local_diagnostics_eq!(
2099
2128
  &context,
2100
- vec!["invalid-method-visibility: `module_function` can only be used in modules (4:3-4:23)"]
2129
+ vec!["InvalidMethodVisibility: `module_function` can only be used in modules (4:3-4:23)"]
2101
2130
  );
2102
2131
 
2103
2132
  for def in context.graph().definitions().values() {
@@ -2169,8 +2198,8 @@ mod visibility_tests {
2169
2198
  assert_local_diagnostics_eq!(
2170
2199
  &context,
2171
2200
  vec![
2172
- "invalid-method-visibility: `private` called with a non-literal argument (2:25-2:32)",
2173
- "invalid-method-visibility: `private` called with a non-literal argument (3:11-3:18)",
2201
+ "InvalidMethodVisibility: `private` called with a non-literal argument (2:25-2:32)",
2202
+ "InvalidMethodVisibility: `private` called with a non-literal argument (3:11-3:18)",
2174
2203
  ]
2175
2204
  );
2176
2205
 
@@ -2200,8 +2229,8 @@ mod visibility_tests {
2200
2229
  assert_local_diagnostics_eq!(
2201
2230
  &context,
2202
2231
  vec![
2203
- "invalid-method-visibility: `private` called with a non-literal argument (2:11-2:18)",
2204
- "invalid-method-visibility: `private` called with a non-literal argument (2:20-2:27)",
2232
+ "InvalidMethodVisibility: `private` called with a non-literal argument (2:11-2:18)",
2233
+ "InvalidMethodVisibility: `private` called with a non-literal argument (2:20-2:27)",
2205
2234
  ]
2206
2235
  );
2207
2236
 
@@ -2221,7 +2250,7 @@ mod visibility_tests {
2221
2250
  // module_function in a class is always invalid regardless of args
2222
2251
  assert_local_diagnostics_eq!(
2223
2252
  &context,
2224
- vec!["invalid-method-visibility: `module_function` can only be used in modules (2:3-2:37)"]
2253
+ vec!["InvalidMethodVisibility: `module_function` can only be used in modules (2:3-2:37)"]
2225
2254
  );
2226
2255
 
2227
2256
  for def in context.graph().definitions().values() {
@@ -2307,12 +2336,13 @@ mod visibility_tests {
2307
2336
  assert_local_diagnostics_eq!(
2308
2337
  &context,
2309
2338
  vec![
2310
- "invalid-method-visibility: `private_class_method` called at top level (1:1-1:34)",
2311
- "invalid-method-visibility: `private_class_method` called at top level (2:1-2:39)",
2312
- "invalid-method-visibility: `private_class_method` called with a non-literal argument (6:24-6:35)",
2313
- "invalid-method-visibility: `private_class_method` does not accept `attr_*` arguments (8:24-8:41)",
2314
- "invalid-method-visibility: `private_class_method` requires a singleton method definition (9:24-9:39)",
2315
- ]
2339
+ "InvalidMethodVisibility: `private_class_method` called at top level (1:1-1:34)",
2340
+ "InvalidMethodVisibility: `private_class_method` called at top level (2:1-2:39)",
2341
+ "InvalidMethodVisibility: `private_class_method` called with a non-literal argument (6:24-6:35)",
2342
+ "InvalidMethodVisibility: `private_class_method` does not accept `attr_*` arguments (8:24-8:41)",
2343
+ "InvalidMethodVisibility: `private_class_method` requires a singleton method definition (9:24-9:39)",
2344
+ ],
2345
+ severity: Severity::Warning
2316
2346
  );
2317
2347
  }
2318
2348
 
@@ -2346,7 +2376,7 @@ mod visibility_tests {
2346
2376
 
2347
2377
  assert_local_diagnostics_eq!(
2348
2378
  &context,
2349
- vec!["invalid-method-visibility: `private_class_method` called with a non-literal argument (5:28-5:40)"]
2379
+ vec!["InvalidMethodVisibility: `private_class_method` called with a non-literal argument (5:28-5:40)"]
2350
2380
  );
2351
2381
 
2352
2382
  assert_definition_at!(&context, "5:25-5:26", MethodVisibility, |def| {
@@ -2367,7 +2397,7 @@ mod visibility_tests {
2367
2397
 
2368
2398
  assert_local_diagnostics_eq!(
2369
2399
  &context,
2370
- vec!["invalid-method-visibility: `private_class_method` called at top level (1:1-1:32)"]
2400
+ vec!["InvalidMethodVisibility: `private_class_method` called at top level (1:1-1:32)"]
2371
2401
  );
2372
2402
  assert_constant_references_eq!(&context, ["NESTED_REF"]);
2373
2403
  }
@@ -2452,7 +2482,7 @@ mod visibility_tests {
2452
2482
  assert_local_diagnostics_eq!(
2453
2483
  &context,
2454
2484
  vec![
2455
- "invalid-method-visibility: `private_class_method` array element must be a Symbol, String, or method definition (5:32-5:42)"
2485
+ "InvalidMethodVisibility: `private_class_method` array element must be a Symbol, String, or method definition (5:32-5:42)"
2456
2486
  ]
2457
2487
  );
2458
2488
 
@@ -2480,9 +2510,7 @@ mod visibility_tests {
2480
2510
 
2481
2511
  assert_local_diagnostics_eq!(
2482
2512
  &context,
2483
- vec![
2484
- "invalid-method-visibility: `private_class_method` requires a singleton method definition (2:25-2:49)"
2485
- ]
2513
+ vec!["InvalidMethodVisibility: `private_class_method` requires a singleton method definition (2:25-2:49)"]
2486
2514
  );
2487
2515
 
2488
2516
  for def in context.graph().definitions().values() {
@@ -2514,7 +2542,7 @@ mod visibility_tests {
2514
2542
  assert_local_diagnostics_eq!(
2515
2543
  &context,
2516
2544
  vec![
2517
- "invalid-method-visibility: `private_class_method` array argument must be the only argument (5:24-5:28)"
2545
+ "InvalidMethodVisibility: `private_class_method` array argument must be the only argument (5:24-5:28)"
2518
2546
  ]
2519
2547
  );
2520
2548
 
@@ -2817,8 +2845,8 @@ mod constant_reference_tests {
2817
2845
  assert_local_diagnostics_eq!(
2818
2846
  &context,
2819
2847
  [
2820
- "dynamic-constant-reference: Dynamic constant reference (3:6-3:14)",
2821
- "parse-warning: assigned but unused variable - foo (5:1-5:4)",
2848
+ "DynamicConstantReference: Dynamic constant reference (3:6-3:14)",
2849
+ "ParseWarning: assigned but unused variable - foo (5:1-5:4)",
2822
2850
  ]
2823
2851
  );
2824
2852
 
@@ -3001,7 +3029,7 @@ mod method_reference_tests {
3001
3029
 
3002
3030
  assert_local_diagnostics_eq!(
3003
3031
  &context,
3004
- ["parse-error: unexpected ... when the parent method is not forwarding (31:5-31:8)"]
3032
+ ["ParseError: unexpected ... when the parent method is not forwarding (31:5-31:8)"]
3005
3033
  );
3006
3034
 
3007
3035
  assert_method_references_eq!(
@@ -3087,18 +3115,18 @@ mod method_reference_tests {
3087
3115
  assert_local_diagnostics_eq!(
3088
3116
  &context,
3089
3117
  [
3090
- "parse-warning: possibly useless use of != in void context (1:1-1:7)",
3091
- "parse-warning: possibly useless use of % in void context (2:1-2:6)",
3092
- "parse-warning: possibly useless use of & in void context (3:1-3:6)",
3093
- "parse-warning: possibly useless use of * in void context (5:1-5:6)",
3094
- "parse-warning: possibly useless use of ** in void context (6:1-6:7)",
3095
- "parse-warning: possibly useless use of + in void context (7:1-7:6)",
3096
- "parse-warning: possibly useless use of - in void context (8:1-8:6)",
3097
- "parse-warning: possibly useless use of / in void context (9:1-9:6)",
3098
- "parse-warning: possibly useless use of == in void context (11:1-11:7)",
3099
- "parse-warning: possibly useless use of ^ in void context (14:1-14:6)",
3100
- "parse-warning: possibly useless use of | in void context (15:1-15:6)",
3101
- "parse-warning: possibly useless use of <=> in void context (17:1-17:8)"
3118
+ "ParseWarning: possibly useless use of != in void context (1:1-1:7)",
3119
+ "ParseWarning: possibly useless use of % in void context (2:1-2:6)",
3120
+ "ParseWarning: possibly useless use of & in void context (3:1-3:6)",
3121
+ "ParseWarning: possibly useless use of * in void context (5:1-5:6)",
3122
+ "ParseWarning: possibly useless use of ** in void context (6:1-6:7)",
3123
+ "ParseWarning: possibly useless use of + in void context (7:1-7:6)",
3124
+ "ParseWarning: possibly useless use of - in void context (8:1-8:6)",
3125
+ "ParseWarning: possibly useless use of / in void context (9:1-9:6)",
3126
+ "ParseWarning: possibly useless use of == in void context (11:1-11:7)",
3127
+ "ParseWarning: possibly useless use of ^ in void context (14:1-14:6)",
3128
+ "ParseWarning: possibly useless use of | in void context (15:1-15:6)",
3129
+ "ParseWarning: possibly useless use of <=> in void context (17:1-17:8)"
3102
3130
  ]
3103
3131
  );
3104
3132
 
@@ -3120,7 +3148,7 @@ mod method_reference_tests {
3120
3148
 
3121
3149
  assert_local_diagnostics_eq!(
3122
3150
  &context,
3123
- ["parse-warning: possibly useless use of < in void context (1:1-1:6)"]
3151
+ ["ParseWarning: possibly useless use of < in void context (1:1-1:6)"]
3124
3152
  );
3125
3153
 
3126
3154
  assert_method_references_eq!(&context, ["x", "<", "<=>", "y"]);
@@ -3136,7 +3164,7 @@ mod method_reference_tests {
3136
3164
 
3137
3165
  assert_local_diagnostics_eq!(
3138
3166
  &context,
3139
- ["parse-warning: possibly useless use of <= in void context (1:1-1:7)"]
3167
+ ["ParseWarning: possibly useless use of <= in void context (1:1-1:7)"]
3140
3168
  );
3141
3169
 
3142
3170
  assert_method_references_eq!(&context, ["x", "<=", "<=>", "y"]);
@@ -3152,7 +3180,7 @@ mod method_reference_tests {
3152
3180
 
3153
3181
  assert_local_diagnostics_eq!(
3154
3182
  &context,
3155
- ["parse-warning: possibly useless use of > in void context (1:1-1:6)"]
3183
+ ["ParseWarning: possibly useless use of > in void context (1:1-1:6)"]
3156
3184
  );
3157
3185
 
3158
3186
  assert_method_references_eq!(&context, ["x", "<=>", ">", "y"]);
@@ -3168,7 +3196,7 @@ mod method_reference_tests {
3168
3196
 
3169
3197
  assert_local_diagnostics_eq!(
3170
3198
  &context,
3171
- ["parse-warning: possibly useless use of >= in void context (1:1-1:7)"]
3199
+ ["ParseWarning: possibly useless use of >= in void context (1:1-1:7)"]
3172
3200
  );
3173
3201
 
3174
3202
  assert_method_references_eq!(&context, ["x", "<=>", ">=", "y"]);
@@ -3672,10 +3700,10 @@ mod superclass_tests {
3672
3700
  assert_local_diagnostics_eq!(
3673
3701
  &context,
3674
3702
  [
3675
- "dynamic-ancestor: Dynamic superclass (1:13-1:24)",
3676
- "dynamic-ancestor: Dynamic superclass (2:13-2:16)",
3677
- "dynamic-constant-reference: Dynamic constant reference (4:13-4:16)",
3678
- "dynamic-ancestor: Dynamic superclass (4:13-4:21)",
3703
+ "DynamicAncestor: Dynamic superclass (1:13-1:24)",
3704
+ "DynamicAncestor: Dynamic superclass (2:13-2:16)",
3705
+ "DynamicConstantReference: Dynamic constant reference (4:13-4:16)",
3706
+ "DynamicAncestor: Dynamic superclass (4:13-4:21)",
3679
3707
  ]
3680
3708
  );
3681
3709
 
@@ -3858,15 +3886,15 @@ mod mixin_tests {
3858
3886
  assert_local_diagnostics_eq!(
3859
3887
  &context,
3860
3888
  [
3861
- "dynamic-constant-reference: Dynamic constant reference (1:9-1:12)",
3862
- "dynamic-ancestor: Dynamic mixin argument (1:9-1:17)",
3863
- "dynamic-constant-reference: Dynamic constant reference (2:9-2:12)",
3864
- "dynamic-ancestor: Dynamic mixin argument (2:9-2:17)",
3865
- "dynamic-constant-reference: Dynamic constant reference (3:8-3:11)",
3866
- "dynamic-ancestor: Dynamic mixin argument (3:8-3:16)",
3867
- "dynamic-ancestor: Dynamic mixin argument (5:9-5:12)",
3868
- "dynamic-ancestor: Dynamic mixin argument (6:9-6:12)",
3869
- "dynamic-ancestor: Dynamic mixin argument (7:8-7:11)"
3889
+ "DynamicConstantReference: Dynamic constant reference (1:9-1:12)",
3890
+ "DynamicAncestor: Dynamic mixin argument (1:9-1:17)",
3891
+ "DynamicConstantReference: Dynamic constant reference (2:9-2:12)",
3892
+ "DynamicAncestor: Dynamic mixin argument (2:9-2:17)",
3893
+ "DynamicConstantReference: Dynamic constant reference (3:8-3:11)",
3894
+ "DynamicAncestor: Dynamic mixin argument (3:8-3:16)",
3895
+ "DynamicAncestor: Dynamic mixin argument (5:9-5:12)",
3896
+ "DynamicAncestor: Dynamic mixin argument (6:9-6:12)",
3897
+ "DynamicAncestor: Dynamic mixin argument (7:8-7:11)"
3870
3898
  ]
3871
3899
  );
3872
3900
  assert!(context.graph().definitions().is_empty());
@@ -3885,9 +3913,9 @@ mod mixin_tests {
3885
3913
  assert_local_diagnostics_eq!(
3886
3914
  &context,
3887
3915
  [
3888
- "top-level-mixin-self: Top level mixin self (1:9-1:13)",
3889
- "top-level-mixin-self: Top level mixin self (2:9-2:13)",
3890
- "top-level-mixin-self: Top level mixin self (3:8-3:12)"
3916
+ "TopLevelMixinSelf: Top level mixin self (1:9-1:13)",
3917
+ "TopLevelMixinSelf: Top level mixin self (2:9-2:13)",
3918
+ "TopLevelMixinSelf: Top level mixin self (3:8-3:12)"
3891
3919
  ]
3892
3920
  );
3893
3921
 
@@ -5168,6 +5196,29 @@ mod dynamic_namespace_tests {
5168
5196
  });
5169
5197
  }
5170
5198
 
5199
+ #[test]
5200
+ fn index_extend_self_in_anonymous_module() {
5201
+ let context = index_source({
5202
+ "
5203
+ Module.new do
5204
+ extend self
5205
+ end
5206
+ "
5207
+ });
5208
+ assert_no_local_diagnostics!(&context);
5209
+
5210
+ assert_definition_at!(&context, "1:1-3:4", Module, |anonymous_module| {
5211
+ let extend = anonymous_module.mixins().first().unwrap();
5212
+ let constant_reference = context
5213
+ .graph()
5214
+ .constant_references()
5215
+ .get(extend.constant_reference_id())
5216
+ .unwrap();
5217
+
5218
+ assert_eq!(anonymous_module.name_id(), constant_reference.name_id());
5219
+ });
5220
+ }
5221
+
5171
5222
  #[test]
5172
5223
  fn index_singleton_method_in_class_new() {
5173
5224
  let context = index_source({
@@ -5261,9 +5312,10 @@ mod diagnostic_tests {
5261
5312
  assert_local_diagnostics_eq!(
5262
5313
  &context,
5263
5314
  [
5264
- "parse-error: expected an `end` to close the `class` statement (1:1-1:6)",
5265
- "parse-error: unexpected end-of-input, assuming it is closing the parent top level context (1:10-2:1)"
5266
- ]
5315
+ "ParseError: expected an `end` to close the `class` statement (1:1-1:6)",
5316
+ "ParseError: unexpected end-of-input, assuming it is closing the parent top level context (1:10-2:1)"
5317
+ ],
5318
+ severity: Severity::Error
5267
5319
  );
5268
5320
 
5269
5321
  // We still index the definition, even though it has errors
@@ -5283,7 +5335,8 @@ mod diagnostic_tests {
5283
5335
 
5284
5336
  assert_local_diagnostics_eq!(
5285
5337
  &context,
5286
- ["parse-warning: assigned but unused variable - foo (1:1-1:4)"]
5338
+ ["ParseWarning: assigned but unused variable - foo (1:1-1:4)"],
5339
+ severity: Severity::Warning
5287
5340
  );
5288
5341
  }
5289
5342
  }
@@ -16,6 +16,7 @@ pub mod listing;
16
16
  pub mod model;
17
17
  pub mod offset;
18
18
  pub mod operation;
19
+ pub(crate) mod path_helpers;
19
20
  pub mod position;
20
21
  pub mod query;
21
22
  pub mod resolution;
@@ -1,6 +1,7 @@
1
1
  use crate::{
2
2
  errors::Errors,
3
3
  job_queue::{Job, JobQueue},
4
+ path_helpers,
4
5
  };
5
6
  use crossbeam_channel::{Sender, unbounded};
6
7
  use glob::Pattern;
@@ -129,7 +130,7 @@ pub fn collect_file_paths<S: BuildHasher>(
129
130
  Arc::new(excluded.iter().filter_map(|entry| Pattern::new(entry).ok()).collect());
130
131
 
131
132
  for path in paths {
132
- let Ok(path) = std::path::absolute(&path) else {
133
+ let Ok(path) = std::path::absolute(&path).map(path_helpers::simplified) else {
133
134
  errors_tx
134
135
  .send(Errors::FileError(format!("Failed to resolve path `{path}`")))
135
136
  .expect("errors receiver dropped before run completion");
@@ -420,6 +421,30 @@ mod tests {
420
421
  assert_eq!(files, [foo.to_str().unwrap().to_string()]);
421
422
  }
422
423
 
424
+ #[cfg(windows)]
425
+ #[test]
426
+ fn collect_files_excludes_a_directory_below_a_verbatim_root() {
427
+ // Exclusions are joined onto the workspace path the configuration resolved, which is spelled plainly. A root
428
+ // given verbatim only matches them once it is spelled that way too.
429
+ let context = Context::new();
430
+ context.touch(&PathBuf::from("excluded").join("skipped.rb"));
431
+
432
+ let mut excluded = HashSet::new();
433
+ excluded.insert(
434
+ context
435
+ .absolute_path_to("excluded")
436
+ .to_string_lossy()
437
+ .replace('\\', "/")
438
+ .into_boxed_str(),
439
+ );
440
+
441
+ let (files, errors) =
442
+ collect_file_paths(vec![format!(r"\\?\{}", context.absolute_path().display())], &excluded);
443
+
444
+ assert!(errors.is_empty());
445
+ assert!(files.is_empty(), "expected the exclusion to apply: {files:?}");
446
+ }
447
+
423
448
  #[test]
424
449
  fn collect_files_excludes_nested_files_matching_globs() {
425
450
  let context = Context::new();
@@ -2,6 +2,7 @@ use clap::{Parser, ValueEnum};
2
2
  use std::{fs, mem, path::PathBuf};
3
3
 
4
4
  use rubydex::{
5
+ config::Config,
5
6
  dot,
6
7
  indexing::{self, IndexerBackend},
7
8
  integrity, listing,
@@ -104,10 +105,12 @@ fn main() {
104
105
  let mut graph = Graph::new();
105
106
 
106
107
  if let Some(workspace_path) = workspace_path_for(&args.paths) {
107
- graph.set_workspace_path(workspace_path);
108
- if let Err(error) = graph.load_config(None) {
109
- eprintln!("{error}");
110
- std::process::exit(1);
108
+ match Config::load(&workspace_path) {
109
+ Ok(config) => graph.load_config(&config),
110
+ Err(error) => {
111
+ eprintln!("{error}");
112
+ std::process::exit(1);
113
+ }
111
114
  }
112
115
  }
113
116