rubocop-ast 1.45.1 → 1.50.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/README.md +0 -2
- data/lib/rubocop/ast/builder.rb +1 -0
- data/lib/rubocop/ast/node/and_node.rb +2 -2
- data/lib/rubocop/ast/node/case_match_node.rb +1 -1
- data/lib/rubocop/ast/node/case_node.rb +1 -1
- data/lib/rubocop/ast/node/complex_node.rb +13 -0
- data/lib/rubocop/ast/node/for_node.rb +1 -1
- data/lib/rubocop/ast/node/hash_node.rb +6 -6
- data/lib/rubocop/ast/node/if_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/descendence.rb +21 -4
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +2 -2
- data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +5 -5
- data/lib/rubocop/ast/node/mixin/numeric_node.rb +3 -3
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +1 -0
- data/lib/rubocop/ast/node/pair_node.rb +1 -1
- data/lib/rubocop/ast/node/symbol_node.rb +1 -1
- data/lib/rubocop/ast/node/when_node.rb +1 -1
- data/lib/rubocop/ast/node/while_node.rb +2 -2
- data/lib/rubocop/ast/node.rb +46 -8
- data/lib/rubocop/ast/node_pattern/compiler/binding.rb +6 -0
- data/lib/rubocop/ast/node_pattern/compiler/node_pattern_subcompiler.rb +1 -1
- data/lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb +15 -3
- data/lib/rubocop/ast/node_pattern/compiler.rb +1 -0
- data/lib/rubocop/ast/node_pattern/lexer.rex +1 -1
- data/lib/rubocop/ast/node_pattern/lexer.rex.rb +2 -2
- data/lib/rubocop/ast/node_pattern/node.rb +1 -1
- data/lib/rubocop/ast/node_pattern.rb +2 -1
- data/lib/rubocop/ast/processed_source.rb +137 -26
- data/lib/rubocop/ast/traversal.rb +2 -1
- data/lib/rubocop/ast/version.rb +1 -1
- data/lib/rubocop/ast.rb +1 -0
- metadata +6 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 21fa08d16f9a915d62568fbf85b25efeefbf23fba1bf710b772130bcdcced47d
|
|
4
|
+
data.tar.gz: 2789ea768313b62f16dc6a6f77e3f4b02e5d1af01a7d765483284fb3cd65c44c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 53cd0e762e23e4394cbd01ed3d2ae6a86983e22f0a18d7782207874d691140a6eca839e67f2ee746ffb942863c65c3278cde553b408cf8c1fdfb0da736e393e4
|
|
7
|
+
data.tar.gz: d8657ab6d0d89f0d9d963e13379283c7aba9245fb9fa3227316f4b7955d6faab37a2da0539814461c5b39e5d8e5c7c12d715c8ebcdd2406e606e7e6f350e0160
|
data/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/rubocop-ast)
|
|
4
4
|
[](https://github.com/rubocop/rubocop-ast/actions/workflows/rubocop.yml)
|
|
5
|
-
[](https://codeclimate.com/github/rubocop/rubocop-ast/test_coverage)
|
|
6
|
-
[](https://codeclimate.com/github/rubocop/rubocop-ast/maintainability)
|
|
7
5
|
|
|
8
6
|
Contains the classes needed by [RuboCop](https://github.com/rubocop/rubocop) to deal with Ruby's AST, in particular:
|
|
9
7
|
|
data/lib/rubocop/ast/builder.rb
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module AST
|
|
5
|
-
# A node extension for `
|
|
5
|
+
# A node extension for `and` nodes. This will be used in place of a plain
|
|
6
6
|
# node when the builder constructs the AST, making its methods available
|
|
7
|
-
# to all `
|
|
7
|
+
# to all `and` nodes within RuboCop.
|
|
8
8
|
class AndNode < Node
|
|
9
9
|
include BinaryOperatorNode
|
|
10
10
|
include PredicateOperatorNode
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module AST
|
|
5
|
+
# A node extension for `complex` 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 `complex` nodes within RuboCop.
|
|
8
|
+
class ComplexNode < Node
|
|
9
|
+
include BasicLiteralNode
|
|
10
|
+
include NumericNode
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -56,10 +56,10 @@ module RuboCop
|
|
|
56
56
|
#
|
|
57
57
|
# @return [self] if a block is given
|
|
58
58
|
# @return [Enumerator] if no block is given
|
|
59
|
-
def each_key
|
|
60
|
-
return
|
|
59
|
+
def each_key
|
|
60
|
+
return to_enum(__method__) unless block_given?
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
each_child_node(:pair) { |pair| yield pair.key }
|
|
63
63
|
|
|
64
64
|
self
|
|
65
65
|
end
|
|
@@ -80,10 +80,10 @@ module RuboCop
|
|
|
80
80
|
#
|
|
81
81
|
# @return [self] if a block is given
|
|
82
82
|
# @return [Enumerator] if no block is given
|
|
83
|
-
def each_value
|
|
84
|
-
return
|
|
83
|
+
def each_value
|
|
84
|
+
return to_enum(__method__) unless block_given?
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
each_child_node(:pair) { |pair| yield pair.value }
|
|
87
87
|
|
|
88
88
|
self
|
|
89
89
|
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? || child.
|
|
28
|
+
yield child if types.empty? || child.type_in?(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_in?(types)
|
|
99
99
|
|
|
100
100
|
visit_descendants(types, &block)
|
|
101
101
|
|
|
@@ -105,11 +105,28 @@ module RuboCop
|
|
|
105
105
|
protected
|
|
106
106
|
|
|
107
107
|
def visit_descendants(types, &block)
|
|
108
|
+
if types.empty?
|
|
109
|
+
visit_all_descendants(&block)
|
|
110
|
+
else
|
|
111
|
+
visit_descendants_of_types(types, &block)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def visit_all_descendants(&block)
|
|
116
|
+
children.each do |child|
|
|
117
|
+
next unless child.is_a?(::AST::Node)
|
|
118
|
+
|
|
119
|
+
yield child
|
|
120
|
+
child.visit_all_descendants(&block)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def visit_descendants_of_types(types, &block)
|
|
108
125
|
children.each do |child|
|
|
109
126
|
next unless child.is_a?(::AST::Node)
|
|
110
127
|
|
|
111
|
-
yield child if
|
|
112
|
-
child.
|
|
128
|
+
yield child if child.type_in?(types)
|
|
129
|
+
child.visit_descendants_of_types(types, &block)
|
|
113
130
|
end
|
|
114
131
|
end
|
|
115
132
|
end
|
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
|
32
32
|
#
|
|
33
33
|
# @return [Parser::Source::Range] the source range for the method name or keyword
|
|
34
34
|
def selector
|
|
35
|
-
if loc
|
|
35
|
+
if loc?(:keyword)
|
|
36
36
|
loc.keyword
|
|
37
37
|
else
|
|
38
38
|
loc.selector
|
|
@@ -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&.any_block_type? &&
|
|
168
|
+
parent&.any_block_type? && equal?(parent.send_node)
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
# Checks whether this node is an arithmetic operation
|
|
@@ -140,7 +140,7 @@ module RuboCop
|
|
|
140
140
|
#
|
|
141
141
|
# @return [Boolean] whether the method is an assignment
|
|
142
142
|
def assignment_method?
|
|
143
|
-
!comparison_method? && method_name.
|
|
143
|
+
!comparison_method? && method_name.end_with?('=')
|
|
144
144
|
end
|
|
145
145
|
|
|
146
146
|
# Checks whether the method is an enumerator method.
|
|
@@ -148,7 +148,7 @@ module RuboCop
|
|
|
148
148
|
# @return [Boolean] whether the method is an enumerator
|
|
149
149
|
def enumerator_method?
|
|
150
150
|
ENUMERATOR_METHODS.include?(method_name) ||
|
|
151
|
-
method_name.
|
|
151
|
+
method_name.start_with?('each_')
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
# Checks whether the method is an Enumerable method.
|
|
@@ -162,14 +162,14 @@ module RuboCop
|
|
|
162
162
|
#
|
|
163
163
|
# @return [Boolean] whether the method is a predicate method
|
|
164
164
|
def predicate_method?
|
|
165
|
-
method_name.
|
|
165
|
+
method_name.end_with?('?')
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
# Checks whether the method is a bang method.
|
|
169
169
|
#
|
|
170
170
|
# @return [Boolean] whether the method is a bang method
|
|
171
171
|
def bang_method?
|
|
172
|
-
method_name.
|
|
172
|
+
method_name.end_with?('!')
|
|
173
173
|
end
|
|
174
174
|
|
|
175
175
|
# Checks whether the method is a camel case method,
|
|
@@ -177,7 +177,7 @@ module RuboCop
|
|
|
177
177
|
#
|
|
178
178
|
# @return [Boolean] whether the method is a camel case method
|
|
179
179
|
def camel_case_method?
|
|
180
|
-
method_name.
|
|
180
|
+
method_name.match?(/\A[A-Z]/)
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
# Checks whether the *explicit* receiver of this node is `self`.
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module AST
|
|
5
|
-
# Common functionality for primitive numeric nodes: `int`, `float`, `rational`...
|
|
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
|
|
9
9
|
|
|
10
|
-
# Checks whether this
|
|
10
|
+
# Checks whether this literal has a sign.
|
|
11
11
|
#
|
|
12
12
|
# @example
|
|
13
13
|
#
|
|
@@ -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
|
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Returns the delimiter of the `pair` as a string. Returns `=>` for a
|
|
35
|
-
#
|
|
35
|
+
# hash rocket delimited `pair` and `:` for a colon delimited `pair`.
|
|
36
36
|
#
|
|
37
37
|
# @param [Boolean] with_spacing whether to include spacing
|
|
38
38
|
# @return [String] the delimiter of the `pair`
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module AST
|
|
5
|
-
# A node extension for `sym` nodes. This will be used in
|
|
5
|
+
# A node extension for `sym` nodes. This will be used in place of a
|
|
6
6
|
# plain node when the builder constructs the AST, making its methods
|
|
7
7
|
# available to all `sym` nodes within RuboCop.
|
|
8
8
|
class SymbolNode < Node
|
|
@@ -24,9 +24,9 @@ module RuboCop
|
|
|
24
24
|
'until'
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
# Checks whether the `
|
|
27
|
+
# Checks whether the `while` node has a `do` keyword.
|
|
28
28
|
#
|
|
29
|
-
# @return [Boolean] whether the `
|
|
29
|
+
# @return [Boolean] whether the `while` node has a `do` keyword
|
|
30
30
|
def do?
|
|
31
31
|
loc_is?(:begin, 'do')
|
|
32
32
|
end
|
data/lib/rubocop/ast/node.rb
CHANGED
|
@@ -76,6 +76,13 @@ 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
|
+
# The node types which could have a source matching `SPECIAL_KEYWORDS`:
|
|
80
|
+
# `__FILE__` parses as `str`, `__LINE__` as `int` and `__ENCODING__` as
|
|
81
|
+
# `const` (or as their own node types when the builder emits them);
|
|
82
|
+
# `str` and `sym` also cover word/symbol array elements, string parts
|
|
83
|
+
# and hash labels spelling out one of these keywords.
|
|
84
|
+
SPECIAL_KEYWORD_TYPES = %i[str sym int const __FILE__ __LINE__ __ENCODING__].to_set.freeze
|
|
85
|
+
private_constant :SPECIAL_KEYWORD_TYPES
|
|
79
86
|
|
|
80
87
|
LITERAL_RECURSIVE_METHODS = (COMPARISON_OPERATORS + %i[* ! <=>]).freeze
|
|
81
88
|
LITERAL_RECURSIVE_TYPES = (OPERATOR_KEYWORDS + COMPOSITE_LITERALS + %i[begin pair]).freeze
|
|
@@ -108,6 +115,13 @@ module RuboCop
|
|
|
108
115
|
rational: :numeric,
|
|
109
116
|
complex: :numeric,
|
|
110
117
|
|
|
118
|
+
str: :any_str,
|
|
119
|
+
dstr: :any_str,
|
|
120
|
+
xstr: :any_str,
|
|
121
|
+
|
|
122
|
+
sym: :any_sym,
|
|
123
|
+
dsym: :any_sym,
|
|
124
|
+
|
|
111
125
|
irange: :range,
|
|
112
126
|
erange: :range,
|
|
113
127
|
|
|
@@ -165,6 +179,13 @@ module RuboCop
|
|
|
165
179
|
# Allows specific single node types, as well as "grouped" types
|
|
166
180
|
# (e.g. `:boolean` for `:true` or `:false`)
|
|
167
181
|
def type?(*types)
|
|
182
|
+
type_in?(types)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Non-splatting variant of `type?`, used by the traversal hot paths to
|
|
186
|
+
# avoid allocating an array per visited node.
|
|
187
|
+
# @api private
|
|
188
|
+
def type_in?(types)
|
|
168
189
|
return true if types.include?(type)
|
|
169
190
|
|
|
170
191
|
group_type = GROUP_FOR_TYPE[type]
|
|
@@ -272,7 +293,7 @@ module RuboCop
|
|
|
272
293
|
def right_siblings
|
|
273
294
|
return [].freeze unless parent
|
|
274
295
|
|
|
275
|
-
parent.children[sibling_index + 1..].freeze
|
|
296
|
+
parent.children[(sibling_index + 1)..].freeze
|
|
276
297
|
end
|
|
277
298
|
|
|
278
299
|
# Common destructuring method. This can be used to normalize
|
|
@@ -280,7 +301,7 @@ module RuboCop
|
|
|
280
301
|
# Some node types override this with their own custom
|
|
281
302
|
# destructuring method.
|
|
282
303
|
#
|
|
283
|
-
# @return [Array<Node>] the different parts of the
|
|
304
|
+
# @return [Array<Node>] the different parts of the node
|
|
284
305
|
alias node_parts to_a
|
|
285
306
|
|
|
286
307
|
# Calls the given block for each ancestor node from parent to root.
|
|
@@ -496,7 +517,7 @@ module RuboCop
|
|
|
496
517
|
end
|
|
497
518
|
|
|
498
519
|
def special_keyword?
|
|
499
|
-
SPECIAL_KEYWORDS.include?(source)
|
|
520
|
+
SPECIAL_KEYWORD_TYPES.include?(type) && SPECIAL_KEYWORDS.include?(source)
|
|
500
521
|
end
|
|
501
522
|
|
|
502
523
|
def operator_keyword?
|
|
@@ -512,11 +533,13 @@ module RuboCop
|
|
|
512
533
|
end
|
|
513
534
|
|
|
514
535
|
def chained?
|
|
515
|
-
parent&.call_type? &&
|
|
536
|
+
parent&.call_type? && equal?(parent.receiver)
|
|
516
537
|
end
|
|
517
538
|
|
|
518
539
|
def argument?
|
|
519
|
-
parent&.send_type?
|
|
540
|
+
return false unless parent&.send_type?
|
|
541
|
+
|
|
542
|
+
parent.arguments.any? { |argument| argument.equal?(self) }
|
|
520
543
|
end
|
|
521
544
|
|
|
522
545
|
def any_def_type?
|
|
@@ -547,6 +570,14 @@ module RuboCop
|
|
|
547
570
|
GROUP_FOR_TYPE[type] == :any_match_pattern
|
|
548
571
|
end
|
|
549
572
|
|
|
573
|
+
def any_str_type?
|
|
574
|
+
GROUP_FOR_TYPE[type] == :any_str
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def any_sym_type?
|
|
578
|
+
GROUP_FOR_TYPE[type] == :any_sym
|
|
579
|
+
end
|
|
580
|
+
|
|
550
581
|
def guard_clause?
|
|
551
582
|
node = operator_keyword? ? rhs : self
|
|
552
583
|
|
|
@@ -680,9 +711,16 @@ module RuboCop
|
|
|
680
711
|
def visit_ancestors(types)
|
|
681
712
|
last_node = self
|
|
682
713
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
714
|
+
if types.empty?
|
|
715
|
+
while (current_node = last_node.parent)
|
|
716
|
+
yield current_node
|
|
717
|
+
last_node = current_node
|
|
718
|
+
end
|
|
719
|
+
else
|
|
720
|
+
while (current_node = last_node.parent)
|
|
721
|
+
yield current_node if current_node.type_in?(types)
|
|
722
|
+
last_node = current_node
|
|
723
|
+
end
|
|
686
724
|
end
|
|
687
725
|
end
|
|
688
726
|
|
|
@@ -26,6 +26,12 @@ module RuboCop
|
|
|
26
26
|
var
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
# Returns currently bound variable names
|
|
30
|
+
# @return [Array<String>] variable names that are currently bound
|
|
31
|
+
def bound_variables
|
|
32
|
+
@bound.values
|
|
33
|
+
end
|
|
34
|
+
|
|
29
35
|
# Yields for each branch of the given union, forbidding unification of
|
|
30
36
|
# bindings which only appear in a subset of the union.
|
|
31
37
|
def union_bind(enum) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
@@ -85,16 +85,21 @@ module RuboCop
|
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
def visit_any_order
|
|
88
|
+
def visit_any_order # rubocop:disable Metrics/AbcSize
|
|
89
89
|
within_loop do
|
|
90
90
|
compiler.with_temp_variables do |matched|
|
|
91
|
+
bound_before = compiler.binding.bound_variables
|
|
91
92
|
case_terms = compile_any_order_branches(matched)
|
|
92
93
|
else_code, init = compile_any_order_else
|
|
93
94
|
term = "#{compile_case(case_terms, else_code)} && #{compile_loop_advance}"
|
|
94
95
|
|
|
96
|
+
# Initialize unification variables before the loop to persist across iterations
|
|
97
|
+
newly_bound = compiler.binding.bound_variables - bound_before
|
|
98
|
+
unify_init = compile_unify_init(newly_bound)
|
|
99
|
+
|
|
95
100
|
all_matched_check = "&&\n#{matched}.size == #{node.term_nodes.size}" if node.rest_node
|
|
96
101
|
<<~RUBY
|
|
97
|
-
(#{init}#{matched} = {}; true) &&
|
|
102
|
+
(#{init}#{unify_init}#{matched} = {}; true) &&
|
|
98
103
|
#{compile_loop(term)} #{all_matched_check} \\
|
|
99
104
|
RUBY
|
|
100
105
|
end
|
|
@@ -261,7 +266,7 @@ module RuboCop
|
|
|
261
266
|
arities = children
|
|
262
267
|
.reverse
|
|
263
268
|
.map(&:arity_range)
|
|
264
|
-
.map { |r| last = last.begin + r.begin..last.max + r.max }
|
|
269
|
+
.map { |r| last = (last.begin + r.begin)..(last.max + r.max) }
|
|
265
270
|
.reverse!
|
|
266
271
|
arities.push last_arity
|
|
267
272
|
end
|
|
@@ -412,6 +417,13 @@ module RuboCop
|
|
|
412
417
|
end
|
|
413
418
|
@in_sync = sub_compilers.all?(&:in_sync)
|
|
414
419
|
end
|
|
420
|
+
|
|
421
|
+
# Generate initialization code for unification variables
|
|
422
|
+
# @param newly_bound [Array<String>] variable names that were newly bound
|
|
423
|
+
# @return [String] initialization code
|
|
424
|
+
def compile_unify_init(newly_bound)
|
|
425
|
+
newly_bound.map { |var| "#{var} = nil; " }.join
|
|
426
|
+
end
|
|
415
427
|
end
|
|
416
428
|
end
|
|
417
429
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# encoding: UTF-8
|
|
3
3
|
#--
|
|
4
4
|
# This file is automatically generated. Do not modify it.
|
|
5
|
-
# Generated by: oedipus_lex version 2.6.
|
|
5
|
+
# Generated by: oedipus_lex version 2.6.3.
|
|
6
6
|
# Source: lib/rubocop/ast/node_pattern/lexer.rex
|
|
7
7
|
#++
|
|
8
8
|
|
|
@@ -122,7 +122,7 @@ class RuboCop::AST::NodePattern::LexerRex
|
|
|
122
122
|
# do nothing
|
|
123
123
|
when ss.skip(/:(#{SYMBOL_NAME})/o) then
|
|
124
124
|
action { emit :tSYMBOL, &:to_sym }
|
|
125
|
-
when ss.skip(/"(
|
|
125
|
+
when ss.skip(/"(.*?)"/) then
|
|
126
126
|
action { emit :tSTRING }
|
|
127
127
|
when ss.skip(/[-+]?\d+\.\d+/) then
|
|
128
128
|
action { emit :tNUMBER, &:to_f }
|
|
@@ -179,7 +179,7 @@ module RuboCop
|
|
|
179
179
|
class AnyOrder < Node
|
|
180
180
|
include ForbidInSeqHead
|
|
181
181
|
|
|
182
|
-
ARITIES = Hash.new { |h, k| h[k] = k - 1..Float::INFINITY }
|
|
182
|
+
ARITIES = Hash.new { |h, k| h[k] = (k - 1)..Float::INFINITY }
|
|
183
183
|
private_constant :ARITIES
|
|
184
184
|
|
|
185
185
|
def term_nodes
|
|
@@ -24,6 +24,8 @@ module RuboCop
|
|
|
24
24
|
# - With no block and no captures: #match returns `true`.
|
|
25
25
|
#
|
|
26
26
|
class NodePattern
|
|
27
|
+
class Invalid < StandardError; end
|
|
28
|
+
|
|
27
29
|
# Helpers for defining methods based on a pattern string
|
|
28
30
|
module Macros
|
|
29
31
|
# Define a method which applies a pattern to an AST node
|
|
@@ -50,7 +52,6 @@ module RuboCop
|
|
|
50
52
|
|
|
51
53
|
extend SimpleForwardable
|
|
52
54
|
include MethodDefiner
|
|
53
|
-
Invalid = Class.new(StandardError)
|
|
54
55
|
|
|
55
56
|
VAR = 'node'
|
|
56
57
|
|
|
@@ -25,6 +25,44 @@ module RuboCop
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# Extends the prism translation parsers so that the conversion of tokens
|
|
29
|
+
# into the `parser` gem's format is deferred until the tokens are first
|
|
30
|
+
# accessed. Building the tokens is a significant part of the translation
|
|
31
|
+
# cost, and not every caller needs them.
|
|
32
|
+
# @api private
|
|
33
|
+
module PrismLazyTokens
|
|
34
|
+
# Same contract as `Parser::Base#tokenize`, except the tokens are
|
|
35
|
+
# returned as a callable that performs the conversion when invoked.
|
|
36
|
+
def tokenize_deferred(source_buffer)
|
|
37
|
+
@source_buffer = source_buffer
|
|
38
|
+
source = source_buffer.source
|
|
39
|
+
|
|
40
|
+
offset_cache = build_offset_cache(source)
|
|
41
|
+
result = unwrap(@parser.parse_lex(source, **prism_options), offset_cache)
|
|
42
|
+
|
|
43
|
+
program, tokens = result.value
|
|
44
|
+
ast = build_ast(program, offset_cache) if result.success?
|
|
45
|
+
comments = build_comments(result.comments, offset_cache)
|
|
46
|
+
|
|
47
|
+
[ast, comments, deferred_tokens(source_buffer, tokens, offset_cache)]
|
|
48
|
+
ensure
|
|
49
|
+
@source_buffer = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def deferred_tokens(source_buffer, tokens, offset_cache)
|
|
55
|
+
lambda do
|
|
56
|
+
@source_buffer = source_buffer
|
|
57
|
+
begin
|
|
58
|
+
build_tokens(tokens, offset_cache)
|
|
59
|
+
ensure
|
|
60
|
+
@source_buffer = nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
28
66
|
# ProcessedSource contains objects which are generated by Parser
|
|
29
67
|
# and other information such as disabled lines for cops.
|
|
30
68
|
# It also provides a convenient way to access source lines.
|
|
@@ -38,7 +76,7 @@ module RuboCop
|
|
|
38
76
|
PARSER_ENGINES = %i[default parser_whitequark parser_prism].freeze
|
|
39
77
|
private_constant :PARSER_ENGINES
|
|
40
78
|
|
|
41
|
-
attr_reader :path, :buffer, :ast, :comments, :
|
|
79
|
+
attr_reader :path, :buffer, :ast, :comments, :diagnostics,
|
|
42
80
|
:parser_error, :raw_source, :ruby_version, :parser_engine
|
|
43
81
|
|
|
44
82
|
def self.from_file(path, ruby_version, parser_engine: :default)
|
|
@@ -46,6 +84,13 @@ module RuboCop
|
|
|
46
84
|
new(file, ruby_version, path, parser_engine: parser_engine)
|
|
47
85
|
end
|
|
48
86
|
|
|
87
|
+
# Subclasses of the prism translation parsers with lazily built tokens.
|
|
88
|
+
# @api private
|
|
89
|
+
def self.lazy_tokens_parser_class(base)
|
|
90
|
+
@lazy_tokens_parser_classes ||= {}
|
|
91
|
+
@lazy_tokens_parser_classes[base] ||= Class.new(base) { include PrismLazyTokens }
|
|
92
|
+
end
|
|
93
|
+
|
|
49
94
|
def initialize(
|
|
50
95
|
source, ruby_version, path = nil, parser_engine: :default, prism_result: nil
|
|
51
96
|
)
|
|
@@ -54,7 +99,7 @@ module RuboCop
|
|
|
54
99
|
# Defaults source encoding to UTF-8, regardless of the encoding it has
|
|
55
100
|
# been read with, which could be non-utf8 depending on the default
|
|
56
101
|
# external encoding.
|
|
57
|
-
(+source).force_encoding(Encoding::UTF_8) unless source.encoding == Encoding::UTF_8
|
|
102
|
+
source = (+source).force_encoding(Encoding::UTF_8) unless source.encoding == Encoding::UTF_8
|
|
58
103
|
|
|
59
104
|
@raw_source = source
|
|
60
105
|
@path = path
|
|
@@ -77,14 +122,13 @@ module RuboCop
|
|
|
77
122
|
def lines
|
|
78
123
|
@lines ||= begin
|
|
79
124
|
all_lines = @buffer.source_lines
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
125
|
+
if all_lines.include?('__END__')
|
|
126
|
+
trim_lines_after_data_marker(all_lines)
|
|
127
|
+
else
|
|
128
|
+
# Don't consult the tokens (which may have to be built first) when
|
|
129
|
+
# the source can't contain a data section.
|
|
130
|
+
all_lines.dup
|
|
86
131
|
end
|
|
87
|
-
result
|
|
88
132
|
end
|
|
89
133
|
end
|
|
90
134
|
|
|
@@ -100,7 +144,7 @@ module RuboCop
|
|
|
100
144
|
|
|
101
145
|
# Raw source checksum for tracking infinite loops.
|
|
102
146
|
def checksum
|
|
103
|
-
Digest::SHA1.hexdigest(@raw_source)
|
|
147
|
+
@checksum ||= Digest::SHA1.hexdigest(@raw_source)
|
|
104
148
|
end
|
|
105
149
|
|
|
106
150
|
# @deprecated Use `comments.each`
|
|
@@ -173,6 +217,8 @@ module RuboCop
|
|
|
173
217
|
end
|
|
174
218
|
|
|
175
219
|
def preceding_line(token)
|
|
220
|
+
return nil if token.line < 2
|
|
221
|
+
|
|
176
222
|
lines[token.line - 2]
|
|
177
223
|
end
|
|
178
224
|
|
|
@@ -191,6 +237,19 @@ module RuboCop
|
|
|
191
237
|
.length
|
|
192
238
|
end
|
|
193
239
|
|
|
240
|
+
# The tokens of the source. With the prism engine the tokens are built
|
|
241
|
+
# lazily on first access, since their conversion is costly and not
|
|
242
|
+
# every caller needs them.
|
|
243
|
+
def tokens
|
|
244
|
+
@tokens ||= begin
|
|
245
|
+
tokens = parser_tokens.map { |t| Token.from_parser_token(t) }
|
|
246
|
+
# The parser tokens are no longer needed, and the deferred conversion
|
|
247
|
+
# holds on to the parser instance, so release both.
|
|
248
|
+
@parser_tokens = nil
|
|
249
|
+
tokens
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
194
253
|
def tokens_within(range_or_node)
|
|
195
254
|
begin_index = first_token_index(range_or_node)
|
|
196
255
|
end_index = last_token_index(range_or_node)
|
|
@@ -209,12 +268,36 @@ module RuboCop
|
|
|
209
268
|
# is passed as a method argument. In this case tokens are interleaved by
|
|
210
269
|
# heredoc contents' tokens.
|
|
211
270
|
def sorted_tokens
|
|
212
|
-
#
|
|
213
|
-
|
|
271
|
+
# Most sources have their tokens already in order, in which case
|
|
272
|
+
# sorting can be skipped entirely. Callers only ever read from the
|
|
273
|
+
# returned array, so it is safe to reuse `tokens` as is.
|
|
274
|
+
@sorted_tokens ||= if tokens_sorted?
|
|
275
|
+
tokens
|
|
276
|
+
else
|
|
277
|
+
# Use stable sort.
|
|
278
|
+
tokens.sort_by.with_index { |token, i| [token.begin_pos, i] }
|
|
279
|
+
end
|
|
214
280
|
end
|
|
215
281
|
|
|
216
282
|
private
|
|
217
283
|
|
|
284
|
+
def tokens_sorted?
|
|
285
|
+
tokens.each_cons(2).all? { |a, b| a.begin_pos <= b.begin_pos }
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# `__END__` only starts a data section when it isn't nested inside a
|
|
289
|
+
# string or heredoc, which is what the last token's line disambiguates.
|
|
290
|
+
def trim_lines_after_data_marker(all_lines)
|
|
291
|
+
last_token_line = tokens.any? ? tokens.last.line : all_lines.size
|
|
292
|
+
result = []
|
|
293
|
+
all_lines.each_with_index do |line, ix|
|
|
294
|
+
break if ix >= last_token_line && line == '__END__'
|
|
295
|
+
|
|
296
|
+
result << line
|
|
297
|
+
end
|
|
298
|
+
result
|
|
299
|
+
end
|
|
300
|
+
|
|
218
301
|
def comment_index
|
|
219
302
|
@comment_index ||= {}.tap do |hash|
|
|
220
303
|
comments.each { |c| hash[c.location.line] = c }
|
|
@@ -222,8 +305,7 @@ module RuboCop
|
|
|
222
305
|
end
|
|
223
306
|
|
|
224
307
|
def parse(source, ruby_version, parser_engine, prism_result)
|
|
225
|
-
|
|
226
|
-
@buffer = Parser::Source::Buffer.new(buffer_name, 1)
|
|
308
|
+
@buffer = Parser::Source::Buffer.new(@path || STRING_SOURCE_NAME, 1)
|
|
227
309
|
|
|
228
310
|
begin
|
|
229
311
|
@buffer.source = source
|
|
@@ -237,12 +319,23 @@ module RuboCop
|
|
|
237
319
|
|
|
238
320
|
parser = create_parser(ruby_version, parser_engine, prism_result)
|
|
239
321
|
|
|
240
|
-
@ast, @comments,
|
|
322
|
+
@ast, @comments, tokens = tokenize(parser)
|
|
323
|
+
store_tokens(tokens)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# The tokens may be an already converted array, or a deferred conversion
|
|
327
|
+
# to be performed when the tokens are first accessed.
|
|
328
|
+
def store_tokens(tokens)
|
|
329
|
+
if tokens.is_a?(Proc)
|
|
330
|
+
@deferred_parser_tokens = tokens
|
|
331
|
+
else
|
|
332
|
+
@parser_tokens = tokens
|
|
333
|
+
end
|
|
241
334
|
end
|
|
242
335
|
|
|
243
336
|
def tokenize(parser)
|
|
244
337
|
begin
|
|
245
|
-
ast, comments, tokens = parser
|
|
338
|
+
ast, comments, tokens = parse_and_lex(parser)
|
|
246
339
|
ast ||= nil # force `false` to `nil`, see https://github.com/whitequark/parser/pull/722
|
|
247
340
|
rescue Parser::SyntaxError
|
|
248
341
|
# All errors are in diagnostics. No need to handle exception.
|
|
@@ -251,11 +344,27 @@ module RuboCop
|
|
|
251
344
|
end
|
|
252
345
|
|
|
253
346
|
ast&.complete!
|
|
254
|
-
tokens.map! { |t| Token.from_parser_token(t) }
|
|
255
347
|
|
|
256
348
|
[ast, comments, tokens]
|
|
257
349
|
end
|
|
258
350
|
|
|
351
|
+
def parse_and_lex(parser)
|
|
352
|
+
if parser.respond_to?(:tokenize_deferred)
|
|
353
|
+
parser.tokenize_deferred(@buffer)
|
|
354
|
+
else
|
|
355
|
+
parser.tokenize(@buffer)
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def parser_tokens
|
|
360
|
+
if @deferred_parser_tokens
|
|
361
|
+
@parser_tokens = @deferred_parser_tokens.call
|
|
362
|
+
@deferred_parser_tokens = nil
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
@parser_tokens
|
|
366
|
+
end
|
|
367
|
+
|
|
259
368
|
# rubocop:disable Lint/FloatComparison, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
260
369
|
def parser_class(ruby_version, parser_engine)
|
|
261
370
|
case parser_engine
|
|
@@ -310,14 +419,13 @@ module RuboCop
|
|
|
310
419
|
when :parser_prism
|
|
311
420
|
case ruby_version
|
|
312
421
|
when 3.3
|
|
313
|
-
require 'prism/translation/parser33'
|
|
314
422
|
Prism::Translation::Parser33
|
|
315
423
|
when 3.4
|
|
316
|
-
require 'prism/translation/parser34'
|
|
317
424
|
Prism::Translation::Parser34
|
|
318
|
-
when 3.5
|
|
319
|
-
|
|
320
|
-
|
|
425
|
+
when 3.5, 4.0
|
|
426
|
+
Prism::Translation::Parser40
|
|
427
|
+
when 4.1
|
|
428
|
+
Prism::Translation::Parser41
|
|
321
429
|
else
|
|
322
430
|
raise ArgumentError, 'RuboCop supports target Ruby versions 3.3 and above with Prism. ' \
|
|
323
431
|
"Specified target Ruby version: #{ruby_version.inspect}"
|
|
@@ -341,6 +449,9 @@ module RuboCop
|
|
|
341
449
|
|
|
342
450
|
parser_class = parser_class(ruby_version, parser_engine)
|
|
343
451
|
|
|
452
|
+
parser_class = self.class.lazy_tokens_parser_class(parser_class) if
|
|
453
|
+
parser_engine == :parser_prism
|
|
454
|
+
|
|
344
455
|
parser_instance = if parser_engine == :parser_prism && prism_result
|
|
345
456
|
# NOTE: Since it is intended for use with Ruby LSP, it targets only Prism.
|
|
346
457
|
# If there is no reuse of a pre-parsed result, such as in Ruby LSP,
|
|
@@ -379,11 +490,11 @@ module RuboCop
|
|
|
379
490
|
end
|
|
380
491
|
end
|
|
381
492
|
|
|
382
|
-
#
|
|
383
|
-
#
|
|
384
|
-
#
|
|
493
|
+
# Prism is used for all Ruby versions it can parse (3.3 and later);
|
|
494
|
+
# the Parser gem does not support Ruby 3.5 or later and is not fully
|
|
495
|
+
# compatible with Ruby 3.4.
|
|
385
496
|
def default_parser_engine(ruby_version)
|
|
386
|
-
if ruby_version >= 3.
|
|
497
|
+
if ruby_version >= 3.3
|
|
387
498
|
:parser_prism
|
|
388
499
|
else
|
|
389
500
|
:parser_whitequark
|
|
@@ -79,13 +79,14 @@ module RuboCop
|
|
|
79
79
|
end
|
|
80
80
|
private_constant :CallbackCompiler
|
|
81
81
|
extend CallbackCompiler
|
|
82
|
+
|
|
82
83
|
send_code = CallbackCompiler::SEND
|
|
83
84
|
|
|
84
85
|
### children count == 0
|
|
85
86
|
no_children = %i[true false nil self cbase zsuper redo retry
|
|
86
87
|
forward_args forwarded_args match_nil_pattern
|
|
87
88
|
forward_arg forwarded_restarg forwarded_kwrestarg
|
|
88
|
-
lambda empty_else kwnilarg
|
|
89
|
+
lambda empty_else kwnilarg blocknilarg
|
|
89
90
|
__FILE__ __LINE__ __ENCODING__]
|
|
90
91
|
|
|
91
92
|
### children count == 0..1
|
data/lib/rubocop/ast/version.rb
CHANGED
data/lib/rubocop/ast.rb
CHANGED
|
@@ -48,6 +48,7 @@ require_relative 'ast/node/case_match_node'
|
|
|
48
48
|
require_relative 'ast/node/case_node'
|
|
49
49
|
require_relative 'ast/node/casgn_node'
|
|
50
50
|
require_relative 'ast/node/class_node'
|
|
51
|
+
require_relative 'ast/node/complex_node'
|
|
51
52
|
require_relative 'ast/node/const_node'
|
|
52
53
|
require_relative 'ast/node/def_node'
|
|
53
54
|
require_relative 'ast/node/defined_node'
|
metadata
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-ast
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.50.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bozhidar Batsov
|
|
8
8
|
- Jonas Arvidsson
|
|
9
9
|
- Yuji Nakayama
|
|
10
|
-
autorequire:
|
|
11
10
|
bindir: bin
|
|
12
11
|
cert_chain: []
|
|
13
|
-
date:
|
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
14
13
|
dependencies:
|
|
15
14
|
- !ruby/object:Gem::Dependency
|
|
16
15
|
name: parser
|
|
@@ -32,14 +31,14 @@ dependencies:
|
|
|
32
31
|
requirements:
|
|
33
32
|
- - "~>"
|
|
34
33
|
- !ruby/object:Gem::Version
|
|
35
|
-
version: '1.
|
|
34
|
+
version: '1.7'
|
|
36
35
|
type: :runtime
|
|
37
36
|
prerelease: false
|
|
38
37
|
version_requirements: !ruby/object:Gem::Requirement
|
|
39
38
|
requirements:
|
|
40
39
|
- - "~>"
|
|
41
40
|
- !ruby/object:Gem::Version
|
|
42
|
-
version: '1.
|
|
41
|
+
version: '1.7'
|
|
43
42
|
description: " RuboCop's Node and NodePattern classes.\n"
|
|
44
43
|
email: rubocop@googlegroups.com
|
|
45
44
|
executables: []
|
|
@@ -69,6 +68,7 @@ files:
|
|
|
69
68
|
- lib/rubocop/ast/node/case_node.rb
|
|
70
69
|
- lib/rubocop/ast/node/casgn_node.rb
|
|
71
70
|
- lib/rubocop/ast/node/class_node.rb
|
|
71
|
+
- lib/rubocop/ast/node/complex_node.rb
|
|
72
72
|
- lib/rubocop/ast/node/const_node.rb
|
|
73
73
|
- lib/rubocop/ast/node/csend_node.rb
|
|
74
74
|
- lib/rubocop/ast/node/def_node.rb
|
|
@@ -162,7 +162,6 @@ metadata:
|
|
|
162
162
|
documentation_uri: https://docs.rubocop.org/rubocop-ast/
|
|
163
163
|
bug_tracker_uri: https://github.com/rubocop/rubocop-ast/issues
|
|
164
164
|
rubygems_mfa_required: 'true'
|
|
165
|
-
post_install_message:
|
|
166
165
|
rdoc_options: []
|
|
167
166
|
require_paths:
|
|
168
167
|
- lib
|
|
@@ -177,8 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
177
176
|
- !ruby/object:Gem::Version
|
|
178
177
|
version: '0'
|
|
179
178
|
requirements: []
|
|
180
|
-
rubygems_version:
|
|
181
|
-
signing_key:
|
|
179
|
+
rubygems_version: 4.0.3
|
|
182
180
|
specification_version: 4
|
|
183
181
|
summary: RuboCop tools to deal with Ruby code AST.
|
|
184
182
|
test_files: []
|