rubocop-ast 1.36.2 → 1.38.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07c76274a87f19afed0f78fd17a51276f0018b7d1771e762135102b4d52b5a5e
4
- data.tar.gz: b1e0a8669b789f063b3a73cdddc6187ef65fa80e8af376a898d90003af988370
3
+ metadata.gz: 3a3205a51f90d1dc493ef4c1ec96a4f40ed796dfc58bfc3661db72e67e134abc
4
+ data.tar.gz: 6d55fec1f58d712845ecb936db794934ea264e64b0adeb2c097fae63a5e5cb3e
5
5
  SHA512:
6
- metadata.gz: 53acbd7b42693e94af37b5ec5e894c77416edabb7a5ad7cb9a4bc82f605dad8b6f324a41a68fe83cfe8227d4421fff4bba77c1b6c33d1234af7972b74a3e6f2f
7
- data.tar.gz: d5723bec108faa1d19eff03b0fefb2f8eeefe885253f16180bedbde4589cba16db6dfd45d27bb82a0f14538e9c93416dd23756f0f79fa3d68ae67a7b3ff30c64
6
+ metadata.gz: 9468ab39ad7cd4ca56f0781605f07136dc89dfcbafc51482d5045799b468bf389d3c61671f49c7242f3dfbcc99090f3bd4b0c178d08b6038818b0158e3078658
7
+ data.tar.gz: a5b2b0604abdd935bfba3213a908678b5697cee7345f5b9941bfdddbfc08ceb8e86cab35895490f2612fd71937baa2ff5b7d75bb2ee4dafb5efd656178dc00c1
@@ -32,7 +32,7 @@ module RuboCop
32
32
  #
33
33
  # @return [Array<Node>] array of argument nodes.
34
34
  def argument_list
35
- each_descendant(*ARGUMENT_TYPES).to_a.freeze
35
+ each_descendant(:argument).to_a.freeze
36
36
  end
37
37
  end
38
38
  end
@@ -7,8 +7,8 @@ module RuboCop
7
7
  # to all `array` nodes within RuboCop.
8
8
  class ArrayNode < Node
9
9
  PERCENT_LITERAL_TYPES = {
10
- string: /^%[wW]/,
11
- symbol: /^%[iI]/
10
+ string: /\A%[wW]/,
11
+ symbol: /\A%[iI]/
12
12
  }.freeze
13
13
  private_constant :PERCENT_LITERAL_TYPES
14
14
 
@@ -34,7 +34,7 @@ module RuboCop
34
34
  #
35
35
  # @return [Boolean] whether the array is enclosed in square brackets
36
36
  def square_brackets?
37
- loc.begin&.is?('[')
37
+ loc_is?(:begin, '[')
38
38
  end
39
39
 
40
40
  # Checks whether the `array` literal is delimited by percent brackets.
@@ -50,7 +50,7 @@ module RuboCop
50
50
  # @return [Boolean] whether the array is enclosed in percent brackets
51
51
  def percent_literal?(type = nil)
52
52
  if type
53
- loc.begin && loc.begin.source =~ PERCENT_LITERAL_TYPES[type]
53
+ loc.begin&.source&.match?(PERCENT_LITERAL_TYPES.fetch(type))
54
54
  else
55
55
  loc.begin&.source&.start_with?('%')
56
56
  end
@@ -17,7 +17,7 @@ module RuboCop
17
17
  #
18
18
  # @return [Boolean] whether the `for` node has a `do` keyword
19
19
  def do?
20
- loc.begin&.is?('do')
20
+ loc_is?(:begin, 'do')
21
21
  end
22
22
 
23
23
  # Checks whether this node body is a void context.
@@ -115,7 +115,7 @@ module RuboCop
115
115
  #
116
116
  # @return [Boolean] whether the `hash` literal is enclosed in braces
117
117
  def braces?
118
- loc.end&.is?('}')
118
+ loc_is?(:end, '}')
119
119
  end
120
120
  end
121
121
  end
@@ -25,6 +25,13 @@ module RuboCop
25
25
  keyword == 'unless'
26
26
  end
27
27
 
28
+ # Checks whether the `if` node has an `then` clause.
29
+ #
30
+ # @return [Boolean] whether the node has an `then` clause
31
+ def then?
32
+ loc_is?(:begin, 'then')
33
+ end
34
+
28
35
  # Checks whether the `if` is an `elsif`. Parser handles these by nesting
29
36
  # `if` nodes in the `else` branch.
30
37
  #
@@ -40,14 +47,14 @@ module RuboCop
40
47
  #
41
48
  # @return [Boolean] whether the node has an `else` clause
42
49
  def else?
43
- loc.respond_to?(:else) && loc.else
50
+ loc?(:else)
44
51
  end
45
52
 
46
53
  # Checks whether the `if` node is a ternary operator.
47
54
  #
48
55
  # @return [Boolean] whether the `if` node is a ternary operator
49
56
  def ternary?
50
- loc.respond_to?(:question)
57
+ loc?(:question)
51
58
  end
52
59
 
53
60
  # Returns the keyword of the `if` statement as a string. Returns an empty
@@ -24,7 +24,7 @@ module RuboCop
24
24
  #
25
25
  # @return [Boolean] whether the `in` node has a `then` keyword
26
26
  def then?
27
- loc.begin&.is?('then')
27
+ loc_is?(:begin, 'then')
28
28
  end
29
29
 
30
30
  # Returns the body of the `in` node.
@@ -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
@@ -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&.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&.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&.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
@@ -260,7 +260,7 @@ module RuboCop
260
260
  ^{ # or the parent is...
261
261
  sclass class module class_constructor? # a class-like node
262
262
  [ { # or some "wrapper"
263
- kwbegin begin block numblock
263
+ kwbegin begin any_block
264
264
  (if _condition <%0 _>) # note: we're excluding the condition of `if` nodes
265
265
  }
266
266
  #in_macro_scope? # that is itself in a macro scope
@@ -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.
@@ -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
@@ -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&.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
@@ -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
@@ -76,9 +76,6 @@ module RuboCop
76
76
  OPERATOR_KEYWORDS = %i[and or].to_set.freeze
77
77
  # @api private
78
78
  SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].to_set.freeze
79
- # @api private
80
- ARGUMENT_TYPES = %i[arg optarg restarg kwarg kwoptarg kwrestarg
81
- blockarg forward_arg shadowarg].to_set.freeze
82
79
 
83
80
  LITERAL_RECURSIVE_METHODS = (COMPARISON_OPERATORS + %i[* ! <=>]).freeze
84
81
  LITERAL_RECURSIVE_TYPES = (OPERATOR_KEYWORDS + COMPOSITE_LITERALS + %i[begin pair]).freeze
@@ -98,7 +95,7 @@ module RuboCop
98
95
  kwrestarg: :argument,
99
96
  blockarg: :argument,
100
97
  forward_arg: :argument,
101
- shardowarg: :argument,
98
+ shadowarg: :argument,
102
99
 
103
100
  true: :boolean,
104
101
  false: :boolean,
@@ -112,7 +109,10 @@ module RuboCop
112
109
  erange: :range,
113
110
 
114
111
  send: :call,
115
- csend: :call
112
+ csend: :call,
113
+
114
+ block: :any_block,
115
+ numblock: :any_block
116
116
  }.freeze
117
117
  private_constant :GROUP_FOR_TYPE
118
118
 
@@ -343,7 +343,7 @@ module RuboCop
343
343
 
344
344
  # @!method receiver(node = self)
345
345
  def_node_matcher :receiver, <<~PATTERN
346
- {(send $_ ...) ({block numblock} (call $_ ...) ...)}
346
+ {(send $_ ...) (any_block (call $_ ...) ...)}
347
347
  PATTERN
348
348
 
349
349
  # @!method str_content(node = self)
@@ -497,7 +497,7 @@ module RuboCop
497
497
  end
498
498
 
499
499
  def parenthesized_call?
500
- loc.respond_to?(:begin) && loc.begin&.is?('(')
500
+ loc_is?(:begin, '(')
501
501
  end
502
502
 
503
503
  def call_type?
@@ -528,12 +528,32 @@ module RuboCop
528
528
  GROUP_FOR_TYPE[type] == :range
529
529
  end
530
530
 
531
+ def any_block_type?
532
+ GROUP_FOR_TYPE[type] == :any_block
533
+ end
534
+
531
535
  def guard_clause?
532
536
  node = operator_keyword? ? rhs : self
533
537
 
534
538
  node.match_guard_clause?
535
539
  end
536
540
 
541
+ # Shortcut to safely check if a location is present
542
+ # @return [Boolean]
543
+ def loc?(which_loc)
544
+ return false unless loc.respond_to?(which_loc)
545
+
546
+ !loc.public_send(which_loc).nil?
547
+ end
548
+
549
+ # Shortcut to safely test a particular location, even if
550
+ # this location does not exist or is `nil`
551
+ def loc_is?(which_loc, str)
552
+ return false unless loc?(which_loc)
553
+
554
+ loc.public_send(which_loc).is?(str)
555
+ end
556
+
537
557
  # @!method match_guard_clause?(node = self)
538
558
  def_node_matcher :match_guard_clause?, <<~PATTERN
539
559
  [${(send nil? {:raise :fail} ...) return break next} single_line?]
@@ -547,7 +567,7 @@ module RuboCop
547
567
  PATTERN
548
568
 
549
569
  # @!method lambda?(node = self)
550
- def_node_matcher :lambda?, '({block numblock} (send nil? :lambda) ...)'
570
+ def_node_matcher :lambda?, '(any_block (send nil? :lambda) ...)'
551
571
 
552
572
  # @!method lambda_or_proc?(node = self)
553
573
  def_node_matcher :lambda_or_proc?, '{lambda? proc?}'
@@ -560,7 +580,7 @@ module RuboCop
560
580
  {
561
581
  (send #global_const?({:Class :Module :Struct}) :new ...)
562
582
  (send #global_const?(:Data) :define ...)
563
- ({block numblock} {
583
+ (any_block {
564
584
  (send #global_const?({:Class :Module :Struct}) :new ...)
565
585
  (send #global_const?(:Data) :define ...)
566
586
  } ...)
@@ -570,20 +590,20 @@ module RuboCop
570
590
  # @deprecated Use `:class_constructor?`
571
591
  # @!method struct_constructor?(node = self)
572
592
  def_node_matcher :struct_constructor?, <<~PATTERN
573
- ({block numblock} (send #global_const?(:Struct) :new ...) _ $_)
593
+ (any_block (send #global_const?(:Struct) :new ...) _ $_)
574
594
  PATTERN
575
595
 
576
596
  # @!method class_definition?(node = self)
577
597
  def_node_matcher :class_definition?, <<~PATTERN
578
598
  {(class _ _ $_)
579
599
  (sclass _ $_)
580
- ({block numblock} (send #global_const?({:Struct :Class}) :new ...) _ $_)}
600
+ (any_block (send #global_const?({:Struct :Class}) :new ...) _ $_)}
581
601
  PATTERN
582
602
 
583
603
  # @!method module_definition?(node = self)
584
604
  def_node_matcher :module_definition?, <<~PATTERN
585
605
  {(module _ $_)
586
- ({block numblock} (send #global_const?(:Module) :new ...) _ $_)}
606
+ (any_block (send #global_const?(:Module) :new ...) _ $_)}
587
607
  PATTERN
588
608
 
589
609
  # Some expressions are evaluated for their value, some for their side
@@ -646,8 +666,7 @@ module RuboCop
646
666
  last_node = self
647
667
 
648
668
  while (current_node = last_node.parent)
649
- yield current_node if types.empty? ||
650
- types.include?(current_node.type)
669
+ yield current_node if types.empty? || current_node.type?(*types)
651
670
  last_node = current_node
652
671
  end
653
672
  end
@@ -48,7 +48,7 @@ module RuboCop
48
48
  children[0]
49
49
  end
50
50
 
51
- # @return [Integer] nb of captures of that node and its descendants
51
+ # @return [Integer] nb of captures that this node will emit
52
52
  def nb_captures
53
53
  children_nodes.sum(&:nb_captures)
54
54
  end
@@ -243,6 +243,12 @@ module RuboCop
243
243
 
244
244
  [with(children: new_children)]
245
245
  end
246
+
247
+ # Each child in a union must contain the same number
248
+ # of captures. Only one branch ends up capturing.
249
+ def nb_captures
250
+ child.nb_captures
251
+ end
246
252
  end
247
253
 
248
254
  # Registry
@@ -285,19 +285,14 @@ module RuboCop
285
285
  raise ArgumentError, "RuboCop found unknown Ruby version: #{ruby_version.inspect}"
286
286
  end
287
287
  when :parser_prism
288
- begin
289
- require 'prism'
290
- rescue LoadError
291
- warn "Error: Unable to load Prism. Add `gem 'prism'` to your Gemfile."
292
- exit!
293
- end
288
+ require_prism
294
289
 
295
290
  case ruby_version
296
291
  when 3.3
297
- require 'prism/translation/parser33'
292
+ require_prism_translation_parser(ruby_version)
298
293
  Prism::Translation::Parser33
299
294
  when 3.4
300
- require 'prism/translation/parser34'
295
+ require_prism_translation_parser(ruby_version)
301
296
  Prism::Translation::Parser34
302
297
  else
303
298
  raise ArgumentError, 'RuboCop supports target Ruby versions 3.3 and above with Prism. ' \
@@ -306,6 +301,31 @@ module RuboCop
306
301
  end
307
302
  end
308
303
 
304
+ # Prism is a native extension, a `LoadError` will be raised if linked to an incompatible
305
+ # Ruby version. Only raise if it really was caused by Prism not being present.
306
+ def require_prism
307
+ require 'prism'
308
+ rescue LoadError => e
309
+ raise unless e.path == 'prism'
310
+
311
+ warn "Error: Unable to load Prism. Add `gem 'prism'` to your Gemfile."
312
+ exit!
313
+ end
314
+
315
+ # While Prism is not yet a dependency, users may run with outdated versions that
316
+ # don't have all the parsers.
317
+ def require_prism_translation_parser(version)
318
+ require "prism/translation/parser#{version.to_s.delete('.')}"
319
+ rescue LoadError
320
+ warn <<~MESSAGE
321
+ Error: Unable to load Prism parser for Ruby #{version}.
322
+ * If you're using Bundler and don't yet have `gem 'prism'` as a dependency, add it now.
323
+ * If you're using Bundler and already have `gem 'prism'` as a dependency, update it to the most recent version.
324
+ * If you don't use Bundler, run `gem update prism`.
325
+ MESSAGE
326
+ exit!
327
+ end
328
+
309
329
  def create_parser(ruby_version, parser_engine)
310
330
  builder = RuboCop::AST::Builder.new
311
331
 
@@ -5,6 +5,7 @@ module RuboCop
5
5
  # A basic wrapper around Parser's tokens.
6
6
  class Token
7
7
  LEFT_PAREN_TYPES = %i[tLPAREN tLPAREN2].freeze
8
+ LEFT_CURLY_TYPES = %i[tLCURLY tLAMBEG].freeze
8
9
 
9
10
  attr_reader :pos, :type, :text
10
11
 
@@ -83,7 +84,7 @@ module RuboCop
83
84
  end
84
85
 
85
86
  def left_curly_brace?
86
- type == :tLCURLY || type == :tLAMBEG
87
+ LEFT_CURLY_TYPES.include?(type)
87
88
  end
88
89
 
89
90
  def right_curly_brace?
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module AST
5
5
  module Version
6
- STRING = '1.36.2'
6
+ STRING = '1.38.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-ast
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.36.2
4
+ version: 1.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-11-27 00:00:00.000000000 Z
13
+ date: 2025-01-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parser