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 +4 -4
- data/lib/rubocop/ast/node/args_node.rb +1 -1
- data/lib/rubocop/ast/node/array_node.rb +4 -4
- data/lib/rubocop/ast/node/for_node.rb +1 -1
- data/lib/rubocop/ast/node/hash_node.rb +1 -1
- data/lib/rubocop/ast/node/if_node.rb +9 -2
- data/lib/rubocop/ast/node/in_pattern_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/descendence.rb +3 -3
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +6 -6
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +7 -2
- data/lib/rubocop/ast/node/str_node.rb +37 -1
- data/lib/rubocop/ast/node/until_node.rb +1 -1
- data/lib/rubocop/ast/node/when_node.rb +1 -1
- data/lib/rubocop/ast/node/while_node.rb +1 -1
- data/lib/rubocop/ast/node.rb +33 -14
- data/lib/rubocop/ast/node_pattern/node.rb +7 -1
- data/lib/rubocop/ast/processed_source.rb +28 -8
- data/lib/rubocop/ast/token.rb +2 -1
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a3205a51f90d1dc493ef4c1ec96a4f40ed796dfc58bfc3661db72e67e134abc
|
4
|
+
data.tar.gz: 6d55fec1f58d712845ecb936db794934ea264e64b0adeb2c097fae63a5e5cb3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9468ab39ad7cd4ca56f0781605f07136dc89dfcbafc51482d5045799b468bf389d3c61671f49c7242f3dfbcc99090f3bd4b0c178d08b6038818b0158e3078658
|
7
|
+
data.tar.gz: a5b2b0604abdd935bfba3213a908678b5697cee7345f5b9941bfdddbfc08ceb8e86cab35895490f2612fd71937baa2ff5b7d75bb2ee4dafb5efd656178dc00c1
|
@@ -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:
|
11
|
-
symbol:
|
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
|
-
|
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
|
53
|
+
loc.begin&.source&.match?(PERCENT_LITERAL_TYPES.fetch(type))
|
54
54
|
else
|
55
55
|
loc.begin&.source&.start_with?('%')
|
56
56
|
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
|
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
|
57
|
+
loc?(:question)
|
51
58
|
end
|
52
59
|
|
53
60
|
# Returns the keyword of the `if` statement as a string. Returns an empty
|
@@ -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? ||
|
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? ||
|
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? ||
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
@@ -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
|
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
|
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
|
-
|
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
|
data/lib/rubocop/ast/node.rb
CHANGED
@@ -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
|
-
|
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 $_ ...) (
|
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
|
-
|
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?, '(
|
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
|
-
(
|
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
|
-
(
|
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
|
-
(
|
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
|
-
(
|
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
|
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
|
-
|
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
|
-
|
292
|
+
require_prism_translation_parser(ruby_version)
|
298
293
|
Prism::Translation::Parser33
|
299
294
|
when 3.4
|
300
|
-
|
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
|
|
data/lib/rubocop/ast/token.rb
CHANGED
@@ -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
|
87
|
+
LEFT_CURLY_TYPES.include?(type)
|
87
88
|
end
|
88
89
|
|
89
90
|
def right_curly_brace?
|
data/lib/rubocop/ast/version.rb
CHANGED
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.
|
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:
|
13
|
+
date: 2025-01-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: parser
|