rubocop-ast 1.36.2 → 1.38.0

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