rubocop-ast 1.29.0 → 1.46.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/rubocop/ast/builder.rb +33 -15
  4. data/lib/rubocop/ast/builder_prism.rb +11 -0
  5. data/lib/rubocop/ast/node/args_node.rb +1 -1
  6. data/lib/rubocop/ast/node/array_node.rb +9 -5
  7. data/lib/rubocop/ast/node/asgn_node.rb +2 -0
  8. data/lib/rubocop/ast/node/block_node.rb +27 -8
  9. data/lib/rubocop/ast/node/casgn_node.rb +4 -12
  10. data/lib/rubocop/ast/node/complex_node.rb +13 -0
  11. data/lib/rubocop/ast/node/const_node.rb +1 -52
  12. data/lib/rubocop/ast/node/def_node.rb +1 -1
  13. data/lib/rubocop/ast/node/ensure_node.rb +36 -0
  14. data/lib/rubocop/ast/node/for_node.rb +1 -1
  15. data/lib/rubocop/ast/node/hash_node.rb +1 -1
  16. data/lib/rubocop/ast/node/if_node.rb +11 -4
  17. data/lib/rubocop/ast/node/in_pattern_node.rb +1 -1
  18. data/lib/rubocop/ast/node/keyword_begin_node.rb +44 -0
  19. data/lib/rubocop/ast/node/masgn_node.rb +63 -0
  20. data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +1 -1
  21. data/lib/rubocop/ast/node/mixin/collection_node.rb +1 -1
  22. data/lib/rubocop/ast/node/mixin/constant_node.rb +62 -0
  23. data/lib/rubocop/ast/node/mixin/descendence.rb +3 -3
  24. data/lib/rubocop/ast/node/mixin/hash_element_node.rb +2 -0
  25. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +12 -13
  26. data/lib/rubocop/ast/node/mixin/numeric_node.rb +2 -2
  27. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +2 -2
  28. data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +7 -2
  29. data/lib/rubocop/ast/node/mlhs_node.rb +29 -0
  30. data/lib/rubocop/ast/node/op_asgn_node.rb +3 -1
  31. data/lib/rubocop/ast/node/rational_node.rb +13 -0
  32. data/lib/rubocop/ast/node/str_node.rb +37 -1
  33. data/lib/rubocop/ast/node/until_node.rb +1 -1
  34. data/lib/rubocop/ast/node/var_node.rb +15 -0
  35. data/lib/rubocop/ast/node/when_node.rb +1 -1
  36. data/lib/rubocop/ast/node/while_node.rb +1 -1
  37. data/lib/rubocop/ast/node.rb +124 -45
  38. data/lib/rubocop/ast/node_pattern/compiler/binding.rb +3 -3
  39. data/lib/rubocop/ast/node_pattern/compiler/debug.rb +3 -8
  40. data/lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb +3 -4
  41. data/lib/rubocop/ast/node_pattern/compiler.rb +1 -1
  42. data/lib/rubocop/ast/node_pattern/lexer.rex.rb +1 -2
  43. data/lib/rubocop/ast/node_pattern/node.rb +11 -6
  44. data/lib/rubocop/ast/node_pattern/parser.racc.rb +4 -2
  45. data/lib/rubocop/ast/node_pattern/parser.rb +1 -1
  46. data/lib/rubocop/ast/node_pattern.rb +1 -1
  47. data/lib/rubocop/ast/processed_source.rb +158 -60
  48. data/lib/rubocop/ast/token.rb +2 -1
  49. data/lib/rubocop/ast/traversal.rb +35 -25
  50. data/lib/rubocop/ast/utilities/simple_forwardable.rb +27 -0
  51. data/lib/rubocop/ast/version.rb +1 -1
  52. data/lib/rubocop/ast.rb +10 -1
  53. metadata +29 -7
  54. data/lib/rubocop/ast/ext/range_min_max.rb +0 -18
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # Common functionality for nodes that deal with constants:
6
+ # `const`, `casgn`.
7
+ module ConstantNode
8
+ # @return [Node, nil] the node associated with the scope (e.g. cbase, const, ...)
9
+ def namespace
10
+ children[0]
11
+ end
12
+
13
+ # @return [Symbol] the demodulized name of the constant: "::Foo::Bar" => :Bar
14
+ def short_name
15
+ children[1]
16
+ end
17
+
18
+ # @return [Boolean] if the constant is a Module / Class, according to the standard convention.
19
+ # Note: some classes might have uppercase in which case this method
20
+ # returns false
21
+ def module_name?
22
+ short_name.match?(/[[:lower:]]/)
23
+ end
24
+ alias class_name? module_name?
25
+
26
+ # @return [Boolean] if the constant starts with `::` (aka s(:cbase))
27
+ def absolute?
28
+ return false unless namespace
29
+
30
+ each_path.first.cbase_type?
31
+ end
32
+
33
+ # @return [Boolean] if the constant does not start with `::` (aka s(:cbase))
34
+ def relative?
35
+ !absolute?
36
+ end
37
+
38
+ # Yield nodes for the namespace
39
+ #
40
+ # For `::Foo::Bar::BAZ` => yields:
41
+ # s(:cbase), then
42
+ # s(:const, :Foo), then
43
+ # s(:const, s(:const, :Foo), :Bar)
44
+ def each_path(&block)
45
+ return to_enum(__method__) unless block
46
+
47
+ descendants = []
48
+ last = self
49
+ loop do
50
+ last = last.children.first
51
+ break if last.nil?
52
+
53
+ descendants << last
54
+ break unless last.const_type?
55
+ end
56
+ descendants.reverse_each(&block)
57
+
58
+ self
59
+ end
60
+ end
61
+ end
62
+ end
@@ -25,7 +25,7 @@ module RuboCop
25
25
  children.each do |child|
26
26
  next unless child.is_a?(::AST::Node)
27
27
 
28
- yield child if types.empty? || types.include?(child.type)
28
+ yield child if types.empty? || child.type?(*types)
29
29
  end
30
30
 
31
31
  self
@@ -95,7 +95,7 @@ module RuboCop
95
95
  def each_node(*types, &block)
96
96
  return to_enum(__method__, *types) unless block
97
97
 
98
- yield self if types.empty? || types.include?(type)
98
+ yield self if types.empty? || type?(*types)
99
99
 
100
100
  visit_descendants(types, &block)
101
101
 
@@ -108,7 +108,7 @@ module RuboCop
108
108
  children.each do |child|
109
109
  next unless child.is_a?(::AST::Node)
110
110
 
111
- yield child if types.empty? || types.include?(child.type)
111
+ yield child if types.empty? || child.type?(*types)
112
112
  child.visit_descendants(types, &block)
113
113
  end
114
114
  end
@@ -99,7 +99,9 @@ module RuboCop
99
99
 
100
100
  def valid_argument_types?
101
101
  [first, second].all? do |argument|
102
+ # rubocop:disable InternalAffairs/NodeTypeMultiplePredicates
102
103
  argument.pair_type? || argument.kwsplat_type?
104
+ # rubocop:enable InternalAffairs/NodeTypeMultiplePredicates
103
105
  end
104
106
  end
105
107
 
@@ -39,10 +39,10 @@ module RuboCop
39
39
  end
40
40
  end
41
41
 
42
- # The `block` or `numblock` node associated with this method dispatch, if any.
42
+ # The `block`, `numblock`, or `itblock` node associated with this method dispatch, if any.
43
43
  #
44
- # @return [BlockNode, nil] the `block` or `numblock` node associated with this method
45
- # call or `nil`
44
+ # @return [BlockNode, nil] the `block`, `numblock`, or `itblock` node associated with this
45
+ # method call or `nil`
46
46
  def block_node
47
47
  parent if block_literal?
48
48
  end
@@ -105,7 +105,7 @@ module RuboCop
105
105
  #
106
106
  # @return [Boolean] whether the dispatched method is a setter
107
107
  def setter_method?
108
- loc.respond_to?(:operator) && loc.operator
108
+ loc?(:operator)
109
109
  end
110
110
  alias assignment? setter_method?
111
111
 
@@ -117,7 +117,7 @@ module RuboCop
117
117
  #
118
118
  # @return [Boolean] whether the method was called with a connecting dot
119
119
  def dot?
120
- loc.respond_to?(:dot) && loc.dot && loc.dot.is?('.')
120
+ loc_is?(:dot, '.')
121
121
  end
122
122
 
123
123
  # Checks whether the dispatched method uses a double colon to connect the
@@ -125,7 +125,7 @@ module RuboCop
125
125
  #
126
126
  # @return [Boolean] whether the method was called with a connecting dot
127
127
  def double_colon?
128
- loc.respond_to?(:dot) && loc.dot && loc.dot.is?('::')
128
+ loc_is?(:dot, '::')
129
129
  end
130
130
 
131
131
  # Checks whether the dispatched method uses a safe navigation operator to
@@ -133,7 +133,7 @@ module RuboCop
133
133
  #
134
134
  # @return [Boolean] whether the method was called with a connecting dot
135
135
  def safe_navigation?
136
- loc.respond_to?(:dot) && loc.dot && loc.dot.is?('&.')
136
+ loc_is?(:dot, '&.')
137
137
  end
138
138
 
139
139
  # Checks whether the *explicit* receiver of this method dispatch is
@@ -165,7 +165,7 @@ module RuboCop
165
165
  #
166
166
  # @return [Boolean] whether the dispatched method has a block
167
167
  def block_literal?
168
- (parent&.block_type? || parent&.numblock_type?) && eql?(parent.send_node)
168
+ parent&.any_block_type? && eql?(parent.send_node)
169
169
  end
170
170
 
171
171
  # Checks whether this node is an arithmetic operation
@@ -200,8 +200,7 @@ module RuboCop
200
200
  arg = node.children[2]
201
201
 
202
202
  return unless node.send_type? && node.receiver.nil? && arg.is_a?(::AST::Node)
203
-
204
- return arg if arg.def_type? || arg.defs_type?
203
+ return arg if arg.any_def_type?
205
204
 
206
205
  def_modifier(arg)
207
206
  end
@@ -260,7 +259,7 @@ module RuboCop
260
259
  ^{ # or the parent is...
261
260
  sclass class module class_constructor? # a class-like node
262
261
  [ { # or some "wrapper"
263
- kwbegin begin block numblock
262
+ kwbegin begin any_block
264
263
  (if _condition <%0 _>) # note: we're excluding the condition of `if` nodes
265
264
  }
266
265
  #in_macro_scope? # that is itself in a macro scope
@@ -271,7 +270,7 @@ module RuboCop
271
270
 
272
271
  # @!method adjacent_def_modifier?(node = self)
273
272
  def_node_matcher :adjacent_def_modifier?, <<~PATTERN
274
- (send nil? _ ({def defs} ...))
273
+ (send nil? _ (any_def ...))
275
274
  PATTERN
276
275
 
277
276
  # @!method bare_access_modifier_declaration?(node = self)
@@ -281,7 +280,7 @@ module RuboCop
281
280
 
282
281
  # @!method non_bare_access_modifier_declaration?(node = self)
283
282
  def_node_matcher :non_bare_access_modifier_declaration?, <<~PATTERN
284
- (send nil? {:public :protected :private :module_function} _)
283
+ (send nil? {:public :protected :private :module_function} _+)
285
284
  PATTERN
286
285
  end
287
286
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RuboCop
4
4
  module AST
5
- # Common functionality for primitive numeric nodes: `int`, `float`, ...
5
+ # Common functionality for primitive numeric nodes: `int`, `float`, `rational`, `complex`...
6
6
  module NumericNode
7
7
  SIGN_REGEX = /\A[+-]/.freeze
8
8
  private_constant :SIGN_REGEX
@@ -15,7 +15,7 @@ module RuboCop
15
15
  #
16
16
  # @return [Boolean] whether this literal has a sign.
17
17
  def sign?
18
- source.match(SIGN_REGEX)
18
+ source.match?(SIGN_REGEX)
19
19
  end
20
20
  end
21
21
  end
@@ -13,7 +13,7 @@ module RuboCop
13
13
  # @return [Boolean] whether this node's arguments are
14
14
  # wrapped in parentheses
15
15
  def parenthesized?
16
- loc.end&.is?(')')
16
+ loc_is?(:end, ')')
17
17
  end
18
18
 
19
19
  # A shorthand for getting the first argument of the node.
@@ -57,7 +57,7 @@ module RuboCop
57
57
  # @return [Boolean] whether the last argument of the node is a block pass
58
58
  def block_argument?
59
59
  arguments? &&
60
- (last_argument.block_pass_type? || last_argument.blockarg_type?)
60
+ last_argument.type?(:block_pass, :blockarg)
61
61
  end
62
62
 
63
63
  # A specialized `ParameterizedNode` for node that have a single child
@@ -14,6 +14,11 @@ module RuboCop
14
14
  SEMANTIC_OR = 'or'
15
15
  private_constant :SEMANTIC_OR
16
16
 
17
+ LOGICAL_OPERATORS = [LOGICAL_AND, LOGICAL_OR].freeze
18
+ private_constant :LOGICAL_OPERATORS
19
+ SEMANTIC_OPERATORS = [SEMANTIC_AND, SEMANTIC_OR].freeze
20
+ private_constant :SEMANTIC_OPERATORS
21
+
17
22
  # Returns the operator as a string.
18
23
  #
19
24
  # @return [String] the operator
@@ -25,14 +30,14 @@ module RuboCop
25
30
  #
26
31
  # @return [Boolean] whether this is a logical operator
27
32
  def logical_operator?
28
- operator == LOGICAL_AND || operator == LOGICAL_OR
33
+ LOGICAL_OPERATORS.include?(operator)
29
34
  end
30
35
 
31
36
  # Checks whether this is a semantic operator.
32
37
  #
33
38
  # @return [Boolean] whether this is a semantic operator
34
39
  def semantic_operator?
35
- operator == SEMANTIC_AND || operator == SEMANTIC_OR
40
+ SEMANTIC_OPERATORS.include?(operator)
36
41
  end
37
42
  end
38
43
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `mlhs` nodes.
6
+ # This will be used in place of a plain node when the builder constructs
7
+ # the AST, making its methods available to all assignment nodes within RuboCop.
8
+ class MlhsNode < Node
9
+ # Returns all the assignment nodes on the left hand side (LHS) of a multiple assignment.
10
+ # These are generally assignment nodes (`lvasgn`, `ivasgn`, `cvasgn`, `gvasgn`, `casgn`)
11
+ # but can also be `send` nodes in case of `foo.bar, ... =` or `foo[:bar], ... =`,
12
+ # or a `splat` node for `*, ... =`.
13
+ #
14
+ # @return [Array<Node>] the assignment nodes of the multiple assignment LHS
15
+ def assignments
16
+ child_nodes.flat_map do |node|
17
+ if node.splat_type?
18
+ # Anonymous splats have no children
19
+ node.child_nodes.first || node
20
+ elsif node.mlhs_type?
21
+ node.assignments
22
+ else
23
+ node
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -10,12 +10,13 @@ module RuboCop
10
10
  def assignment_node
11
11
  node_parts[0]
12
12
  end
13
+ alias lhs assignment_node
13
14
 
14
15
  # The name of the variable being assigned as a symbol.
15
16
  #
16
17
  # @return [Symbol] the name of the variable being assigned
17
18
  def name
18
- assignment_node.name
19
+ assignment_node.call_type? ? assignment_node.method_name : assignment_node.name
19
20
  end
20
21
 
21
22
  # The operator being used for assignment as a symbol.
@@ -31,6 +32,7 @@ module RuboCop
31
32
  def expression
32
33
  node_parts.last
33
34
  end
35
+ alias rhs expression
34
36
  end
35
37
  end
36
38
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `rational` nodes. This will be used in place of a plain
6
+ # node when the builder constructs the AST, making its methods available to
7
+ # all `rational` nodes within RuboCop.
8
+ class RationalNode < Node
9
+ include BasicLiteralNode
10
+ include NumericNode
11
+ end
12
+ end
13
+ end
@@ -8,13 +8,49 @@ module RuboCop
8
8
  class StrNode < Node
9
9
  include BasicLiteralNode
10
10
 
11
+ PERCENT_LITERAL_TYPES = {
12
+ :% => /\A%(?=[^a-zA-Z])/,
13
+ :q => /\A%q/,
14
+ :Q => /\A%Q/
15
+ }.freeze
16
+ private_constant :PERCENT_LITERAL_TYPES
17
+
18
+ def single_quoted?
19
+ loc_is?(:begin, "'")
20
+ end
21
+
22
+ def double_quoted?
23
+ loc_is?(:begin, '"')
24
+ end
25
+
11
26
  def character_literal?
12
- loc.respond_to?(:begin) && loc.begin && loc.begin.is?('?')
27
+ loc_is?(:begin, '?')
13
28
  end
14
29
 
15
30
  def heredoc?
16
31
  loc.is_a?(Parser::Source::Map::Heredoc)
17
32
  end
33
+
34
+ # Checks whether the string literal is delimited by percent brackets.
35
+ #
36
+ # @overload percent_literal?
37
+ # Check for any string percent literal.
38
+ #
39
+ # @overload percent_literal?(type)
40
+ # Check for a string percent literal of type `type`.
41
+ #
42
+ # @param type [Symbol] an optional percent literal type
43
+ #
44
+ # @return [Boolean] whether the string is enclosed in percent brackets
45
+ def percent_literal?(type = nil)
46
+ return false unless loc?(:begin)
47
+
48
+ if type
49
+ loc.begin.source.match?(PERCENT_LITERAL_TYPES.fetch(type))
50
+ else
51
+ loc.begin.source.start_with?('%')
52
+ end
53
+ end
18
54
  end
19
55
  end
20
56
  end
@@ -28,7 +28,7 @@ module RuboCop
28
28
  #
29
29
  # @return [Boolean] whether the `until` node has a `do` keyword
30
30
  def do?
31
- loc.begin&.is?('do')
31
+ loc_is?(:begin, 'do')
32
32
  end
33
33
  end
34
34
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `lvar`, `ivar`, `cvar` and `gvar` nodes.
6
+ # This will be used in place of a plain node when the builder constructs
7
+ # the AST, making its methods available to all assignment nodes within RuboCop.
8
+ class VarNode < Node
9
+ # @return [Symbol] The name of the variable.
10
+ def name
11
+ node_parts[0]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  #
34
34
  # @return [Boolean] whether the `when` node has a `then` keyword
35
35
  def then?
36
- loc.begin&.is?('then')
36
+ loc_is?(:begin, 'then')
37
37
  end
38
38
 
39
39
  # Returns the body of the `when` node.
@@ -28,7 +28,7 @@ module RuboCop
28
28
  #
29
29
  # @return [Boolean] whether the `until` node has a `do` keyword
30
30
  def do?
31
- loc.begin&.is?('do')
31
+ loc_is?(:begin, 'do')
32
32
  end
33
33
  end
34
34
  end