rubocop-ast 0.3.0 → 0.5.1

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: 918c6017183db74497fc68166973904312bac7583f7752c2e55d1829574cb248
4
- data.tar.gz: 1d04eb24fcbaec96b4bf0f17694018c31034fce4b3d81a9446ca98b3085e05a4
3
+ metadata.gz: f71ef8c3ea38e4fc2ef139e7ec61bc6811cc4aea1e3cc4031055ca49aa2a20b3
4
+ data.tar.gz: 3b338905a203f204230099806070e653785e0999d196b09d6a2af3ed69450c10
5
5
  SHA512:
6
- metadata.gz: 54f6882ebf057c76a9c97212a62b295d03baea85ec7c44e606b412e74edce01b6c4bba93dfafa341756009a8bfa2352c4b2b3b22bdbf689dac08ddd9395a9aff
7
- data.tar.gz: '08e60b802e83dba688bf1a31be417f9880b640194cf3b966849dd2c211de5a1f3797c8a37be3f2d3aa466d6c994b10c31277b0ed3dc708b12fe1c2f7a0f15552'
6
+ metadata.gz: 61df3d081d020042e922967ed5653781f5c589c9960dc9666d17a339b4c09f57cb948df4be2356bbc175598d4cbbc9f10329e2020f468f1812ce1da383a2768f
7
+ data.tar.gz: fc5711d88c212f81d4bc0e9aedf461de610d2903a22e217b11ccc95fbabad0170c1a0149b79f49db8475e848cee2b86924f302ea4172e67eee5b7b6e2ab38229
@@ -5,6 +5,7 @@ require 'forwardable'
5
5
  require 'set'
6
6
 
7
7
  require_relative 'ast/ext/range'
8
+ require_relative 'ast/ext/set'
8
9
  require_relative 'ast/node_pattern'
9
10
  require_relative 'ast/sexp'
10
11
  require_relative 'ast/node'
@@ -28,6 +29,7 @@ require_relative 'ast/node/break_node'
28
29
  require_relative 'ast/node/case_match_node'
29
30
  require_relative 'ast/node/case_node'
30
31
  require_relative 'ast/node/class_node'
32
+ require_relative 'ast/node/const_node'
31
33
  require_relative 'ast/node/def_node'
32
34
  require_relative 'ast/node/defined_node'
33
35
  require_relative 'ast/node/ensure_node'
@@ -47,6 +49,7 @@ require_relative 'ast/node/or_node'
47
49
  require_relative 'ast/node/pair_node'
48
50
  require_relative 'ast/node/range_node'
49
51
  require_relative 'ast/node/regexp_node'
52
+ require_relative 'ast/node/rescue_node'
50
53
  require_relative 'ast/node/resbody_node'
51
54
  require_relative 'ast/node/return_node'
52
55
  require_relative 'ast/node/self_class_node'
@@ -60,6 +63,7 @@ require_relative 'ast/node/while_node'
60
63
  require_relative 'ast/node/yield_node'
61
64
  require_relative 'ast/builder'
62
65
  require_relative 'ast/processed_source'
66
+ require_relative 'ast/rubocop_compatibility'
63
67
  require_relative 'ast/token'
64
68
  require_relative 'ast/traversal'
65
69
  require_relative 'ast/version'
@@ -27,6 +27,7 @@ module RuboCop
27
27
  case_match: CaseMatchNode,
28
28
  case: CaseNode,
29
29
  class: ClassNode,
30
+ const: ConstNode,
30
31
  def: DefNode,
31
32
  defined?: DefinedNode,
32
33
  defs: DefNode,
@@ -48,6 +49,7 @@ module RuboCop
48
49
  or: OrNode,
49
50
  pair: PairNode,
50
51
  regexp: RegexpNode,
52
+ rescue: RescueNode,
51
53
  resbody: ResbodyNode,
52
54
  return: ReturnNode,
53
55
  csend: SendNode,
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ test = :foo
4
+ case test
5
+ when Set[:foo]
6
+ # ok, RUBY_VERSION > 2.4
7
+ else
8
+ # Harmonize `Set#===`
9
+ class Set
10
+ alias === include?
11
+ end
12
+ end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  IMMUTABLE_LITERALS = (LITERALS - MUTABLE_LITERALS).freeze
39
39
 
40
40
  EQUALS_ASSIGNMENTS = %i[lvasgn ivasgn cvasgn gvasgn
41
- casgn masgn].freeze
41
+ casgn masgn rasgn mrasgn].freeze
42
42
  SHORTHAND_ASSIGNMENTS = %i[op_asgn or_asgn and_asgn].freeze
43
43
  ASSIGNMENTS = (EQUALS_ASSIGNMENTS + SHORTHAND_ASSIGNMENTS).freeze
44
44
 
@@ -92,6 +92,16 @@ module RuboCop
92
92
  @mutable_attributes[:parent] = node
93
93
  end
94
94
 
95
+ # @return [Boolean]
96
+ def parent?
97
+ !!parent
98
+ end
99
+
100
+ # @return [Boolean]
101
+ def root?
102
+ !parent
103
+ end
104
+
95
105
  def complete!
96
106
  @mutable_attributes.freeze
97
107
  each_child_node(&:complete!)
@@ -116,12 +126,50 @@ module RuboCop
116
126
 
117
127
  # Returns the index of the receiver node in its siblings. (Sibling index
118
128
  # uses zero based numbering.)
129
+ # Use is discouraged, this is a potentially slow method.
119
130
  #
120
- # @return [Integer] the index of the receiver node in its siblings
131
+ # @return [Integer, nil] the index of the receiver node in its siblings
121
132
  def sibling_index
122
133
  parent&.children&.index { |sibling| sibling.equal?(self) }
123
134
  end
124
135
 
136
+ # Use is discouraged, this is a potentially slow method and can lead
137
+ # to even slower algorithms
138
+ # @return [Node, nil] the right (aka next) sibling
139
+ def right_sibling
140
+ return unless parent
141
+
142
+ parent.children[sibling_index + 1].freeze
143
+ end
144
+
145
+ # Use is discouraged, this is a potentially slow method and can lead
146
+ # to even slower algorithms
147
+ # @return [Node, nil] the left (aka previous) sibling
148
+ def left_sibling
149
+ i = sibling_index
150
+ return if i.nil? || i.zero?
151
+
152
+ parent.children[i - 1].freeze
153
+ end
154
+
155
+ # Use is discouraged, this is a potentially slow method and can lead
156
+ # to even slower algorithms
157
+ # @return [Array<Node>] the left (aka previous) siblings
158
+ def left_siblings
159
+ return [].freeze unless parent
160
+
161
+ parent.children[0...sibling_index].freeze
162
+ end
163
+
164
+ # Use is discouraged, this is a potentially slow method and can lead
165
+ # to even slower algorithms
166
+ # @return [Array<Node>] the right (aka next) siblings
167
+ def right_siblings
168
+ return [].freeze unless parent
169
+
170
+ parent.children[sibling_index + 1..-1].freeze
171
+ end
172
+
125
173
  # Common destructuring method. This can be used to normalize
126
174
  # destructuring for different variations of the node.
127
175
  # Some node types override this with their own custom
@@ -261,8 +309,10 @@ module RuboCop
261
309
  self
262
310
  end
263
311
 
312
+ # Note: Some rare nodes may have no source, like `s(:args)` in `foo {}`
313
+ # @return [String, nil]
264
314
  def source
265
- loc.expression.source
315
+ loc.expression&.source
266
316
  end
267
317
 
268
318
  def source_range
@@ -25,7 +25,7 @@ module RuboCop
25
25
  # @return [Array<Node>]
26
26
  def arguments
27
27
  if numblock_type?
28
- [] # Numbered parameters have no block arguments.
28
+ [].freeze # Numbered parameters have no block arguments.
29
29
  else
30
30
  node_parts[1]
31
31
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `const` nodes.
6
+ class ConstNode < Node
7
+ # The `send` node associated with this block.
8
+ #
9
+ # @return [Node, nil] the node associated with the scope (e.g. cbase, const, ...)
10
+ def namespace
11
+ children[0]
12
+ end
13
+
14
+ # @return [Symbol] the demodulized name of the constant: "::Foo::Bar" => :Bar
15
+ def short_name
16
+ children[1]
17
+ end
18
+
19
+ # The body of this block.
20
+ #
21
+ # @return [Boolean] if the constant is a Module / Class, according to the standard convention.
22
+ # Note: some classes might have uppercase in which case this method
23
+ # returns false
24
+ def module_name?
25
+ short_name.match?(/[[:lower:]]/)
26
+ end
27
+ alias class_name? module_name?
28
+
29
+ # @return [Boolean] if the constant starts with `::` (aka s(:cbase))
30
+ def absolute?
31
+ return false unless namespace
32
+
33
+ each_path.first.cbase_type?
34
+ end
35
+
36
+ # @return [Boolean] if the constant does not start with `::` (aka s(:cbase))
37
+ def relative?
38
+ !absolute?
39
+ end
40
+
41
+ # Yield nodes for the namespace
42
+ #
43
+ # For `::Foo::Bar::BAZ` => yields:
44
+ # s(:cbase), then
45
+ # s(:const, :Foo), then
46
+ # s(:const, s(:const, :Foo), :Bar)
47
+ def each_path(&block)
48
+ return to_enum(__method__) unless block_given?
49
+
50
+ descendants = []
51
+ last = self
52
+ loop do
53
+ last = last.children.first
54
+ break if last.nil?
55
+
56
+ descendants << last
57
+ break unless last.const_type?
58
+ end
59
+ descendants.reverse_each(&block)
60
+
61
+ self
62
+ end
63
+ end
64
+ end
65
+ end
@@ -42,7 +42,7 @@ module RuboCop
42
42
  #
43
43
  # @return [Boolean] whether the dispatched method is a macro method
44
44
  def macro?
45
- !receiver && macro_scope?
45
+ !receiver && in_macro_scope?
46
46
  end
47
47
 
48
48
  # Checks whether the dispatched method is an access modifier.
@@ -222,31 +222,21 @@ module RuboCop
222
222
 
223
223
  private
224
224
 
225
- def_node_matcher :macro_scope?, <<~PATTERN
226
- {^{({sclass class module block} ...) class_constructor?}
227
- ^^{({sclass class module block} ... ({begin if} ...)) class_constructor?}
228
- ^#macro_kwbegin_wrapper?
229
- #root_node?}
225
+ def_node_matcher :in_macro_scope?, <<~PATTERN
226
+ {
227
+ root? # Either a root node,
228
+ ^{ # or the parent is...
229
+ sclass class module class_constructor? # a class-like node
230
+ [ { # or some "wrapper"
231
+ kwbegin begin block
232
+ (if _condition <%0 _>) # note: we're excluding the condition of `if` nodes
233
+ }
234
+ #in_macro_scope? # that is itself in a macro scope
235
+ ]
236
+ }
237
+ }
230
238
  PATTERN
231
239
 
232
- # Check if a node's parent is a kwbegin wrapper within a macro scope
233
- #
234
- # @param parent [Node] parent of the node being checked
235
- #
236
- # @return [Boolean] true if the parent is a kwbegin in a macro scope
237
- def macro_kwbegin_wrapper?(parent)
238
- parent.kwbegin_type? && macro_scope?(parent)
239
- end
240
-
241
- # Check if a node does not have a parent
242
- #
243
- # @param node [Node]
244
- #
245
- # @return [Boolean] if the parent is nil
246
- def root_node?(node)
247
- node.parent.nil?
248
- end
249
-
250
240
  def_node_matcher :adjacent_def_modifier?, <<~PATTERN
251
241
  (send nil? _ ({def defs} ...))
252
242
  PATTERN
@@ -82,9 +82,9 @@ module RuboCop
82
82
  # and optimizes other calls
83
83
  module RestArguments
84
84
  include ParameterizedNode
85
- # @return [Array] arguments, if any
85
+ # @return [Array<Node>] arguments, if any
86
86
  def arguments
87
- children[first_argument_index..-1]
87
+ children[first_argument_index..-1].freeze
88
88
  end
89
89
 
90
90
  # A shorthand for getting the first argument of the node.
@@ -13,12 +13,33 @@ module RuboCop
13
13
  node_parts[2]
14
14
  end
15
15
 
16
+ # Returns an array of all the exceptions in the `rescue` clause.
17
+ #
18
+ # @return [Array<Node>] an array of exception nodes
19
+ def exceptions
20
+ exceptions_node = node_parts[0]
21
+ if exceptions_node.nil?
22
+ []
23
+ elsif exceptions_node.array_type?
24
+ exceptions_node.values
25
+ else
26
+ [exceptions_node]
27
+ end
28
+ end
29
+
16
30
  # Returns the exception variable of the `rescue` clause.
17
31
  #
18
32
  # @return [Node, nil] The exception variable of the `resbody`.
19
33
  def exception_variable
20
34
  node_parts[1]
21
35
  end
36
+
37
+ # Returns the index of the `resbody` branch within the exception handling statement.
38
+ #
39
+ # @return [Integer] the index of the `resbody` branch
40
+ def branch_index
41
+ parent.resbody_branches.index(self)
42
+ end
22
43
  end
23
44
  end
24
45
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `rescue` nodes. This will be used in place of a
6
+ # plain node when the builder constructs the AST, making its methods
7
+ # available to all `rescue` nodes within RuboCop.
8
+ class RescueNode < Node
9
+ # Returns the body of the rescue node.
10
+ #
11
+ # @return [Node, nil] The body of the rescue node.
12
+ def body
13
+ node_parts[0]
14
+ end
15
+
16
+ # Returns an array of all the rescue branches in the exception handling statement.
17
+ #
18
+ # @return [Array<ResbodyNode>] an array of `resbody` nodes
19
+ def resbody_branches
20
+ node_parts[1...-1]
21
+ end
22
+
23
+ # Returns an array of all the rescue branches in the exception handling statement.
24
+ #
25
+ # @return [Array<Node, nil>] an array of the bodies of the rescue branches
26
+ # and the else (if any). Note that these bodies could be nil.
27
+ def branches
28
+ bodies = resbody_branches.map(&:body)
29
+ bodies.push(else_branch) if else?
30
+ bodies
31
+ end
32
+
33
+ # Returns the else branch of the exception handling statement, if any.
34
+ #
35
+ # @return [Node] the else branch node of the exception handling statement
36
+ # @return [nil] if the exception handling statement does not have an else branch.
37
+ def else_branch
38
+ node_parts[-1]
39
+ end
40
+
41
+ # Checks whether this exception handling statement has an `else` branch.
42
+ #
43
+ # @return [Boolean] whether the exception handling statement has an `else` branch
44
+ def else?
45
+ loc.else
46
+ end
47
+ end
48
+ end
49
+ end
@@ -205,7 +205,7 @@ module RuboCop
205
205
 
206
206
  def initialize(str, root = 'node0', node_var = root)
207
207
  @string = str
208
- # For def_node_pattern, root == node_var
208
+ # For def_node_matcher, root == node_var
209
209
  # For def_node_search, root is the root node to search on,
210
210
  # and node_var is the current descendant being searched.
211
211
  @root = root
@@ -159,6 +159,20 @@ module RuboCop
159
159
  .length
160
160
  end
161
161
 
162
+ def tokens_within(range_or_node)
163
+ begin_index = first_token_index(range_or_node)
164
+ end_index = last_token_index(range_or_node)
165
+ sorted_tokens[begin_index..end_index]
166
+ end
167
+
168
+ def first_token_of(range_or_node)
169
+ sorted_tokens[first_token_index(range_or_node)]
170
+ end
171
+
172
+ def last_token_of(range_or_node)
173
+ sorted_tokens[last_token_index(range_or_node)]
174
+ end
175
+
162
176
  private
163
177
 
164
178
  def comment_index
@@ -215,9 +229,9 @@ module RuboCop
215
229
  when 2.7
216
230
  require 'parser/ruby27'
217
231
  Parser::Ruby27
218
- when 2.8
219
- require 'parser/ruby28'
220
- Parser::Ruby28
232
+ when 2.8, 3.0
233
+ require 'parser/ruby30'
234
+ Parser::Ruby30
221
235
  else
222
236
  raise ArgumentError,
223
237
  "RuboCop found unknown Ruby version: #{ruby_version.inspect}"
@@ -240,6 +254,32 @@ module RuboCop
240
254
  end
241
255
  end
242
256
  end
257
+
258
+ def first_token_index(range_or_node)
259
+ begin_pos = source_range(range_or_node).begin_pos
260
+ sorted_tokens.bsearch_index { |token| token.begin_pos >= begin_pos }
261
+ end
262
+
263
+ def last_token_index(range_or_node)
264
+ end_pos = source_range(range_or_node).end_pos
265
+ sorted_tokens.bsearch_index { |token| token.end_pos >= end_pos }
266
+ end
267
+
268
+ # The tokens list is always sorted by token position, except for cases when heredoc
269
+ # is passed as a method argument. In this case tokens are interleaved by
270
+ # heredoc contents' tokens.
271
+ def sorted_tokens
272
+ # Use stable sort.
273
+ @sorted_tokens ||= tokens.sort_by.with_index { |token, i| [token.begin_pos, i] }
274
+ end
275
+
276
+ def source_range(range_or_node)
277
+ if range_or_node.respond_to?(:source_range)
278
+ range_or_node.source_range
279
+ else
280
+ range_or_node
281
+ end
282
+ end
243
283
  end
244
284
  end
245
285
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # ...
5
+ module AST
6
+ # Responsible for compatibility with main gem
7
+ # @api private
8
+ module RuboCopCompatibility
9
+ INCOMPATIBLE_COPS = {
10
+ '0.89.0' => 'Layout/LineLength',
11
+ '0.92.0' => 'Style/MixinUsage'
12
+ }.freeze
13
+ def rubocop_loaded
14
+ loaded = Gem::Version.new(RuboCop::Version::STRING)
15
+ incompatible = INCOMPATIBLE_COPS.select do |k, _v|
16
+ loaded < Gem::Version.new(k)
17
+ end.values
18
+ return if incompatible.empty?
19
+
20
+ warn <<~WARNING
21
+ *** WARNING – Incompatible versions of `rubocop` and `rubocop-ast`
22
+ You may encounter issues with the following \
23
+ Cop#{'s' if incompatible.size > 1}: #{incompatible.join(', ')}
24
+ Please upgrade rubocop to at least v#{INCOMPATIBLE_COPS.keys.last}
25
+ WARNING
26
+ end
27
+ end
28
+
29
+ extend RuboCopCompatibility
30
+ end
31
+ end
@@ -28,7 +28,7 @@ module RuboCop
28
28
  arg_expr pin match_rest if_guard unless_guard
29
29
  match_with_trailing_comma].freeze
30
30
  MANY_CHILD_NODES = %i[dstr dsym xstr regexp array hash pair
31
- mlhs masgn or_asgn and_asgn
31
+ mlhs masgn or_asgn and_asgn rasgn mrasgn
32
32
  undef alias args super yield or and
33
33
  while_post until_post iflipflop eflipflop
34
34
  match_with_lvasgn begin kwbegin return
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module AST
5
5
  module Version
6
- STRING = '0.3.0'
6
+ STRING = '0.5.1'
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: 0.3.0
4
+ version: 0.5.1
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: 2020-08-02 00:00:00.000000000 Z
13
+ date: 2020-09-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parser
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 2.7.1.4
21
+ version: 2.7.1.5
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 2.7.1.4
28
+ version: 2.7.1.5
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: bundler
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -60,6 +60,7 @@ files:
60
60
  - lib/rubocop/ast.rb
61
61
  - lib/rubocop/ast/builder.rb
62
62
  - lib/rubocop/ast/ext/range.rb
63
+ - lib/rubocop/ast/ext/set.rb
63
64
  - lib/rubocop/ast/node.rb
64
65
  - lib/rubocop/ast/node/alias_node.rb
65
66
  - lib/rubocop/ast/node/and_node.rb
@@ -70,6 +71,7 @@ files:
70
71
  - lib/rubocop/ast/node/case_match_node.rb
71
72
  - lib/rubocop/ast/node/case_node.rb
72
73
  - lib/rubocop/ast/node/class_node.rb
74
+ - lib/rubocop/ast/node/const_node.rb
73
75
  - lib/rubocop/ast/node/def_node.rb
74
76
  - lib/rubocop/ast/node/defined_node.rb
75
77
  - lib/rubocop/ast/node/ensure_node.rb
@@ -101,6 +103,7 @@ files:
101
103
  - lib/rubocop/ast/node/range_node.rb
102
104
  - lib/rubocop/ast/node/regexp_node.rb
103
105
  - lib/rubocop/ast/node/resbody_node.rb
106
+ - lib/rubocop/ast/node/rescue_node.rb
104
107
  - lib/rubocop/ast/node/return_node.rb
105
108
  - lib/rubocop/ast/node/self_class_node.rb
106
109
  - lib/rubocop/ast/node/send_node.rb
@@ -113,6 +116,7 @@ files:
113
116
  - lib/rubocop/ast/node/yield_node.rb
114
117
  - lib/rubocop/ast/node_pattern.rb
115
118
  - lib/rubocop/ast/processed_source.rb
119
+ - lib/rubocop/ast/rubocop_compatibility.rb
116
120
  - lib/rubocop/ast/sexp.rb
117
121
  - lib/rubocop/ast/token.rb
118
122
  - lib/rubocop/ast/traversal.rb