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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7fd9852873f22808386ddc6962f7373509ec03930f3e5c667475d512480b705
4
- data.tar.gz: b6d36926cd045b8486679af378d1fdd21875b941d3f5916fbb6876f04ef75e11
3
+ metadata.gz: 7d2a487128abbc36ae15a961ea8b7d1e5c63a266efb81cfbb815965d4f77a4e0
4
+ data.tar.gz: 10af6d44e0a7b22a6e43f3e14e720c0df6991be9efc2e38ad47c5526d170d935
5
5
  SHA512:
6
- metadata.gz: b83bb3a5b3c20a8831d6ad8e075d536b3ff8042d873ce6062161fbe1556e80da5fc4646499dc0432864ecb034ffe3ade83f7ac2f37562a9df22620b486e61e5a
7
- data.tar.gz: d6f98f800797330d515911991c9215e8fa616cdcde7a73666aa0d25ff05b70b9274a1f0df689f8a820a6573c391bca487100a258a142c21a60f3fd8ea6e5c5e8
6
+ metadata.gz: 4eec6dc6fbb933a3c8628cfc54332e1b019b7423b298ac155899cfc62db3e52ddfd1a3308d20bea5e856250ed56af0a84ae856e4ef482e7368e0f1c1be264639
7
+ data.tar.gz: 1e20432910c02a763ccc0d99ac18771b4ac0ac578c2d749ecc77e9084ec4784551fb8778ee3bbdf24709a9ec00f046320cb37c9975038c04f5674a24db943c04
@@ -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? ? true : parent.value_used?
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(source, ruby_version, path = nil, parser_engine: :parser_whitequark)
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
- @ast, @comments, @tokens = tokenize(create_parser(ruby_version, parser_engine))
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
- def create_parser(ruby_version, parser_engine)
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).new(builder).tap do |parser|
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, *signature,
36
- arity: signature.size..signature.size,
37
- arity_check: ENV.fetch('RUBOCOP_DEBUG', nil) && self.arity_check(arity),
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(signature, prelude)
53
- signature
54
- .map.with_index do |arg, i|
55
- TEMPLATE[arg].gsub('%<index>i', i.to_s)
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 arity_check(range)
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
- ### arity == 0
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
- ### arity == 0..1
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
- ### arity == 1
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
- ### arity > 1
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 arity
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, arity: 0..1
125
- def_callback opt_node_child, :nil?, arity: 0..1
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?, arity: 1..2
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, arity_check: nil
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?, arity: 2..3
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
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module AST
5
5
  module Version
6
- STRING = '1.38.1'
6
+ STRING = '1.39.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.38.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-02-25 00:00:00.000000000 Z
13
+ date: 2025-03-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parser