shirobai 2026.0820.0300 → 2026.0905.1300
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/Cargo.lock +2 -2
- data/Cargo.toml +1 -1
- data/crates/shirobai-core/src/bin/analysis_profile.rs +1 -1
- data/crates/shirobai-core/src/bin/bundle_profile.rs +1 -1
- data/crates/shirobai-core/src/bin/hotspot_profile.rs +1 -1
- data/crates/shirobai-core/src/rules/aligner.rs +19 -6
- data/crates/shirobai-core/src/rules/bundle.rs +24 -10
- data/crates/shirobai-core/src/rules/duplicate_methods.rs +57 -14
- data/crates/shirobai-core/src/rules/extra_spacing.rs +352 -20
- data/crates/shirobai-core/src/rules/first_argument_indentation.rs +135 -12
- data/crates/shirobai-core/src/rules/if_unless_modifier.rs +7 -25
- data/crates/shirobai-core/src/rules/method_name.rs +29 -1
- data/crates/shirobai-core/src/rules/multiline_method_call_indentation.rs +24 -8
- data/crates/shirobai-core/src/rules/space_around_operators.rs +62 -21
- data/crates/shirobai-core/src/rules/space_before_first_arg.rs +23 -4
- data/crates/shirobai-core/src/rules/tokens.rs +28 -0
- data/ext/shirobai/src/lib.rs +11 -18
- data/lib/shirobai/cop/layout/empty_line_after_magic_comment.rb +41 -13
- data/lib/shirobai/cop/layout/end_of_line.rb +18 -7
- data/lib/shirobai/cop/layout/extra_spacing.rb +5 -3
- data/lib/shirobai/cop/layout/first_argument_indentation.rb +12 -7
- data/lib/shirobai/cop/layout/line_continuation_spacing.rb +8 -1
- data/lib/shirobai/cop/layout/line_length.rb +7 -1
- data/lib/shirobai/cop/lint/duplicate_methods.rb +55 -16
- data/lib/shirobai/cop/naming/method_name.rb +14 -4
- data/lib/shirobai/cop/style/if_unless_modifier.rb +13 -12
- data/lib/shirobai/cop/style/magic_comment_format.rb +10 -4
- data/lib/shirobai/dispatch.rb +2 -2
- data/lib/shirobai/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1f4f98851b8d60acd4a275498959e3e6a0fca00455715bcdfa5b16a653a90015
|
|
4
|
+
data.tar.gz: 9bb15c3004bfa6415d01d2e6038dfa430cd930f260f988faf22133f445869597
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7effd8214232c64b9fee9ecbe046bf102e2b24936aef4c991039bd8028acc79d936b4c6d0d42ed184a247e1e1ac0b1ea0ca268f57c6001a3d16e9913af9106a5
|
|
7
|
+
data.tar.gz: 186a7b1f6e790e78c73f85ed0000bacf40ed19dbb8c0ab426b52b31b124f81f7eb907392400732b242b8fd92026907bef51f637f117c0957e92c14f117f1f3ae
|
data/Cargo.lock
CHANGED
|
@@ -356,7 +356,7 @@ checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"
|
|
|
356
356
|
|
|
357
357
|
[[package]]
|
|
358
358
|
name = "shirobai"
|
|
359
|
-
version = "2026.
|
|
359
|
+
version = "2026.905.1300"
|
|
360
360
|
dependencies = [
|
|
361
361
|
"magnus",
|
|
362
362
|
"shirobai-core",
|
|
@@ -364,7 +364,7 @@ dependencies = [
|
|
|
364
364
|
|
|
365
365
|
[[package]]
|
|
366
366
|
name = "shirobai-core"
|
|
367
|
-
version = "2026.
|
|
367
|
+
version = "2026.905.1300"
|
|
368
368
|
dependencies = [
|
|
369
369
|
"libc",
|
|
370
370
|
"ruby-prism",
|
data/Cargo.toml
CHANGED
|
@@ -7,7 +7,7 @@ resolver = "3"
|
|
|
7
7
|
# is crate 2026.709.0 -- cargo rejects leading zeros in numeric segments, and
|
|
8
8
|
# Gem::Version normalizes to the same integers, so the two stay value-equal).
|
|
9
9
|
[workspace.package]
|
|
10
|
-
version = "2026.
|
|
10
|
+
version = "2026.905.1300"
|
|
11
11
|
|
|
12
12
|
# Release tuning. The hot path crosses crate boundaries (ext cdylib -> core
|
|
13
13
|
# check_* -> ruby-prism); without LTO the cross-crate calls are not inlined and
|
|
@@ -221,7 +221,7 @@ fn run_perrule(sources: &[Vec<u8>], cfg: &BundleConfig, iterations: usize) {
|
|
|
221
221
|
s,
|
|
222
222
|
cfg.first_argument_style,
|
|
223
223
|
cfg.first_argument_indent,
|
|
224
|
-
cfg.
|
|
224
|
+
cfg.first_argument_fixed_mode,
|
|
225
225
|
));
|
|
226
226
|
}),
|
|
227
227
|
e!("redundant_self", |s: &[u8]| {
|
|
@@ -411,7 +411,7 @@ fn run_full_firstarg(sources: &[Vec<u8>]) -> usize {
|
|
|
411
411
|
let mut sink = 0usize;
|
|
412
412
|
for s in sources {
|
|
413
413
|
sink = sink.wrapping_add(
|
|
414
|
-
rules::first_argument_indentation::check_first_argument_indentation(s, 0, 2,
|
|
414
|
+
rules::first_argument_indentation::check_first_argument_indentation(s, 0, 2, 0)
|
|
415
415
|
.len(),
|
|
416
416
|
);
|
|
417
417
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
//! Shared alignment helper for the `AllowForAlignment` family of cops.
|
|
2
2
|
//!
|
|
3
|
-
//! `Layout/SpaceAroundOperators` and `Layout/
|
|
3
|
+
//! `Layout/SpaceAroundOperators` and `Layout/ExtraSpacing` both honour an
|
|
4
4
|
//! `AllowForAlignment` option that permits extra spacing used to vertically
|
|
5
5
|
//! align a token with something on a preceding or following line. The logic is
|
|
6
6
|
//! the `PrecedingFollowingAlignment` mixin in stock rubocop
|
|
7
7
|
//! (`lib/rubocop/cop/mixin/preceding_following_alignment.rb`). This module hosts
|
|
8
|
-
//! the single implementation both cops drive (copy-divergence is
|
|
9
|
-
//! equivalence is held by each cop's cargo tests).
|
|
8
|
+
//! the single implementation both token-stream cops drive (copy-divergence is
|
|
9
|
+
//! forbidden; equivalence is held by each cop's cargo tests).
|
|
10
|
+
//! `Layout/SpaceBeforeFirstArg` runs the same search over a masked byte scan
|
|
11
|
+
//! (it has no token stream); a change to the search rules here must be
|
|
12
|
+
//! mirrored in `space_before_first_arg.rs`.
|
|
10
13
|
//!
|
|
11
14
|
//! [`Aligner`] is bound to one source + its parser-gem token list. It needs the
|
|
12
15
|
//! token list, so callers build it in the walk-outer phase (the token cache
|
|
@@ -198,8 +201,18 @@ impl<'a> Aligner<'a> {
|
|
|
198
201
|
let Some(index) = first_non_space_index(line) else {
|
|
199
202
|
continue;
|
|
200
203
|
};
|
|
201
|
-
if
|
|
202
|
-
|
|
204
|
+
if let Some(ind) = indent {
|
|
205
|
+
// When searching for the nearest line with the same
|
|
206
|
+
// indentation, more deeply indented lines are nested content
|
|
207
|
+
// of the current group and are skipped, but a less deeply
|
|
208
|
+
// indented line ends the enclosing block: an alignment anchor
|
|
209
|
+
// beyond it would be coincidental (1.90).
|
|
210
|
+
if index < ind {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
if index > ind {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
203
216
|
}
|
|
204
217
|
// The first line with a non-space (and matching indent, if given)
|
|
205
218
|
// decides the result; stock returns the predicate value here.
|
|
@@ -220,7 +233,7 @@ impl<'a> Aligner<'a> {
|
|
|
220
233
|
|
|
221
234
|
/// `aligned_comment_lines`: lines of full-line comments (a comment whose
|
|
222
235
|
/// expression begins its line).
|
|
223
|
-
fn aligned_comment_line(&self, line: usize) -> bool {
|
|
236
|
+
pub(crate) fn aligned_comment_line(&self, line: usize) -> bool {
|
|
224
237
|
self.tokens.iter().any(|t| {
|
|
225
238
|
t.comment() && self.line(t.begin_pos) == line && self.begins_its_line(t.begin_pos)
|
|
226
239
|
})
|
|
@@ -113,7 +113,7 @@ pub fn check_multiline_bundle(
|
|
|
113
113
|
/// | 15-17 | multiline_operation style / indent / base |
|
|
114
114
|
/// | 18-20 | multiline_method_call style / indent / base |
|
|
115
115
|
/// | 21-23 | argument_alignment style / indent / incompatible |
|
|
116
|
-
/// | 24-26 | first_argument_indentation style / indent /
|
|
116
|
+
/// | 24-26 | first_argument_indentation style / indent / fixed_mode (0 off / 1 `with_fixed_indentation` with FirstMethodArgumentLineBreak off: defer all / 2 with it on: defer conflicts) |
|
|
117
117
|
/// | 27-33 | indentation_width width / relative_to_receiver / access_modifier_outdent / indented_internal_methods / end_align / def_end_align_def / use_tabs |
|
|
118
118
|
/// | 34 | closing_paren_indent |
|
|
119
119
|
/// | 35-37 | first_array_element style / indent / enforce_fixed_indentation |
|
|
@@ -231,6 +231,7 @@ pub fn check_multiline_bundle(
|
|
|
231
231
|
/// | 26 | arguments_forwarding RedundantKeywordRestArgumentNames |
|
|
232
232
|
/// | 27 | arguments_forwarding RedundantBlockArgumentNames |
|
|
233
233
|
/// | 28 | duplicate_methods_delegating (`Lint/DuplicateMethods` `DelegatingMethods`, 1.89) |
|
|
234
|
+
/// | 29 | method_name_forbidden (`Naming/MethodName` `ForbiddenIdentifiers`: valid-style names the filtered flavor keeps) |
|
|
234
235
|
///
|
|
235
236
|
/// Performance segment `nums[1]` (the shirobai-performance plugin origin):
|
|
236
237
|
///
|
|
@@ -319,6 +320,9 @@ pub struct BundleConfig {
|
|
|
319
320
|
pub variable_number_flags: u8,
|
|
320
321
|
pub variable_number_allowed_identifiers: Vec<String>,
|
|
321
322
|
pub method_name_style: u8,
|
|
323
|
+
/// `Naming/MethodName` `ForbiddenIdentifiers`: names the filtered flavor
|
|
324
|
+
/// returns even when their style is fine (list 29).
|
|
325
|
+
pub method_name_forbidden: Vec<String>,
|
|
322
326
|
pub safe_navigation_nil_methods: Vec<String>,
|
|
323
327
|
pub dot_position_style: u8,
|
|
324
328
|
pub line_length_max: usize,
|
|
@@ -333,7 +337,7 @@ pub struct BundleConfig {
|
|
|
333
337
|
pub array_alignment_indent: usize,
|
|
334
338
|
pub first_argument_style: u8,
|
|
335
339
|
pub first_argument_indent: usize,
|
|
336
|
-
pub
|
|
340
|
+
pub first_argument_fixed_mode: u8,
|
|
337
341
|
pub indentation_width: indentation_width::Config,
|
|
338
342
|
pub closing_paren_indent: usize,
|
|
339
343
|
pub first_array_element_style: u8,
|
|
@@ -486,7 +490,7 @@ pub const ORIGIN_RAILS: usize = 3;
|
|
|
486
490
|
pub const N_ORIGINS: usize = 4;
|
|
487
491
|
|
|
488
492
|
const CORE_NUMS_LEN: usize = 134;
|
|
489
|
-
const CORE_LISTS_LEN: usize =
|
|
493
|
+
const CORE_LISTS_LEN: usize = 30;
|
|
490
494
|
const PERF_NUMS_LEN: usize = 3;
|
|
491
495
|
const PERF_LISTS_LEN: usize = 1;
|
|
492
496
|
|
|
@@ -564,6 +568,8 @@ impl BundleConfig {
|
|
|
564
568
|
variable_number_flags: nums[9] as u8,
|
|
565
569
|
variable_number_allowed_identifiers: next_list(),
|
|
566
570
|
method_name_style: nums[10] as u8,
|
|
571
|
+
// Filled after the literal: list 29 follows the DuplicateMethods list.
|
|
572
|
+
method_name_forbidden: Vec::new(),
|
|
567
573
|
safe_navigation_nil_methods: next_list(),
|
|
568
574
|
dot_position_style: nums[11] as u8,
|
|
569
575
|
line_length_max: nums[12] as usize,
|
|
@@ -579,7 +585,7 @@ impl BundleConfig {
|
|
|
579
585
|
frozen_string_literal_comment_style: nums[116] as u8,
|
|
580
586
|
first_argument_style: nums[24] as u8,
|
|
581
587
|
first_argument_indent: nums[25] as usize,
|
|
582
|
-
|
|
588
|
+
first_argument_fixed_mode: nums[26] as u8,
|
|
583
589
|
indentation_width: indentation_width::Config {
|
|
584
590
|
width: nums[27] as usize,
|
|
585
591
|
relative_to_receiver: nums[28] != 0,
|
|
@@ -862,6 +868,7 @@ impl BundleConfig {
|
|
|
862
868
|
rails: rails_config::RailsConfig::from_segment(rails_nums, &rails_lists)?,
|
|
863
869
|
};
|
|
864
870
|
bundle.duplicate_methods.delegating_methods = next_list();
|
|
871
|
+
bundle.method_name_forbidden = next_list();
|
|
865
872
|
Ok(bundle)
|
|
866
873
|
}
|
|
867
874
|
}
|
|
@@ -1216,7 +1223,7 @@ pub fn check_all_bundle(source: &[u8], cfg: &BundleConfig) -> BundleResult {
|
|
|
1216
1223
|
source,
|
|
1217
1224
|
cfg.first_argument_style,
|
|
1218
1225
|
cfg.first_argument_indent,
|
|
1219
|
-
cfg.
|
|
1226
|
+
cfg.first_argument_fixed_mode,
|
|
1220
1227
|
);
|
|
1221
1228
|
let mut snc_rule = safe_navigation_chain::build_rule(source, &cfg.safe_navigation_nil_methods);
|
|
1222
1229
|
let mut iw_rule = indentation_width::build_rule(source, cfg.indentation_width, &[], &[]);
|
|
@@ -1588,7 +1595,7 @@ pub fn check_all_bundle(source: &[u8], cfg: &BundleConfig) -> BundleResult {
|
|
|
1588
1595
|
};
|
|
1589
1596
|
// `Layout/ExtraSpacing` is a token-scan cop with an AST side input: it walks
|
|
1590
1597
|
// the token stream collected up front as adjacent pairs, and its own
|
|
1591
|
-
// `with_parsed` (`
|
|
1598
|
+
// `with_parsed` (`collect_def_info`, sharing the cached parse) supplies the
|
|
1592
1599
|
// `remove_equals_in_def` positions the alignment / assignment logic needs.
|
|
1593
1600
|
let extra_spacing = match &bundle_tokens {
|
|
1594
1601
|
Some(tokens) if cfg.extra_spacing_enabled => {
|
|
@@ -1720,9 +1727,15 @@ pub fn check_all_bundle(source: &[u8], cfg: &BundleConfig) -> BundleResult {
|
|
|
1720
1727
|
);
|
|
1721
1728
|
|
|
1722
1729
|
// --- Cops off the shared walk (see the doc comment above). ---
|
|
1723
|
-
// The bundle always computes the filtered flavor
|
|
1724
|
-
// config needs the unfiltered one
|
|
1725
|
-
|
|
1730
|
+
// The bundle always computes the filtered flavor (keeping the forbidden
|
|
1731
|
+
// identifiers); a `MethodName` whose config needs the unfiltered one
|
|
1732
|
+
// (pattern lists) takes the fallback path on the Ruby side.
|
|
1733
|
+
let method_name = method_name::check_method_name_filtered_keeping(
|
|
1734
|
+
source,
|
|
1735
|
+
cfg.method_name_style,
|
|
1736
|
+
true,
|
|
1737
|
+
&cfg.method_name_forbidden,
|
|
1738
|
+
);
|
|
1726
1739
|
let line_length = line_length::check_line_length_with_heredocs(
|
|
1727
1740
|
source,
|
|
1728
1741
|
cfg.line_length_max,
|
|
@@ -2028,6 +2041,7 @@ mod tests {
|
|
|
2028
2041
|
["kwargs", "options", "opts"].map(String::from).to_vec(), // af: RedundantKeywordRestArgumentNames
|
|
2029
2042
|
["blk", "block", "proc"].map(String::from).to_vec(), // af: RedundantBlockArgumentNames
|
|
2030
2043
|
vec!["delegate".to_string()], // duplicate_methods: DelegatingMethods
|
|
2044
|
+
vec![], // method_name: ForbiddenIdentifiers
|
|
2031
2045
|
];
|
|
2032
2046
|
// Performance segment (origin 1): enabled, with the SafeMultiline
|
|
2033
2047
|
// defaults and RuboCop's default preferred method for Detect
|
|
@@ -2585,7 +2599,7 @@ mod tests {
|
|
|
2585
2599
|
src.as_bytes(),
|
|
2586
2600
|
0,
|
|
2587
2601
|
2,
|
|
2588
|
-
|
|
2602
|
+
0,
|
|
2589
2603
|
);
|
|
2590
2604
|
assert!(!fa_alone.is_empty());
|
|
2591
2605
|
assert_eq!(bundle.first_argument_indentation.len(), fa_alone.len());
|
|
@@ -105,9 +105,10 @@ pub struct DupMethodEvent {
|
|
|
105
105
|
/// 1.89 the suffix is `"@#{path}:#{line}:#{begin_pos}"`
|
|
106
106
|
/// (`anon_block_identity`), distinguishing blocks that share a line.
|
|
107
107
|
pub scope_begin: i64,
|
|
108
|
-
/// A `
|
|
109
|
-
///
|
|
110
|
-
|
|
108
|
+
/// A `track_intentional_redefinition` event (1.89 self-alias trick, 1.90
|
|
109
|
+
/// Active Support markers): `name` carries the humanized method name;
|
|
110
|
+
/// the wrapper records it and skips the bookkeeping.
|
|
111
|
+
pub intentional_redefinition: bool,
|
|
111
112
|
/// The key carries a scope id (`scope_id` non-nil in stock) — gates the
|
|
112
113
|
/// project-index cross-file check in the wrapper.
|
|
113
114
|
pub scoped: bool,
|
|
@@ -116,6 +117,8 @@ pub struct DupMethodEvent {
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
const RESTRICT_ON_SEND: &[&[u8]] = &[
|
|
120
|
+
b"silence_redefinition_of_method",
|
|
121
|
+
b"redefine_method",
|
|
119
122
|
b"alias_method",
|
|
120
123
|
b"attr_reader",
|
|
121
124
|
b"attr_writer",
|
|
@@ -727,17 +730,19 @@ impl<'s> DuplicateMethodsRule<'s> {
|
|
|
727
730
|
line,
|
|
728
731
|
rescue_scope,
|
|
729
732
|
scope_begin,
|
|
730
|
-
|
|
733
|
+
intentional_redefinition: false,
|
|
731
734
|
scoped,
|
|
732
735
|
inside_def,
|
|
733
736
|
});
|
|
734
737
|
}
|
|
735
738
|
|
|
736
|
-
/// Stock `
|
|
737
|
-
/// `alias_method :foo, :foo`
|
|
738
|
-
///
|
|
739
|
+
/// Stock `track_intentional_redefinition`: `alias foo foo` /
|
|
740
|
+
/// `alias_method :foo, :foo` (1.89) and, with
|
|
741
|
+
/// `ActiveSupportExtensionsEnabled`, `silence_redefinition_of_method
|
|
742
|
+
/// :foo` / `redefine_method(:foo)` (1.90) mark an intentional
|
|
743
|
+
/// redefinition of a method defined in another file. Only tracked when
|
|
739
744
|
/// `parent_module_name` resolves, like stock.
|
|
740
|
-
fn
|
|
745
|
+
fn track_intentional_redefinition(&mut self, name: &str) {
|
|
741
746
|
let Some(scope) = self.pmn(self.frames.len()) else {
|
|
742
747
|
return;
|
|
743
748
|
};
|
|
@@ -753,7 +758,7 @@ impl<'s> DuplicateMethodsRule<'s> {
|
|
|
753
758
|
line: 0,
|
|
754
759
|
rescue_scope: 0,
|
|
755
760
|
scope_begin: -1,
|
|
756
|
-
|
|
761
|
+
intentional_redefinition: true,
|
|
757
762
|
scoped: false,
|
|
758
763
|
inside_def: false,
|
|
759
764
|
});
|
|
@@ -930,7 +935,7 @@ impl<'s> DuplicateMethodsRule<'s> {
|
|
|
930
935
|
return;
|
|
931
936
|
};
|
|
932
937
|
if new == old {
|
|
933
|
-
self.
|
|
938
|
+
self.track_intentional_redefinition(&new);
|
|
934
939
|
return;
|
|
935
940
|
}
|
|
936
941
|
if self.if_depth > 0 {
|
|
@@ -1016,7 +1021,7 @@ impl<'s> DuplicateMethodsRule<'s> {
|
|
|
1016
1021
|
return;
|
|
1017
1022
|
};
|
|
1018
1023
|
if new == old {
|
|
1019
|
-
self.
|
|
1024
|
+
self.track_intentional_redefinition(&new);
|
|
1020
1025
|
return;
|
|
1021
1026
|
}
|
|
1022
1027
|
if self.if_depth > 0 {
|
|
@@ -1078,6 +1083,20 @@ impl<'s> DuplicateMethodsRule<'s> {
|
|
|
1078
1083
|
let defined = values.last().unwrap().clone().unwrap();
|
|
1079
1084
|
self.found_instance_method(&defined, off, node_start);
|
|
1080
1085
|
}
|
|
1086
|
+
// `active_support_redefinition_marker` (1.90): `(send nil?
|
|
1087
|
+
// {:silence_redefinition_of_method :redefine_method} ({sym str}
|
|
1088
|
+
// $_) ...)`. Scope resolution starts from the call node itself —
|
|
1089
|
+
// stock passes `node.block_node || node` because parser hangs
|
|
1090
|
+
// the block above the send, prism below it.
|
|
1091
|
+
b"silence_redefinition_of_method" | b"redefine_method" => {
|
|
1092
|
+
if !self.cfg.active_support_extensions_enabled {
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
let Some(marked) = args.first().and_then(sym_or_str_value) else {
|
|
1096
|
+
return;
|
|
1097
|
+
};
|
|
1098
|
+
self.track_intentional_redefinition(&marked);
|
|
1099
|
+
}
|
|
1081
1100
|
b"def_delegators" | b"def_instance_delegators" => {
|
|
1082
1101
|
if args.len() < 2 {
|
|
1083
1102
|
return;
|
|
@@ -1450,7 +1469,7 @@ mod tests {
|
|
|
1450
1469
|
fn events(src: &str) -> Vec<(String, String, i64, i64, u8)> {
|
|
1451
1470
|
all_events(src)
|
|
1452
1471
|
.into_iter()
|
|
1453
|
-
.filter(|e| !e.
|
|
1472
|
+
.filter(|e| !e.intentional_redefinition)
|
|
1454
1473
|
.map(|e| (e.key, e.name, e.scope_line, e.sexp_start, e.rescue_scope))
|
|
1455
1474
|
.collect()
|
|
1456
1475
|
}
|
|
@@ -1667,11 +1686,11 @@ mod tests {
|
|
|
1667
1686
|
fn alias_forms() {
|
|
1668
1687
|
assert_eq!(keys("class A\n alias foo bar\nend\n"), vec!["A#foo"]);
|
|
1669
1688
|
assert_eq!(keys("class A\n alias foo foo\nend\n"), Vec::<String>::new());
|
|
1670
|
-
// ...but 1.89 tracks it as
|
|
1689
|
+
// ...but 1.89 tracks it as an intentional-redefinition event (the
|
|
1671
1690
|
// cross-file redefinition marker).
|
|
1672
1691
|
let sa: Vec<DupMethodEvent> = all_events("class A\n alias foo foo\nend\n")
|
|
1673
1692
|
.into_iter()
|
|
1674
|
-
.filter(|e| e.
|
|
1693
|
+
.filter(|e| e.intentional_redefinition)
|
|
1675
1694
|
.collect();
|
|
1676
1695
|
assert_eq!(sa.len(), 1);
|
|
1677
1696
|
assert_eq!(sa[0].name, "A#foo");
|
|
@@ -1721,6 +1740,30 @@ mod tests {
|
|
|
1721
1740
|
assert_eq!(evts[0].key, "A#foo");
|
|
1722
1741
|
}
|
|
1723
1742
|
|
|
1743
|
+
// Active Support redefinition markers (1.90): tracked like the
|
|
1744
|
+
// self-alias trick, only with `ActiveSupportExtensionsEnabled`. The
|
|
1745
|
+
// `redefine_method` block hangs off the call in prism, so the scope
|
|
1746
|
+
// still resolves to the enclosing class.
|
|
1747
|
+
#[test]
|
|
1748
|
+
fn active_support_redefinition_markers() {
|
|
1749
|
+
let src = "class A\n silence_redefinition_of_method :foo\n redefine_method('bar') do\n 1\n end\nend\n";
|
|
1750
|
+
let marked = |enabled: bool| {
|
|
1751
|
+
check_duplicate_methods(
|
|
1752
|
+
src.as_bytes(),
|
|
1753
|
+
&Config {
|
|
1754
|
+
active_support_extensions_enabled: enabled,
|
|
1755
|
+
delegating_methods: vec!["delegate".to_string()],
|
|
1756
|
+
},
|
|
1757
|
+
)
|
|
1758
|
+
.into_iter()
|
|
1759
|
+
.filter(|e| e.intentional_redefinition)
|
|
1760
|
+
.map(|e| e.name)
|
|
1761
|
+
.collect::<Vec<_>>()
|
|
1762
|
+
};
|
|
1763
|
+
assert_eq!(marked(true), vec!["A#foo", "A#bar"]);
|
|
1764
|
+
assert!(marked(false).is_empty());
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1724
1767
|
// delegate prefix handling.
|
|
1725
1768
|
#[test]
|
|
1726
1769
|
fn delegate_prefix() {
|