evilution 1.4.0 → 1.5.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/interactions.jsonl +70 -0
  3. data/CHANGELOG.md +50 -0
  4. data/README.md +64 -22
  5. data/docs/architecture.md +56 -12
  6. data/docs/isolation.md +82 -0
  7. data/lib/evilution/ast/class_body.rb +101 -0
  8. data/lib/evilution/ast/included_block.rb +20 -6
  9. data/lib/evilution/ast/never_nil.rb +36 -0
  10. data/lib/evilution/ast/parser.rb +94 -31
  11. data/lib/evilution/ast/round_half_mode.rb +38 -0
  12. data/lib/evilution/ast/source_surgeon.rb +2 -3
  13. data/lib/evilution/ast/syntax_check.rb +56 -0
  14. data/lib/evilution/ast/uncovered_code.rb +7 -7
  15. data/lib/evilution/cli/exit_guard.rb +26 -4
  16. data/lib/evilution/integration/base.rb +10 -2
  17. data/lib/evilution/integration/loading/body_call_neutralizer.rb +59 -14
  18. data/lib/evilution/integration/loading/concern_redeclaration.rb +33 -14
  19. data/lib/evilution/integration/loading/concern_state_cleaner.rb +3 -3
  20. data/lib/evilution/integration/loading/mutation_applier.rb +33 -6
  21. data/lib/evilution/integration/loading/own_methods.rb +87 -0
  22. data/lib/evilution/integration/loading/redefinition_recovery.rb +2 -3
  23. data/lib/evilution/integration/loading/source_evaluator.rb +9 -2
  24. data/lib/evilution/integration/loading/superseded_modules.rb +103 -0
  25. data/lib/evilution/integration/loading/syntax_validator.rb +2 -2
  26. data/lib/evilution/isolation/fork.rb +82 -10
  27. data/lib/evilution/isolation/in_process.rb +79 -4
  28. data/lib/evilution/mcp/info_tool/status_glossary.rb +13 -2
  29. data/lib/evilution/mcp/info_tool.rb +3 -2
  30. data/lib/evilution/mutation.rb +18 -11
  31. data/lib/evilution/mutator/base.rb +27 -7
  32. data/lib/evilution/mutator/constant_value_subjects.rb +13 -0
  33. data/lib/evilution/mutator/operator/alias_removal.rb +11 -81
  34. data/lib/evilution/mutator/operator/argument_nil_substitution.rb +2 -2
  35. data/lib/evilution/mutator/operator/argument_removal.rb +2 -2
  36. data/lib/evilution/mutator/operator/array_literal.rb +29 -0
  37. data/lib/evilution/mutator/operator/attr_accessor_swap.rb +68 -0
  38. data/lib/evilution/mutator/operator/boolean_literal_replacement.rb +2 -0
  39. data/lib/evilution/mutator/operator/call_to_nil.rb +12 -3
  40. data/lib/evilution/mutator/operator/complex_literal.rb +39 -0
  41. data/lib/evilution/mutator/operator/compound_assignment.rb +47 -0
  42. data/lib/evilution/mutator/operator/constant_namespace_strip.rb +57 -0
  43. data/lib/evilution/mutator/operator/constant_read_to_nil.rb +58 -0
  44. data/lib/evilution/mutator/operator/constant_write_to_nil.rb +32 -0
  45. data/lib/evilution/mutator/operator/data_struct_member.rb +1 -1
  46. data/lib/evilution/mutator/operator/explicit_super_mutation.rb +2 -2
  47. data/lib/evilution/mutator/operator/float_literal.rb +54 -19
  48. data/lib/evilution/mutator/operator/freeze_removal.rb +86 -0
  49. data/lib/evilution/mutator/operator/hash_literal.rb +51 -0
  50. data/lib/evilution/mutator/operator/index_range_to_drop.rb +67 -0
  51. data/lib/evilution/mutator/operator/index_receiver_to_self.rb +20 -0
  52. data/lib/evilution/mutator/operator/index_to_key_predicate.rb +58 -0
  53. data/lib/evilution/mutator/operator/index_write_to_value.rb +37 -0
  54. data/lib/evilution/mutator/operator/integer_literal.rb +39 -9
  55. data/lib/evilution/mutator/operator/memoization_break.rb +18 -0
  56. data/lib/evilution/mutator/operator/mixin_removal.rb +18 -55
  57. data/lib/evilution/mutator/operator/nil_replacement.rb +2 -0
  58. data/lib/evilution/mutator/operator/operator_write_receiver_promotion.rb +38 -0
  59. data/lib/evilution/mutator/operator/range_replacement.rb +2 -0
  60. data/lib/evilution/mutator/operator/rational_literal.rb +40 -0
  61. data/lib/evilution/mutator/operator/reduce_to_sum.rb +1 -1
  62. data/lib/evilution/mutator/operator/rescue_class_widening.rb +54 -0
  63. data/lib/evilution/mutator/operator/round_half_mode_swap.rb +36 -0
  64. data/lib/evilution/mutator/operator/safe_navigation_insertion.rb +57 -0
  65. data/lib/evilution/mutator/operator/safe_navigation_removal.rb +2 -24
  66. data/lib/evilution/mutator/operator/short_circuit_to_eager.rb +34 -0
  67. data/lib/evilution/mutator/operator/sleep_to_zero.rb +43 -0
  68. data/lib/evilution/mutator/operator/splat_operator.rb +16 -24
  69. data/lib/evilution/mutator/operator/string_literal.rb +29 -0
  70. data/lib/evilution/mutator/operator/superclass_removal.rb +14 -40
  71. data/lib/evilution/mutator/operator/symbol_literal.rb +47 -2
  72. data/lib/evilution/mutator/operator/to_i_to_integer.rb +1 -1
  73. data/lib/evilution/mutator/operator/variable_read_to_nil.rb +113 -0
  74. data/lib/evilution/mutator/operator/visibility_removal.rb +74 -0
  75. data/lib/evilution/mutator/primitives.rb +24 -2
  76. data/lib/evilution/mutator/receiver_positions.rb +79 -0
  77. data/lib/evilution/mutator/registry.rb +29 -2
  78. data/lib/evilution/parallel/work_queue/channel/frame.rb +6 -0
  79. data/lib/evilution/parallel/work_queue/channel.rb +58 -5
  80. data/lib/evilution/parallel/work_queue/dispatcher/reply.rb +41 -0
  81. data/lib/evilution/parallel/work_queue/dispatcher.rb +14 -1
  82. data/lib/evilution/parallel/work_queue/worker/loop.rb +5 -0
  83. data/lib/evilution/parallel/work_queue/worker.rb +13 -4
  84. data/lib/evilution/parallel/work_queue.rb +15 -9
  85. data/lib/evilution/runner/mutation_executor/strategy/parallel.rb +10 -0
  86. data/lib/evilution/runner/subject_pipeline/target.rb +86 -0
  87. data/lib/evilution/runner/subject_pipeline.rb +20 -51
  88. data/lib/evilution/runner.rb +1 -1
  89. data/lib/evilution/subject.rb +18 -1
  90. data/lib/evilution/version.rb +1 -1
  91. data/lib/evilution.rb +62 -0
  92. metadata +32 -2
@@ -7,16 +7,20 @@ require_relative "../diagnostic"
7
7
  require_relative "../git/changed_files"
8
8
 
9
9
  class Evilution::Runner::SubjectPipeline
10
- def initialize(config, parser:)
10
+ autoload :Target, File.expand_path("subject_pipeline/target", __dir__)
11
+
12
+ def initialize(config, parser:, registry: Evilution::Mutator::Registry.for_profile(config.profile))
11
13
  @config = config
12
14
  @parser = parser
15
+ @registry = registry
16
+ @target = Target.parse(config.target)
13
17
  end
14
18
 
15
19
  def call
16
20
  subjects = parse_subjects
17
21
  @subjects_by_file = subjects.group_by(&:file_path)
18
- subjects = filter_by_descendants(subjects) if descendants_target?
19
- subjects = filter_by_target(subjects) if method_target?
22
+ subjects = filter_by_descendants(subjects) if target.descendants?
23
+ subjects = filter_by_target(subjects) if target.method?
20
24
  subjects = filter_by_line_ranges(subjects) if config.line_ranges?
21
25
  subjects
22
26
  end
@@ -30,7 +34,7 @@ class Evilution::Runner::SubjectPipeline
30
34
  # generated for, per file -- known only once #call's subjects are planned.
31
35
  #
32
36
  # A line range is checked as given; a whole file only when it has no
33
- # subjects at all -- every class with an `include` or a constant would
37
+ # subjects at all -- every class with an `include` or a DSL call would
34
38
  # otherwise warn.
35
39
  def report_uncovered_code(mutated_lines = {})
36
40
  by_file = @subjects_by_file || {}
@@ -49,10 +53,13 @@ class Evilution::Runner::SubjectPipeline
49
53
 
50
54
  private
51
55
 
52
- attr_reader :config, :parser
56
+ attr_reader :config, :parser, :registry, :target
53
57
 
58
+ # The parser finds every subject there is; those of a kind no operator of
59
+ # this run mutates are left out, so that they neither count as covering
60
+ # their lines nor show up with nothing generated for them.
54
61
  def parse_subjects
55
- target_files.flat_map { |file| parser.call(file) }
62
+ target_files.flat_map { |file| parser.call(file) }.select { |subject| registry.accepts?(subject) }
56
63
  end
57
64
 
58
65
  def uncovered_entry(file, file_subjects, mutated_lines)
@@ -71,24 +78,12 @@ class Evilution::Runner::SubjectPipeline
71
78
  def warn_uncovered(entry)
72
79
  Evilution::Diagnostic.warn(
73
80
  "[evilution] #{entry[:file]}:#{entry[:lines].join(", ")} holds code outside every subject " \
74
- "(class-body code such as DSL calls and constants is not mutated); no mutations target those lines."
81
+ "(class-body code such as DSL calls is not mutated); no mutations target those lines."
75
82
  )
76
83
  end
77
84
 
78
- def source_glob_target?
79
- config.target&.start_with?("source:")
80
- end
81
-
82
- def descendants_target?
83
- config.target&.start_with?("descendants:")
84
- end
85
-
86
- def method_target?
87
- config.target? && !source_glob_target? && !descendants_target?
88
- end
89
-
90
85
  def resolve_source_glob
91
- pattern = config.target.delete_prefix("source:")
86
+ pattern = target.value
92
87
  files = Dir.glob(pattern)
93
88
  raise Evilution::Error, "no files found matching '#{pattern}'" if files.empty?
94
89
 
@@ -96,10 +91,9 @@ class Evilution::Runner::SubjectPipeline
96
91
  end
97
92
 
98
93
  def filter_by_descendants(subjects)
99
- base_name = config.target.delete_prefix("descendants:")
100
94
  inheritance = Evilution::AST::InheritanceScanner.call(target_files)
101
- class_names = resolve_descendant_set(base_name, inheritance)
102
- raise Evilution::Error, "no classes found matching '#{config.target}'" if class_names.empty?
95
+ class_names = resolve_descendant_set(target.value, inheritance)
96
+ raise Evilution::Error, "no classes found matching '#{target}'" if class_names.empty?
103
97
 
104
98
  subjects.select { |s| class_names.include?(s.name.split(/[#.]/).first) }
105
99
  end
@@ -125,14 +119,14 @@ class Evilution::Runner::SubjectPipeline
125
119
  end
126
120
 
127
121
  def filter_by_target(subjects)
128
- matched = subjects.select(&target_matcher)
122
+ matched = subjects.select { |subject| target.selects?(subject) }
129
123
  raise Evilution::Error, build_no_match_error if matched.empty?
130
124
 
131
125
  matched
132
126
  end
133
127
 
134
128
  def resolve_target_files
135
- return resolve_source_glob if source_glob_target?
129
+ return resolve_source_glob if target.source_glob?
136
130
  return config.target_files unless config.target_files.empty?
137
131
 
138
132
  @used_git_fallback = true
@@ -140,38 +134,13 @@ class Evilution::Runner::SubjectPipeline
140
134
  end
141
135
 
142
136
  def build_no_match_error
143
- base = "no subject matched '#{config.target}'"
137
+ base = "no subject matched '#{target}'"
144
138
  return base unless @used_git_fallback
145
139
 
146
140
  "#{base}; scanned git-changed files only. Pass file paths or " \
147
141
  "--target source:<glob> to scan the full codebase."
148
142
  end
149
143
 
150
- def target_matcher
151
- target = config.target
152
- return wildcard_matcher(target.chomp("*")) if target.end_with?("*")
153
- return prefix_matcher(target) if target.end_with?("#", ".")
154
- return exact_matcher(target) if target.include?("#") || target.include?(".")
155
-
156
- class_matcher(target)
157
- end
158
-
159
- def wildcard_matcher(prefix)
160
- ->(s) { s.name.split(/[#.]/).first.start_with?(prefix) }
161
- end
162
-
163
- def prefix_matcher(prefix)
164
- ->(s) { s.name.start_with?(prefix) }
165
- end
166
-
167
- def exact_matcher(target)
168
- ->(s) { s.name == target }
169
- end
170
-
171
- def class_matcher(target)
172
- ->(s) { s.name == target || s.name.start_with?("#{target}#") || s.name.start_with?("#{target}.") }
173
- end
174
-
175
144
  def filter_by_line_ranges(subjects)
176
145
  subjects.select do |subject|
177
146
  range = config.line_ranges[subject.file_path]
@@ -71,7 +71,7 @@ class Evilution::Runner
71
71
  attr_reader :parser, :registry, :cache, :on_result, :hooks
72
72
 
73
73
  def subject_pipeline
74
- @subject_pipeline ||= Evilution::Runner::SubjectPipeline.new(config, parser: parser)
74
+ @subject_pipeline ||= Evilution::Runner::SubjectPipeline.new(config, parser: parser, registry: registry)
75
75
  end
76
76
 
77
77
  def mutation_planner
@@ -5,16 +5,33 @@
5
5
  # constant outside any method, such as `Point = Data.define(:x, :y)`. A :scope
6
6
  # or :aasm subject is the body of a callable handed to a class-body
7
7
  # declaration.
8
+ #
9
+ # A :constant_write subject is any other assignment to a constant, the whole
10
+ # of it: `LIMIT = 10`. Applying a mutation re-evaluates the file, which
11
+ # assigns the constant again, and evaluating the original after the tests
12
+ # puts it back. What read the constant while the file first loaded is
13
+ # not run again -- a class-body call (`validates length: { maximum: LIMIT }`)
14
+ # or a constant computed from it in another file keeps the old value -- so
15
+ # only code that reads the constant when called sees the mutant.
16
+ #
17
+ # A subject written in a concern's `included` or `prepended` block is marked
18
+ # `concern_hook`: the block runs in each class that takes the concern, so a
19
+ # mutation of it has to be run again on the classes that took it already.
8
20
  class Evilution::Subject
9
21
  attr_reader :name, :file_path, :line_number, :source, :node, :kind
10
22
 
11
- def initialize(name:, file_path:, line_number:, source:, node:, kind: :method)
23
+ def initialize(name:, file_path:, line_number:, source:, node:, kind: :method, concern_hook: false)
12
24
  @name = name
13
25
  @file_path = file_path
14
26
  @line_number = line_number
15
27
  @source = source
16
28
  @node = node
17
29
  @kind = kind
30
+ @concern_hook = concern_hook
31
+ end
32
+
33
+ def concern_hook?
34
+ @concern_hook
18
35
  end
19
36
 
20
37
  def release_node!
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evilution
4
- VERSION = "1.4.0"
4
+ VERSION = "1.5.0"
5
5
  end
data/lib/evilution.rb CHANGED
@@ -27,6 +27,8 @@ require_relative "evilution/mutator/operator/comparison_replacement"
27
27
  require_relative "evilution/mutator/operator/boolean_literal_replacement"
28
28
  require_relative "evilution/mutator/operator/integer_literal"
29
29
  require_relative "evilution/mutator/operator/float_literal"
30
+ require_relative "evilution/mutator/operator/complex_literal"
31
+ require_relative "evilution/mutator/operator/rational_literal"
30
32
  require_relative "evilution/mutator/operator/nil_replacement"
31
33
  require_relative "evilution/mutator/operator/boolean_operator_replacement"
32
34
  require_relative "evilution/mutator/operator/boolean_operand_promotion"
@@ -65,6 +67,7 @@ require_relative "evilution/mutator/operator/argument_order_permutation"
65
67
  require_relative "evilution/mutator/operator/keyword_value_swap"
66
68
  require_relative "evilution/mutator/operator/comparison_operand_swap"
67
69
  require_relative "evilution/mutator/operator/integer_division_to_fdiv"
70
+ require_relative "evilution/mutator/operator/round_half_mode_swap"
68
71
  require_relative "evilution/mutator/operator/off_by_one_boundary"
69
72
  require_relative "evilution/mutator/operator/format_specifier_swap"
70
73
  require_relative "evilution/mutator/operator/exception_swallow"
@@ -81,6 +84,23 @@ require_relative "evilution/mutator/operator/rescue_handler_promotion"
81
84
  require_relative "evilution/mutator/operator/rescue_handler_concatenation"
82
85
  require_relative "evilution/mutator/operator/rescue_else_concatenation"
83
86
  require_relative "evilution/mutator/operator/return_keyword_removal"
87
+ require_relative "evilution/mutator/operator/memoization_break"
88
+ require_relative "evilution/mutator/operator/short_circuit_to_eager"
89
+ require_relative "evilution/mutator/operator/freeze_removal"
90
+ require_relative "evilution/mutator/operator/rescue_class_widening"
91
+ require_relative "evilution/mutator/operator/visibility_removal"
92
+ require_relative "evilution/mutator/operator/attr_accessor_swap"
93
+ require_relative "evilution/mutator/operator/sleep_to_zero"
94
+ require_relative "evilution/mutator/operator/index_receiver_to_self"
95
+ require_relative "evilution/mutator/operator/index_to_key_predicate"
96
+ require_relative "evilution/mutator/operator/index_range_to_drop"
97
+ require_relative "evilution/mutator/operator/index_write_to_value"
98
+ require_relative "evilution/mutator/operator/constant_read_to_nil"
99
+ require_relative "evilution/mutator/operator/constant_namespace_strip"
100
+ require_relative "evilution/mutator/operator/constant_write_to_nil"
101
+ require_relative "evilution/mutator/operator/variable_read_to_nil"
102
+ require_relative "evilution/mutator/operator/operator_write_receiver_promotion"
103
+ require_relative "evilution/mutator/operator/safe_navigation_insertion"
84
104
  require_relative "evilution/mutator/operator/arithmetic_replacement"
85
105
  require_relative "evilution/mutator/operator/string_literal"
86
106
  require_relative "evilution/mutator/operator/array_literal"
@@ -233,6 +253,48 @@ module Evilution
233
253
  @in_isolated_worker = previous
234
254
  end
235
255
 
256
+ # Marks the stretch in which the tests run against a mutation whose source has
257
+ # already loaded. A fork child that dies in it reports the death as the
258
+ # mutation's doing; one that dies earlier cannot say so.
259
+ #
260
+ # The child asks at exit, and by then the block is over in one of two ways.
261
+ # A stack overflow that exhausts the machine stack before the VM's own makes
262
+ # Ruby run neither `rescue` nor `ensure`, so the mark is still set. Which of
263
+ # the two stacks gives out first depends on the stack limit of the process,
264
+ # not on the Ruby version. Otherwise the exception unwinds through here, the
265
+ # mark is cleared, and the exception itself is kept to be recognised by.
266
+ def self.while_running_tests
267
+ previous = @running_tests
268
+ @running_tests = true
269
+ @tests_left_by = nil
270
+ yield
271
+ rescue Exception => e # rubocop:disable Lint/RescueException -- recorded and re-raised, never handled
272
+ @tests_left_by = e
273
+ raise
274
+ ensure
275
+ @running_tests = previous
276
+ end
277
+
278
+ def self.running_tests?
279
+ @running_tests == true
280
+ end
281
+
282
+ # Whether a process dying on `error` is dying of its test run.
283
+ def self.died_running_tests?(error)
284
+ running_tests? || @tests_left_by.equal?(error)
285
+ end
286
+
287
+ # Set by fork isolation in the child it forks for one mutation. Such a
288
+ # process applies its mutation, runs the tests and ends, so work that only
289
+ # serves a later mutation in the same process can be left out of it.
290
+ def self.single_mutation_process!
291
+ @single_mutation_process = true
292
+ end
293
+
294
+ def self.single_mutation_process?
295
+ @single_mutation_process == true
296
+ end
297
+
236
298
  # Base directory for resolving project-relative paths. An isolated worker
237
299
  # has chdir'd into a per-mutation sandbox (EV-wqxu / GH #1278), so callers
238
300
  # in that context must anchor against PROJECT_ROOT rather than Dir.pwd —
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evilution
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Kiselev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-08 00:00:00.000000000 Z
11
+ date: 2026-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -142,12 +142,14 @@ files:
142
142
  - lib/evilution/ast.rb
143
143
  - lib/evilution/ast/aasm_declaration.rb
144
144
  - lib/evilution/ast/callback_declaration.rb
145
+ - lib/evilution/ast/class_body.rb
145
146
  - lib/evilution/ast/constant_names.rb
146
147
  - lib/evilution/ast/heredoc_span.rb
147
148
  - lib/evilution/ast/included_block.rb
148
149
  - lib/evilution/ast/inheritance_scanner.rb
149
150
  - lib/evilution/ast/literal_callable.rb
150
151
  - lib/evilution/ast/local_reads.rb
152
+ - lib/evilution/ast/never_nil.rb
151
153
  - lib/evilution/ast/parser.rb
152
154
  - lib/evilution/ast/pattern.rb
153
155
  - lib/evilution/ast/pattern/filter.rb
@@ -155,9 +157,11 @@ files:
155
157
  - lib/evilution/ast/pattern/method_name.rb
156
158
  - lib/evilution/ast/pattern/parser.rb
157
159
  - lib/evilution/ast/regexp_pattern.rb
160
+ - lib/evilution/ast/round_half_mode.rb
158
161
  - lib/evilution/ast/scope_declaration.rb
159
162
  - lib/evilution/ast/sorbet_sig_detector.rb
160
163
  - lib/evilution/ast/source_surgeon.rb
164
+ - lib/evilution/ast/syntax_check.rb
161
165
  - lib/evilution/ast/uncovered_code.rb
162
166
  - lib/evilution/ast/value_object_definition.rb
163
167
  - lib/evilution/baseline.rb
@@ -282,9 +286,11 @@ files:
282
286
  - lib/evilution/integration/loading/concern_state_cleaner.rb
283
287
  - lib/evilution/integration/loading/constant_pinner.rb
284
288
  - lib/evilution/integration/loading/mutation_applier.rb
289
+ - lib/evilution/integration/loading/own_methods.rb
285
290
  - lib/evilution/integration/loading/redefinition_recovery.rb
286
291
  - lib/evilution/integration/loading/reeval_warning_filter.rb
287
292
  - lib/evilution/integration/loading/source_evaluator.rb
293
+ - lib/evilution/integration/loading/superseded_modules.rb
288
294
  - lib/evilution/integration/loading/syntax_validator.rb
289
295
  - lib/evilution/integration/loading/test_class_cache.rb
290
296
  - lib/evilution/integration/loading/test_load_path.rb
@@ -353,6 +359,7 @@ files:
353
359
  - lib/evilution/mutation.rb
354
360
  - lib/evilution/mutator.rb
355
361
  - lib/evilution/mutator/base.rb
362
+ - lib/evilution/mutator/constant_value_subjects.rb
356
363
  - lib/evilution/mutator/operator.rb
357
364
  - lib/evilution/mutator/operator/alias_removal.rb
358
365
  - lib/evilution/mutator/operator/argument_list_removal.rb
@@ -364,6 +371,7 @@ files:
364
371
  - lib/evilution/mutator/operator/arithmetic_replacement.rb
365
372
  - lib/evilution/mutator/operator/array_coercion_to_literal.rb
366
373
  - lib/evilution/mutator/operator/array_literal.rb
374
+ - lib/evilution/mutator/operator/attr_accessor_swap.rb
367
375
  - lib/evilution/mutator/operator/attribute_write_to_read.rb
368
376
  - lib/evilution/mutator/operator/bang_method.rb
369
377
  - lib/evilution/mutator/operator/begin_unwrap.rb
@@ -392,11 +400,15 @@ files:
392
400
  - lib/evilution/mutator/operator/collection_return.rb
393
401
  - lib/evilution/mutator/operator/comparison_operand_swap.rb
394
402
  - lib/evilution/mutator/operator/comparison_replacement.rb
403
+ - lib/evilution/mutator/operator/complex_literal.rb
395
404
  - lib/evilution/mutator/operator/compound_assignment.rb
396
405
  - lib/evilution/mutator/operator/conditional_branch.rb
397
406
  - lib/evilution/mutator/operator/conditional_flip.rb
398
407
  - lib/evilution/mutator/operator/conditional_negation.rb
399
408
  - lib/evilution/mutator/operator/const_get_to_constant_path.rb
409
+ - lib/evilution/mutator/operator/constant_namespace_strip.rb
410
+ - lib/evilution/mutator/operator/constant_read_to_nil.rb
411
+ - lib/evilution/mutator/operator/constant_write_to_nil.rb
400
412
  - lib/evilution/mutator/operator/data_struct_member.rb
401
413
  - lib/evilution/mutator/operator/defined_check.rb
402
414
  - lib/evilution/mutator/operator/dig_to_fetch_chain.rb
@@ -410,13 +422,18 @@ files:
410
422
  - lib/evilution/mutator/operator/format_specifier_swap.rb
411
423
  - lib/evilution/mutator/operator/forwarded_argument_drop.rb
412
424
  - lib/evilution/mutator/operator/forwarding_super_to_explicit.rb
425
+ - lib/evilution/mutator/operator/freeze_removal.rb
413
426
  - lib/evilution/mutator/operator/global_variable_write.rb
414
427
  - lib/evilution/mutator/operator/hash_literal.rb
415
428
  - lib/evilution/mutator/operator/if_branch_swap.rb
416
429
  - lib/evilution/mutator/operator/index_assignment_removal.rb
430
+ - lib/evilution/mutator/operator/index_range_to_drop.rb
431
+ - lib/evilution/mutator/operator/index_receiver_to_self.rb
417
432
  - lib/evilution/mutator/operator/index_to_at.rb
418
433
  - lib/evilution/mutator/operator/index_to_dig.rb
419
434
  - lib/evilution/mutator/operator/index_to_fetch.rb
435
+ - lib/evilution/mutator/operator/index_to_key_predicate.rb
436
+ - lib/evilution/mutator/operator/index_write_to_value.rb
420
437
  - lib/evilution/mutator/operator/inequality_to_negated_identity.rb
421
438
  - lib/evilution/mutator/operator/inline_rescue.rb
422
439
  - lib/evilution/mutator/operator/instance_variable_write.rb
@@ -430,6 +447,7 @@ files:
430
447
  - lib/evilution/mutator/operator/local_variable_assignment.rb
431
448
  - lib/evilution/mutator/operator/loop_body_to_raise.rb
432
449
  - lib/evilution/mutator/operator/loop_flip.rb
450
+ - lib/evilution/mutator/operator/memoization_break.rb
433
451
  - lib/evilution/mutator/operator/method_body_replacement.rb
434
452
  - lib/evilution/mutator/operator/method_body_to_raise.rb
435
453
  - lib/evilution/mutator/operator/method_body_to_super.rb
@@ -442,6 +460,7 @@ files:
442
460
  - lib/evilution/mutator/operator/no_matching_pattern_else.rb
443
461
  - lib/evilution/mutator/operator/numbered_parameter_swap.rb
444
462
  - lib/evilution/mutator/operator/off_by_one_boundary.rb
463
+ - lib/evilution/mutator/operator/operator_write_receiver_promotion.rb
445
464
  - lib/evilution/mutator/operator/optional_default_injection.rb
446
465
  - lib/evilution/mutator/operator/optional_parameter_to_required.rb
447
466
  - lib/evilution/mutator/operator/pattern_matching_alternative.rb
@@ -454,6 +473,7 @@ files:
454
473
  - lib/evilution/mutator/operator/predicate_to_nil.rb
455
474
  - lib/evilution/mutator/operator/proc_to_lambda.rb
456
475
  - lib/evilution/mutator/operator/range_replacement.rb
476
+ - lib/evilution/mutator/operator/rational_literal.rb
457
477
  - lib/evilution/mutator/operator/receiver_constructor_swap.rb
458
478
  - lib/evilution/mutator/operator/receiver_replacement.rb
459
479
  - lib/evilution/mutator/operator/redo_statement.rb
@@ -470,6 +490,7 @@ files:
470
490
  - lib/evilution/mutator/operator/regexp_option_removal.rb
471
491
  - lib/evilution/mutator/operator/regexp_quantifier_minimum_swap.rb
472
492
  - lib/evilution/mutator/operator/rescue_body_replacement.rb
493
+ - lib/evilution/mutator/operator/rescue_class_widening.rb
473
494
  - lib/evilution/mutator/operator/rescue_else_concatenation.rb
474
495
  - lib/evilution/mutator/operator/rescue_handler_concatenation.rb
475
496
  - lib/evilution/mutator/operator/rescue_handler_promotion.rb
@@ -478,9 +499,13 @@ files:
478
499
  - lib/evilution/mutator/operator/return_keyword_removal.rb
479
500
  - lib/evilution/mutator/operator/return_value_removal.rb
480
501
  - lib/evilution/mutator/operator/rightward_assignment.rb
502
+ - lib/evilution/mutator/operator/round_half_mode_swap.rb
503
+ - lib/evilution/mutator/operator/safe_navigation_insertion.rb
481
504
  - lib/evilution/mutator/operator/safe_navigation_removal.rb
482
505
  - lib/evilution/mutator/operator/scalar_return.rb
483
506
  - lib/evilution/mutator/operator/send_mutation.rb
507
+ - lib/evilution/mutator/operator/short_circuit_to_eager.rb
508
+ - lib/evilution/mutator/operator/sleep_to_zero.rb
484
509
  - lib/evilution/mutator/operator/splat_operator.rb
485
510
  - lib/evilution/mutator/operator/statement_deletion.rb
486
511
  - lib/evilution/mutator/operator/statement_reorder.rb
@@ -491,9 +516,12 @@ files:
491
516
  - lib/evilution/mutator/operator/symbol_to_proc_replacement.rb
492
517
  - lib/evilution/mutator/operator/to_i_to_integer.rb
493
518
  - lib/evilution/mutator/operator/typed_default_return.rb
519
+ - lib/evilution/mutator/operator/variable_read_to_nil.rb
520
+ - lib/evilution/mutator/operator/visibility_removal.rb
494
521
  - lib/evilution/mutator/operator/yield_statement.rb
495
522
  - lib/evilution/mutator/operator/zsuper_removal.rb
496
523
  - lib/evilution/mutator/primitives.rb
524
+ - lib/evilution/mutator/receiver_positions.rb
497
525
  - lib/evilution/mutator/registry.rb
498
526
  - lib/evilution/mutator/rescue_handlers.rb
499
527
  - lib/evilution/parallel.rb
@@ -504,6 +532,7 @@ files:
504
532
  - lib/evilution/parallel/work_queue/collection_state.rb
505
533
  - lib/evilution/parallel/work_queue/dispatcher.rb
506
534
  - lib/evilution/parallel/work_queue/dispatcher/deadline_tracker.rb
535
+ - lib/evilution/parallel/work_queue/dispatcher/reply.rb
507
536
  - lib/evilution/parallel/work_queue/validators.rb
508
537
  - lib/evilution/parallel/work_queue/validators/optional_positive_int.rb
509
538
  - lib/evilution/parallel/work_queue/validators/optional_positive_number.rb
@@ -628,6 +657,7 @@ files:
628
657
  - lib/evilution/runner/mutation_planner.rb
629
658
  - lib/evilution/runner/report_publisher.rb
630
659
  - lib/evilution/runner/subject_pipeline.rb
660
+ - lib/evilution/runner/subject_pipeline/target.rb
631
661
  - lib/evilution/runner/target_spec_audit.rb
632
662
  - lib/evilution/session.rb
633
663
  - lib/evilution/session/diff.rb