rubocop-ast 1.38.1 → 1.39.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.rb +1 -1
- data/lib/rubocop/ast/processed_source.rb +50 -6
- data/lib/rubocop/ast/traversal.rb +29 -20
- 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: 7d2a487128abbc36ae15a961ea8b7d1e5c63a266efb81cfbb815965d4f77a4e0
|
4
|
+
data.tar.gz: 10af6d44e0a7b22a6e43f3e14e720c0df6991be9efc2e38ad47c5526d170d935
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4eec6dc6fbb933a3c8628cfc54332e1b019b7423b298ac155899cfc62db3e52ddfd1a3308d20bea5e856250ed56af0a84ae856e4ef482e7368e0f1c1be264639
|
7
|
+
data.tar.gz: 1e20432910c02a763ccc0d99ac18771b4ac0ac578c2d749ecc77e9084ec4784551fb8778ee3bbdf24709a9ec00f046320cb37c9975038c04f5674a24db943c04
|
data/lib/rubocop/ast/node.rb
CHANGED
@@ -685,7 +685,7 @@ module RuboCop
|
|
685
685
|
def case_if_value_used?
|
686
686
|
# (case <condition> <when...>)
|
687
687
|
# (if <condition> <truebranch> <falsebranch>)
|
688
|
-
sibling_index.zero?
|
688
|
+
sibling_index.zero? || parent.value_used?
|
689
689
|
end
|
690
690
|
|
691
691
|
def while_until_value_used?
|
@@ -4,6 +4,27 @@ require 'digest/sha1'
|
|
4
4
|
|
5
5
|
module RuboCop
|
6
6
|
module AST
|
7
|
+
# A `Prism` interface's class that provides a fixed `Prism::ParseLexResult` instead of parsing.
|
8
|
+
#
|
9
|
+
# This class implements the `parse_lex` method to return a preparsed `Prism::ParseLexResult`
|
10
|
+
# rather than parsing the source code. When the parse result is already available externally,
|
11
|
+
# such as in Ruby LSP, the Prism parsing process can be bypassed.
|
12
|
+
class PrismPreparsed
|
13
|
+
def initialize(prism_result)
|
14
|
+
unless prism_result.is_a?(Prism::ParseLexResult)
|
15
|
+
raise ArgumentError, <<~MESSAGE
|
16
|
+
Expected a `Prism::ParseLexResult` object, but received `#{prism_result.class}`.
|
17
|
+
MESSAGE
|
18
|
+
end
|
19
|
+
|
20
|
+
@prism_result = prism_result
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_lex(_source, **_prism_options)
|
24
|
+
@prism_result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
7
28
|
# ProcessedSource contains objects which are generated by Parser
|
8
29
|
# and other information such as disabled lines for cops.
|
9
30
|
# It also provides a convenient way to access source lines.
|
@@ -25,7 +46,9 @@ module RuboCop
|
|
25
46
|
new(file, ruby_version, path, parser_engine: parser_engine)
|
26
47
|
end
|
27
48
|
|
28
|
-
def initialize(
|
49
|
+
def initialize(
|
50
|
+
source, ruby_version, path = nil, parser_engine: :parser_whitequark, prism_result: nil
|
51
|
+
)
|
29
52
|
parser_engine = parser_engine.to_sym
|
30
53
|
unless PARSER_ENGINES.include?(parser_engine)
|
31
54
|
raise ArgumentError, 'The keyword argument `parser_engine` accepts `parser_whitequark` ' \
|
@@ -44,7 +67,7 @@ module RuboCop
|
|
44
67
|
@parser_engine = parser_engine
|
45
68
|
@parser_error = nil
|
46
69
|
|
47
|
-
parse(source, ruby_version, parser_engine)
|
70
|
+
parse(source, ruby_version, parser_engine, prism_result)
|
48
71
|
end
|
49
72
|
|
50
73
|
def ast_with_comments
|
@@ -202,7 +225,7 @@ module RuboCop
|
|
202
225
|
end
|
203
226
|
end
|
204
227
|
|
205
|
-
def parse(source, ruby_version, parser_engine)
|
228
|
+
def parse(source, ruby_version, parser_engine, prism_result)
|
206
229
|
buffer_name = @path || STRING_SOURCE_NAME
|
207
230
|
@buffer = Parser::Source::Buffer.new(buffer_name, 1)
|
208
231
|
|
@@ -216,7 +239,9 @@ module RuboCop
|
|
216
239
|
return
|
217
240
|
end
|
218
241
|
|
219
|
-
|
242
|
+
parser = create_parser(ruby_version, parser_engine, prism_result)
|
243
|
+
|
244
|
+
@ast, @comments, @tokens = tokenize(parser)
|
220
245
|
end
|
221
246
|
|
222
247
|
def tokenize(parser)
|
@@ -326,10 +351,28 @@ module RuboCop
|
|
326
351
|
exit!
|
327
352
|
end
|
328
353
|
|
329
|
-
|
354
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
355
|
+
def create_parser(ruby_version, parser_engine, prism_result)
|
330
356
|
builder = RuboCop::AST::Builder.new
|
331
357
|
|
332
|
-
parser_class(ruby_version, parser_engine)
|
358
|
+
parser_class = parser_class(ruby_version, parser_engine)
|
359
|
+
|
360
|
+
# NOTE: Check if the `Prism#initialize` method has the `:parser` keyword argument.
|
361
|
+
# The `:parser` keyword argument cannot be used to switch parsers because older versions of
|
362
|
+
# Prism do not support it.
|
363
|
+
parser_switch_available = parser_class.instance_method(:initialize).parameters.assoc(:key)
|
364
|
+
|
365
|
+
parser_instance = if prism_result && parser_switch_available
|
366
|
+
# NOTE: Since it is intended for use with Ruby LSP, it targets only Prism.
|
367
|
+
# If there is no reuse of a pre-parsed result, such as in Ruby LSP,
|
368
|
+
# regular parsing with Prism occurs, and `else` branch will be executed.
|
369
|
+
prism_reparsed = PrismPreparsed.new(prism_result)
|
370
|
+
parser_class.new(builder, parser: prism_reparsed)
|
371
|
+
else
|
372
|
+
parser_class.new(builder)
|
373
|
+
end
|
374
|
+
|
375
|
+
parser_instance.tap do |parser|
|
333
376
|
# On JRuby there's a risk that we hang in tokenize() if we
|
334
377
|
# don't set the all errors as fatal flag. The problem is caused by a bug
|
335
378
|
# in Racc that is discussed in issue #93 of the whitequark/parser
|
@@ -341,6 +384,7 @@ module RuboCop
|
|
341
384
|
end
|
342
385
|
end
|
343
386
|
end
|
387
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
344
388
|
|
345
389
|
def first_token_index(range_or_node)
|
346
390
|
begin_pos = source_range(range_or_node).begin_pos
|
@@ -26,16 +26,18 @@ module RuboCop
|
|
26
26
|
SEND = 'send(TYPE_TO_METHOD[child.type], child)'
|
27
27
|
assign_code = 'child = node.children[%<index>i]'
|
28
28
|
code = "#{assign_code}\n#{SEND}"
|
29
|
+
# How a particular child node should be visited. For example, if a child node
|
30
|
+
# can be nil it should be guarded behind a nil check. Or, if a child node is a literal
|
31
|
+
# (like a symbol) then the literal itself should not be visited.
|
29
32
|
TEMPLATE = {
|
30
33
|
skip: '',
|
31
34
|
always: code,
|
32
35
|
nil?: "#{code} if child"
|
33
36
|
}.freeze
|
34
37
|
|
35
|
-
def def_callback(type, *
|
36
|
-
|
37
|
-
|
38
|
-
body: self.body(signature, arity_check))
|
38
|
+
def def_callback(type, *child_node_types,
|
39
|
+
expected_children_count: child_node_types.size..child_node_types.size,
|
40
|
+
body: self.body(child_node_types, expected_children_count))
|
39
41
|
type, *aliases = type
|
40
42
|
lineno = caller_locations(1, 1).first.lineno
|
41
43
|
module_eval(<<~RUBY, __FILE__, lineno)
|
@@ -49,16 +51,23 @@ module RuboCop
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
|
-
def body(
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
def body(child_node_types, expected_children_count)
|
55
|
+
visit_children_code =
|
56
|
+
child_node_types
|
57
|
+
.map.with_index do |child_type, i|
|
58
|
+
TEMPLATE.fetch(child_type).gsub('%<index>i', i.to_s)
|
56
59
|
end
|
57
|
-
.unshift(prelude)
|
58
60
|
.join("\n")
|
61
|
+
|
62
|
+
<<~BODY
|
63
|
+
#{children_count_check_code(expected_children_count)}
|
64
|
+
#{visit_children_code}
|
65
|
+
BODY
|
59
66
|
end
|
60
67
|
|
61
|
-
def
|
68
|
+
def children_count_check_code(range)
|
69
|
+
return '' unless ENV.fetch('RUBOCOP_DEBUG', false)
|
70
|
+
|
62
71
|
<<~RUBY
|
63
72
|
n = node.children.size
|
64
73
|
raise DebugError, [
|
@@ -72,18 +81,18 @@ module RuboCop
|
|
72
81
|
extend CallbackCompiler
|
73
82
|
send_code = CallbackCompiler::SEND
|
74
83
|
|
75
|
-
###
|
84
|
+
### children count == 0
|
76
85
|
no_children = %i[true false nil self cbase zsuper redo retry
|
77
86
|
forward_args forwarded_args match_nil_pattern
|
78
87
|
forward_arg forwarded_restarg forwarded_kwrestarg
|
79
88
|
lambda empty_else kwnilarg
|
80
89
|
__FILE__ __LINE__ __ENCODING__]
|
81
90
|
|
82
|
-
###
|
91
|
+
### children count == 0..1
|
83
92
|
opt_symbol_child = %i[restarg kwrestarg]
|
84
93
|
opt_node_child = %i[splat kwsplat match_rest]
|
85
94
|
|
86
|
-
###
|
95
|
+
### children count == 1
|
87
96
|
literal_child = %i[int float complex
|
88
97
|
rational str sym lvar
|
89
98
|
ivar cvar gvar nth_ref back_ref
|
@@ -100,12 +109,12 @@ module RuboCop
|
|
100
109
|
NO_CHILD_NODES = (no_children + opt_symbol_child + literal_child).to_set.freeze
|
101
110
|
private_constant :NO_CHILD_NODES # Used by Commissioner
|
102
111
|
|
103
|
-
###
|
112
|
+
### children count > 1
|
104
113
|
symbol_then_opt_node = %i[lvasgn ivasgn cvasgn gvasgn]
|
105
114
|
symbol_then_node_or_nil = %i[optarg kwoptarg]
|
106
115
|
node_then_opt_node = %i[while until module sclass]
|
107
116
|
|
108
|
-
### variable
|
117
|
+
### variable children count
|
109
118
|
many_node_children = %i[dstr dsym xstr regexp array hash pair
|
110
119
|
mlhs masgn or_asgn and_asgn rasgn mrasgn
|
111
120
|
undef alias args super yield or and
|
@@ -121,18 +130,18 @@ module RuboCop
|
|
121
130
|
|
122
131
|
### Callbacks for above
|
123
132
|
def_callback no_children
|
124
|
-
def_callback opt_symbol_child, :skip,
|
125
|
-
def_callback opt_node_child, :nil?,
|
133
|
+
def_callback opt_symbol_child, :skip, expected_children_count: 0..1
|
134
|
+
def_callback opt_node_child, :nil?, expected_children_count: 0..1
|
126
135
|
|
127
136
|
def_callback literal_child, :skip
|
128
137
|
def_callback node_child, :always
|
129
138
|
def_callback node_or_nil_child, :nil?
|
130
139
|
|
131
|
-
def_callback symbol_then_opt_node, :skip, :nil?,
|
140
|
+
def_callback symbol_then_opt_node, :skip, :nil?, expected_children_count: 1..2
|
132
141
|
def_callback symbol_then_node_or_nil, :skip, :nil?
|
133
142
|
def_callback node_then_opt_node, :always, :nil?
|
134
143
|
|
135
|
-
def_callback many_symbol_children, :skip,
|
144
|
+
def_callback many_symbol_children, :skip, expected_children_count: (0..)
|
136
145
|
def_callback many_node_children, body: <<~RUBY
|
137
146
|
node.children.each { |child| #{send_code} }
|
138
147
|
RUBY
|
@@ -143,7 +152,7 @@ module RuboCop
|
|
143
152
|
|
144
153
|
### Other particular cases
|
145
154
|
def_callback :const, :nil?, :skip
|
146
|
-
def_callback :casgn, :nil?, :skip, :nil?,
|
155
|
+
def_callback :casgn, :nil?, :skip, :nil?, expected_children_count: 2..3
|
147
156
|
def_callback :class, :always, :nil?, :nil?
|
148
157
|
def_callback :def, :skip, :always, :nil?
|
149
158
|
def_callback :op_asgn, :always, :skip, :always
|
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.39.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: 2025-
|
13
|
+
date: 2025-03-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: parser
|