rubocop-ast 1.49.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/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/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/descendence.rb +21 -4
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +5 -5
- data/lib/rubocop/ast/node/mixin/numeric_node.rb +1 -1
- 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 +30 -7
- data/lib/rubocop/ast/processed_source.rb +133 -21
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +1 -1
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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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`.
|
|
@@ -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
|
|
@@ -172,6 +179,13 @@ module RuboCop
|
|
|
172
179
|
# Allows specific single node types, as well as "grouped" types
|
|
173
180
|
# (e.g. `:boolean` for `:true` or `:false`)
|
|
174
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)
|
|
175
189
|
return true if types.include?(type)
|
|
176
190
|
|
|
177
191
|
group_type = GROUP_FOR_TYPE[type]
|
|
@@ -287,7 +301,7 @@ module RuboCop
|
|
|
287
301
|
# Some node types override this with their own custom
|
|
288
302
|
# destructuring method.
|
|
289
303
|
#
|
|
290
|
-
# @return [Array<Node>] the different parts of the
|
|
304
|
+
# @return [Array<Node>] the different parts of the node
|
|
291
305
|
alias node_parts to_a
|
|
292
306
|
|
|
293
307
|
# Calls the given block for each ancestor node from parent to root.
|
|
@@ -503,7 +517,7 @@ module RuboCop
|
|
|
503
517
|
end
|
|
504
518
|
|
|
505
519
|
def special_keyword?
|
|
506
|
-
SPECIAL_KEYWORDS.include?(source)
|
|
520
|
+
SPECIAL_KEYWORD_TYPES.include?(type) && SPECIAL_KEYWORDS.include?(source)
|
|
507
521
|
end
|
|
508
522
|
|
|
509
523
|
def operator_keyword?
|
|
@@ -519,11 +533,13 @@ module RuboCop
|
|
|
519
533
|
end
|
|
520
534
|
|
|
521
535
|
def chained?
|
|
522
|
-
parent&.call_type? &&
|
|
536
|
+
parent&.call_type? && equal?(parent.receiver)
|
|
523
537
|
end
|
|
524
538
|
|
|
525
539
|
def argument?
|
|
526
|
-
parent&.send_type?
|
|
540
|
+
return false unless parent&.send_type?
|
|
541
|
+
|
|
542
|
+
parent.arguments.any? { |argument| argument.equal?(self) }
|
|
527
543
|
end
|
|
528
544
|
|
|
529
545
|
def any_def_type?
|
|
@@ -695,9 +711,16 @@ module RuboCop
|
|
|
695
711
|
def visit_ancestors(types)
|
|
696
712
|
last_node = self
|
|
697
713
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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
|
|
701
724
|
end
|
|
702
725
|
end
|
|
703
726
|
|
|
@@ -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
|
|
@@ -340,6 +449,9 @@ module RuboCop
|
|
|
340
449
|
|
|
341
450
|
parser_class = parser_class(ruby_version, parser_engine)
|
|
342
451
|
|
|
452
|
+
parser_class = self.class.lazy_tokens_parser_class(parser_class) if
|
|
453
|
+
parser_engine == :parser_prism
|
|
454
|
+
|
|
343
455
|
parser_instance = if parser_engine == :parser_prism && prism_result
|
|
344
456
|
# NOTE: Since it is intended for use with Ruby LSP, it targets only Prism.
|
|
345
457
|
# If there is no reuse of a pre-parsed result, such as in Ruby LSP,
|
|
@@ -378,11 +490,11 @@ module RuboCop
|
|
|
378
490
|
end
|
|
379
491
|
end
|
|
380
492
|
|
|
381
|
-
#
|
|
382
|
-
#
|
|
383
|
-
#
|
|
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.
|
|
384
496
|
def default_parser_engine(ruby_version)
|
|
385
|
-
if ruby_version >= 3.
|
|
497
|
+
if ruby_version >= 3.3
|
|
386
498
|
:parser_prism
|
|
387
499
|
else
|
|
388
500
|
:parser_whitequark
|
data/lib/rubocop/ast/version.rb
CHANGED