mutant 0.11.13 → 0.11.14

Sign up to get free protection for your applications and to get access to all the features.
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: ''