mutant 0.11.13 → 0.11.14

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mutant/ast/find_metaclass_containing.rb +6 -6
  3. data/lib/mutant/ast/meta/const.rb +1 -1
  4. data/lib/mutant/ast/meta/optarg.rb +1 -1
  5. data/lib/mutant/ast/meta/resbody.rb +1 -1
  6. data/lib/mutant/ast/meta/send.rb +1 -1
  7. data/lib/mutant/ast/meta/symbol.rb +1 -1
  8. data/lib/mutant/ast/meta.rb +1 -1
  9. data/lib/mutant/ast/named_children.rb +1 -1
  10. data/lib/mutant/ast/node_predicates.rb +1 -1
  11. data/lib/mutant/ast/nodes.rb +1 -1
  12. data/lib/mutant/ast/pattern/lexer.rb +1 -1
  13. data/lib/mutant/ast/pattern/parser.rb +1 -1
  14. data/lib/mutant/ast/pattern/source.rb +1 -1
  15. data/lib/mutant/ast/pattern/token.rb +1 -1
  16. data/lib/mutant/ast/pattern.rb +1 -1
  17. data/lib/mutant/ast/regexp/transformer/direct.rb +1 -1
  18. data/lib/mutant/ast/regexp/transformer/named_group.rb +1 -1
  19. data/lib/mutant/ast/regexp/transformer/options_group.rb +1 -1
  20. data/lib/mutant/ast/regexp/transformer/quantifier.rb +1 -1
  21. data/lib/mutant/ast/regexp/transformer/recursive.rb +1 -1
  22. data/lib/mutant/ast/regexp/transformer/root.rb +1 -1
  23. data/lib/mutant/ast/regexp/transformer/text.rb +1 -1
  24. data/lib/mutant/ast/regexp/transformer.rb +1 -1
  25. data/lib/mutant/ast/regexp.rb +1 -1
  26. data/lib/mutant/ast/sexp.rb +1 -1
  27. data/lib/mutant/ast/structure.rb +8 -3
  28. data/lib/mutant/ast/types.rb +1 -1
  29. data/lib/mutant/ast.rb +31 -29
  30. data/lib/mutant/config.rb +1 -1
  31. data/lib/mutant/matcher/method/instance.rb +3 -2
  32. data/lib/mutant/matcher/method/metaclass.rb +4 -3
  33. data/lib/mutant/matcher/method/singleton.rb +3 -2
  34. data/lib/mutant/matcher/method.rb +32 -23
  35. data/lib/mutant/mutator/node/block.rb +5 -3
  36. data/lib/mutant/parser.rb +0 -7
  37. data/lib/mutant/version.rb +1 -1
  38. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c08faadc47c13b47986719ddba1ca0437797643ff67c4d16869f6e195352fa2
4
- data.tar.gz: 3ea0e03ddff19eb0ae3566e611fbd2171dd0624cbae5c40903c4cbf3ade98ebb
3
+ metadata.gz: 58b6affbd17beee4a525b5efa35e83b18d3d65316ec5abd2b773c4722377e79b
4
+ data.tar.gz: 10b60ffd99ea8b477537bed09af2c122ffc14152a69c9a020ed09cca73dfa2d8
5
5
  SHA512:
6
- metadata.gz: c18497e6427a64d05f11dab3a0a177c2bdb99c00a5acb7984bfa76ef7083628afa16ede769a2152b06101dfe0876bd38de02633f8082b38baf1fef7e8c08576b
7
- data.tar.gz: 96348aa482664e934312d7e6fc363b69d94f5158bbb5af7feaef329814769cc645c1474625675e2def3aab0fafc3ab164fe151958a2650019c45084eeb6bfe87
6
+ metadata.gz: 39bd2f27290e3e3ba1ec6be8ae515759db5970fe121e9732797819bcb243c1038b0582c49e52fe7c6ab99d9332dfce4eb4fcf62b75558bd79954929bb432a8fd
7
+ data.tar.gz: da7555f1f168b6359163aeb3cd58dd69b5cb553da005830169cabdc9de949317f7ddae0790e6e84cc7990dfcd3d7c0c2c9b85f05c0b7b8de18bf96079d2c58e7
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Given an AST, finds the sclass that directly(-ish) contains the provided
6
6
  # node.
7
7
  # This won't match arbitrarily complex structures - it only searches the
@@ -10,7 +10,7 @@ module Mutant
10
10
  # Descending into 'begin' nodes is supported because these are generated for
11
11
  # the one-line syntax class << self; def foo; end
12
12
  class FindMetaclassContaining
13
- include NodePredicates, Concord.new(:root, :target), Procto
13
+ include NodePredicates, Concord.new(:ast, :target), Procto
14
14
 
15
15
  SCLASS_BODY_INDEX = 1
16
16
 
@@ -22,11 +22,11 @@ module Mutant
22
22
  #
23
23
  # @api private
24
24
  def call
25
- AST.find_last_path(root) do |current|
26
- next unless n_sclass?(current)
25
+ Structure.for(ast.node.type).each_node(ast.node) do |current|
26
+ return current if n_sclass?(current) && metaclass_of?(current)
27
+ end
27
28
 
28
- metaclass_of?(current)
29
- end.last
29
+ nil
30
30
  end
31
31
 
32
32
  private
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
  end # Meta
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
 
6
6
  # Helper methods to define named children
7
7
  module NamedChildren
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Module for node predicates
6
6
  module NodePredicates
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Singleton nodes
6
6
  module Nodes
7
7
  extend Sexp
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class Lexer
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # rubocop:disable Metrics/ClassLength
6
6
  # rubocop:disable Metrics/MethodLength
7
7
  class Pattern
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  class Source
7
7
  include Anima.new(:string)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  class Token
7
7
  include Anima.new(:type, :value, :location)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  include Adamantium
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for nodes which map directly to other domain
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for named groups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for option groups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for regexp quantifiers
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for nodes with children
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for root nodes
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Regexp AST transformer for nodes that encode a text value
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  # Regexp bijective mapper
7
7
  #
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Regexp source mapper
6
6
  module Regexp
7
7
  # Parse regex string into expression
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Mixin for node sexp syntax
6
6
  module Sexp
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # AST Structure metadata
6
6
  # rubocop:disable Metrics/ModuleLength
7
7
  module Structure
@@ -26,7 +26,7 @@ module Mutant
26
26
  end
27
27
 
28
28
  def value(node)
29
- node.children.fetch(index)
29
+ node.children.at(index)
30
30
  end
31
31
  end
32
32
 
@@ -246,7 +246,7 @@ module Mutant
246
246
  type: :class,
247
247
  fixed: Node.fixed(
248
248
  [
249
- [Node::Fixed::Descendant, :name],
249
+ [Node::Fixed::Attribute, :name],
250
250
  [Node::Fixed::Descendant, :superclass],
251
251
  [Node::Fixed::Descendant, :body]
252
252
  ]
@@ -386,6 +386,11 @@ module Mutant
386
386
  fixed: Node.fixed([[Node::Fixed::Attribute, :value]]),
387
387
  variable: nil
388
388
  ),
389
+ Node.new(
390
+ type: :forwarded_args,
391
+ fixed: EMPTY_ARRAY,
392
+ variable: nil
393
+ ),
389
394
  Node.new(
390
395
  type: :for,
391
396
  fixed: Node.fixed(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Groups of node types
6
6
  module Types # rubocop:disable Metrics/ModuleLength
7
7
  ASSIGNABLE_VARIABLES = Set.new(%i[ivasgn lvasgn cvasgn gvasgn]).freeze
data/lib/mutant/ast.rb CHANGED
@@ -1,41 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- # AST helpers
5
- module AST
6
-
7
- # Find last node satisfying predicate (as block)
8
- #
9
- # @return [Parser::AST::Node]
10
- # if satisfying node is found
11
- #
12
- # @yield [Parser::AST::Node]
13
- #
14
- # @yieldreturn [Boolean]
15
- # true in case node satisfies predicate
16
- #
17
- # @return [nil]
18
- # otherwise
19
- def self.find_last_path(node, &predicate)
20
- fail ArgumentError, 'block expected' unless block_given?
21
- path = []
22
- walk(node, [node]) do |candidate, stack|
23
- if predicate.call(candidate)
24
- path = stack.dup
25
- end
4
+ class AST
5
+ include Adamantium, Anima.new(
6
+ :node,
7
+ :comment_associations
8
+ )
9
+
10
+ class View
11
+ include Adamantium, Anima.new(:node, :path)
12
+ end
13
+
14
+ def on_line(line)
15
+ line_map.fetch(line, EMPTY_HASH).map do |node, path|
16
+ View.new(node: node, path: path)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def line_map
23
+ line_map = {}
24
+
25
+ walk_path(node) do |node, path|
26
+ expression = node.location.expression || next
27
+ (line_map[expression.line] ||= []) << [node, path]
26
28
  end
27
- path
29
+
30
+ line_map
28
31
  end
32
+ memoize :line_map
29
33
 
30
- def self.walk(node, stack, &block)
31
- block.call(node, stack)
34
+ def walk_path(node, stack = [node.type], &block)
35
+ block.call(node, stack.dup)
32
36
  node.children.grep(::Parser::AST::Node) do |child|
33
- stack.push(child)
34
- walk(child, stack, &block)
37
+ stack.push(child.type)
38
+ walk_path(child, stack, &block)
35
39
  stack.pop
36
40
  end
37
41
  end
38
- private_class_method :walk
39
-
40
42
  end # AST
41
43
  end # Mutant
data/lib/mutant/config.rb CHANGED
@@ -42,7 +42,7 @@ module Mutant
42
42
  MUTATION_TIMEOUT_DEPRECATION = <<~'MESSAGE'
43
43
  Deprecated configuration toplevel key `mutation_timeout` found.
44
44
 
45
- This key will be removed in the next mayor version.
45
+ This key will be removed in the next major version.
46
46
  Instead place your mutation timeout configuration under the `mutation` key
47
47
  like this:
48
48
 
@@ -30,8 +30,9 @@ module Mutant
30
30
 
31
31
  # Instance method specific evaluator
32
32
  class Evaluator < Evaluator
33
- SUBJECT_CLASS = Subject::Method::Instance
34
- NAME_INDEX = 0
33
+ MATCH_NODE_TYPE = :def
34
+ NAME_INDEX = 0
35
+ SUBJECT_CLASS = Subject::Method::Instance
35
36
 
36
37
  private
37
38
 
@@ -22,10 +22,11 @@ module Mutant
22
22
  # Metaclass method evaluator
23
23
  class Evaluator < Evaluator
24
24
  # Terminology note: the "receiver" is the `self` in `class << self`
25
- SUBJECT_CLASS = Subject::Method::Metaclass
26
- NAME_INDEX = 0
27
25
  CONST_NAME_INDEX = 1
26
+ MATCH_NODE_TYPE = :def
27
+ NAME_INDEX = 0
28
28
  SCLASS_RECEIVER_INDEX = 0
29
+ SUBJECT_CLASS = Subject::Method::Metaclass
29
30
  RECEIVER_WARNING = 'Can only match :def inside :sclass on ' \
30
31
  ':self or :const, got :sclass on %p ' \
31
32
  'unable to match'
@@ -45,7 +46,7 @@ module Mutant
45
46
  end
46
47
 
47
48
  def metaclass_containing(node)
48
- AST::FindMetaclassContaining.call(ast.node, node)
49
+ AST::FindMetaclassContaining.call(ast, node)
49
50
  end
50
51
 
51
52
  def line?(node)
@@ -18,10 +18,11 @@ module Mutant
18
18
 
19
19
  # Singleton method evaluator
20
20
  class Evaluator < Evaluator
21
- SUBJECT_CLASS = Subject::Method::Singleton
22
- RECEIVER_INDEX = 0
21
+ MATCH_NODE_TYPE = :defs
23
22
  NAME_INDEX = 1
23
+ RECEIVER_INDEX = 0
24
24
  RECEIVER_WARNING = 'Can only match :defs on :self or :const got %p unable to match'
25
+ SUBJECT_CLASS = Subject::Method::Singleton
25
26
 
26
27
  private
27
28
 
@@ -41,23 +41,38 @@ module Mutant
41
41
  #
42
42
  # @return [Enumerable<Subject>]
43
43
  def call
44
- return EMPTY_ARRAY if skip?
44
+ location = source_location
45
+
46
+ if location.nil? || !location.first.end_with?('.rb')
47
+ env.warn(SOURCE_LOCATION_WARNING_FORMAT % target_method)
45
48
 
46
- [subject].compact
49
+ return EMPTY_ARRAY
50
+ end
51
+
52
+ match_view
47
53
  end
48
54
 
49
55
  private
50
56
 
51
- def skip?
52
- location = source_location
53
-
54
- file = location&.first
57
+ def match_view
58
+ return EMPTY_ARRAY if matched_view.nil?
55
59
 
56
- if location.nil? || !file.end_with?('.rb')
57
- env.warn(SOURCE_LOCATION_WARNING_FORMAT % target_method)
58
- elsif matched_node_path.any?(&method(:n_block?))
60
+ if matched_view.path.any?(&:block.public_method(:equal?))
59
61
  env.warn(CLOSURE_WARNING_FORMAT % target_method)
62
+
63
+ return EMPTY_ARRAY
60
64
  end
65
+
66
+ [subject]
67
+ end
68
+
69
+ def subject
70
+ self.class::SUBJECT_CLASS.new(
71
+ config: subject_config(matched_view.node),
72
+ context: context,
73
+ node: matched_view.node,
74
+ visibility: visibility
75
+ )
61
76
  end
62
77
 
63
78
  def method_name
@@ -95,17 +110,6 @@ module Mutant
95
110
  T::Private::Methods.signature_for_method(target_method)
96
111
  end
97
112
 
98
- def subject
99
- node = matched_node_path.last || return
100
-
101
- self.class::SUBJECT_CLASS.new(
102
- config: subject_config(node),
103
- context: context,
104
- node: node,
105
- visibility: visibility
106
- )
107
- end
108
-
109
113
  def subject_config(node)
110
114
  Subject::Config.parse(
111
115
  comments: ast.comment_associations.fetch(node, []),
@@ -113,10 +117,15 @@ module Mutant
113
117
  )
114
118
  end
115
119
 
116
- def matched_node_path
117
- AST.find_last_path(ast.node, &method(:match?))
120
+ def matched_view
121
+ return if source_location.nil?
122
+
123
+ ast
124
+ .on_line(source_line)
125
+ .select { |view| view.node.type.eql?(self.class::MATCH_NODE_TYPE) && match?(view.node) }
126
+ .last
118
127
  end
119
- memoize :matched_node_path
128
+ memoize :matched_view
120
129
 
121
130
  def visibility
122
131
  # This can be cleaned up once we are on >ruby-3.0
@@ -38,9 +38,11 @@ module Mutant
38
38
  end
39
39
 
40
40
  def body_has_control?
41
- AST.find_last_path(body) do |node|
42
- n_break?(node) || n_next?(node)
43
- end.any?
41
+ AST::Structure.for(body.type).each_node(body) do |node|
42
+ return true if n_break?(node) || n_next?(node)
43
+ end
44
+
45
+ false
44
46
  end
45
47
 
46
48
  def mutate_body_receiver
data/lib/mutant/parser.rb CHANGED
@@ -5,13 +5,6 @@ module Mutant
5
5
  class Parser
6
6
  include Adamantium, Equalizer.new
7
7
 
8
- class AST
9
- include Anima.new(
10
- :node,
11
- :comment_associations
12
- )
13
- end
14
-
15
8
  # Initialize object
16
9
  #
17
10
  # @return [undefined]
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.13'
5
+ VERSION = '0.11.14'
6
6
  end # Mutant
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.13
4
+ version: 0.11.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-06 00:00:00.000000000 Z
11
+ date: 2022-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -393,7 +393,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
393
393
  - !ruby/object:Gem::Version
394
394
  version: '0'
395
395
  requirements: []
396
- rubygems_version: 3.3.7
396
+ rubygems_version: 3.1.6
397
397
  signing_key:
398
398
  specification_version: 4
399
399
  summary: ''