rubocop-ast 0.0.1 → 0.3.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/lib/rubocop/ast.rb +10 -7
  4. data/lib/rubocop/ast/builder.rb +6 -1
  5. data/lib/rubocop/ast/ext/range.rb +28 -0
  6. data/lib/rubocop/ast/node.rb +41 -8
  7. data/lib/rubocop/ast/node/array_node.rb +2 -8
  8. data/lib/rubocop/ast/node/break_node.rb +1 -6
  9. data/lib/rubocop/ast/node/case_match_node.rb +3 -9
  10. data/lib/rubocop/ast/node/case_node.rb +13 -9
  11. data/lib/rubocop/ast/node/def_node.rb +5 -24
  12. data/lib/rubocop/ast/node/defined_node.rb +2 -0
  13. data/lib/rubocop/ast/node/float_node.rb +1 -0
  14. data/lib/rubocop/ast/node/forward_args_node.rb +15 -0
  15. data/lib/rubocop/ast/node/hash_node.rb +21 -8
  16. data/lib/rubocop/ast/node/if_node.rb +7 -14
  17. data/lib/rubocop/ast/node/index_node.rb +48 -0
  18. data/lib/rubocop/ast/node/indexasgn_node.rb +50 -0
  19. data/lib/rubocop/ast/node/int_node.rb +1 -0
  20. data/lib/rubocop/ast/node/lambda_node.rb +65 -0
  21. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +2 -8
  22. data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +99 -3
  23. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +56 -0
  24. data/lib/rubocop/ast/node/next_node.rb +12 -0
  25. data/lib/rubocop/ast/node/pair_node.rb +2 -2
  26. data/lib/rubocop/ast/node/regexp_node.rb +61 -2
  27. data/lib/rubocop/ast/node/return_node.rb +1 -13
  28. data/lib/rubocop/ast/node/send_node.rb +9 -2
  29. data/lib/rubocop/ast/node/super_node.rb +2 -0
  30. data/lib/rubocop/ast/node/when_node.rb +3 -9
  31. data/lib/rubocop/ast/node/yield_node.rb +2 -0
  32. data/lib/rubocop/ast/node_pattern.rb +952 -0
  33. data/lib/rubocop/ast/processed_source.rb +246 -0
  34. data/lib/rubocop/ast/token.rb +116 -0
  35. data/lib/rubocop/ast/traversal.rb +5 -3
  36. data/lib/rubocop/ast/version.rb +1 -1
  37. metadata +16 -13
  38. data/lib/rubocop/ast/node/retry_node.rb +0 -17
  39. data/lib/rubocop/error.rb +0 -34
  40. data/lib/rubocop/node_pattern.rb +0 -881
  41. data/lib/rubocop/processed_source.rb +0 -211
  42. data/lib/rubocop/token.rb +0 -114
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4c380d9edb3f0bdbdb8d7d9822b25cd96f9d23b7428bf8e8c56e4e19cf5628b
4
- data.tar.gz: 3568dc3fabb7c2d6b0575c9dc07341b4bb0b5daf6d65e284fdd524000a7de019
3
+ metadata.gz: 918c6017183db74497fc68166973904312bac7583f7752c2e55d1829574cb248
4
+ data.tar.gz: 1d04eb24fcbaec96b4bf0f17694018c31034fce4b3d81a9446ca98b3085e05a4
5
5
  SHA512:
6
- metadata.gz: 228b11a44b85a2bb3467afad8d28aadd65d7864ee7a5639773b007bcb2b9eef37ef2daff14d923730ec1b50cf3b7bfd96556ba3573e179615b9c7aba7d787480
7
- data.tar.gz: 061d70e99b00be1f84ab91d18cab96a97829e1ee5a62ef615013eae5994b72f67aa0b6101b64bf0715de6b863ebf60022849b1930ed7e306ff841d86bff39d60
6
+ metadata.gz: 54f6882ebf057c76a9c97212a62b295d03baea85ec7c44e606b412e74edce01b6c4bba93dfafa341756009a8bfa2352c4b2b3b22bdbf689dac08ddd9395a9aff
7
+ data.tar.gz: '08e60b802e83dba688bf1a31be417f9880b640194cf3b966849dd2c211de5a1f3797c8a37be3f2d3aa466d6c994b10c31277b0ed3dc708b12fe1c2f7a0f15552'
data/README.md CHANGED
@@ -1,11 +1,17 @@
1
1
  # RuboCop AST
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rubocop-ast.svg)](https://badge.fury.io/rb/rubocop-ast)
4
- [![CircleCI](https://circleci.com/gh/rubocop-hq/rubocop-ast.svg?style=svg)](https://circleci.com/gh/rubocop-hq/rubocop-ast)
4
+ [![CI](https://github.com/rubocop-hq/rubocop-ast/workflows/CI/badge.svg)](https://github.com/rubocop-hq/rubocop-ast/actions?query=workflow%3ACI)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/a29666e6373bc41bc0a9/test_coverage)](https://codeclimate.com/github/rubocop-hq/rubocop-ast/test_coverage)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/a29666e6373bc41bc0a9/maintainability)](https://codeclimate.com/github/rubocop-hq/rubocop-ast/maintainability)
5
7
 
6
8
  Contains the classes needed by [RuboCop](https://github.com/rubocop-hq/rubocop) to deal with Ruby's AST, in particular:
7
- * `RuboCop::AST::Node`
8
- * `RuboCop::NodePattern`
9
+
10
+ * `RuboCop::AST::Node` ([doc](docs/modules/ROOT/pages/node_types.adoc))
11
+ * `RuboCop::AST::NodePattern` ([doc](docs/modules/ROOT/pages/node_pattern.adoc))
12
+
13
+ This gem may be used independently from the main RuboCop gem. It was extracted from RuboCop in version 0.84 and its only
14
+ dependency is the [parser](https://github.com/whitequark/parser) gem, which `rubocop-ast` extends.
9
15
 
10
16
  ## Installation
11
17
 
@@ -23,7 +29,20 @@ gem 'rubocop-ast'
23
29
 
24
30
  ## Usage
25
31
 
26
- Refer to the documentation of `RuboCop::AST::Node` and [`RuboCop::NodePattern`](manual/node_pattern.md)
32
+ Refer to the documentation of [`RuboCop::AST::Node`](docs/modules/ROOT/pages/node_types.adoc) and [`RuboCop::AST::NodePattern`](docs/modules/ROOT/pages/node_pattern.adoc)
33
+
34
+ See the [docs site](https://docs.rubocop.org/rubocop-ast) for more details.
35
+
36
+ ### Parser compatibility switches
37
+
38
+ This gem, by default, uses most [legacy AST output from parser](https://github.com/whitequark/parser/#usage), except for `emit_forward_arg` which is set to `true`.
39
+
40
+ The main `RuboCop` gem uses these defaults (and is currently only compatible with these), but this gem can be used separately from `RuboCop` and is meant to be compatible with all settings. For example, to have `-> { ... }` emitted
41
+ as `LambdaNode` instead of `SendNode`:
42
+
43
+ ```ruby
44
+ RuboCop::AST::Builder.emit_lambda = true
45
+ ```
27
46
 
28
47
  ## Contributing
29
48
 
@@ -2,10 +2,10 @@
2
2
 
3
3
  require 'parser'
4
4
  require 'forwardable'
5
+ require 'set'
5
6
 
6
- require_relative 'error'
7
- require_relative 'node_pattern'
8
-
7
+ require_relative 'ast/ext/range'
8
+ require_relative 'ast/node_pattern'
9
9
  require_relative 'ast/sexp'
10
10
  require_relative 'ast/node'
11
11
  require_relative 'ast/node/mixin/method_identifier_predicates'
@@ -36,15 +36,18 @@ require_relative 'ast/node/forward_args_node'
36
36
  require_relative 'ast/node/float_node'
37
37
  require_relative 'ast/node/hash_node'
38
38
  require_relative 'ast/node/if_node'
39
+ require_relative 'ast/node/index_node'
40
+ require_relative 'ast/node/indexasgn_node'
39
41
  require_relative 'ast/node/int_node'
40
42
  require_relative 'ast/node/keyword_splat_node'
43
+ require_relative 'ast/node/lambda_node'
41
44
  require_relative 'ast/node/module_node'
45
+ require_relative 'ast/node/next_node'
42
46
  require_relative 'ast/node/or_node'
43
47
  require_relative 'ast/node/pair_node'
44
48
  require_relative 'ast/node/range_node'
45
49
  require_relative 'ast/node/regexp_node'
46
50
  require_relative 'ast/node/resbody_node'
47
- require_relative 'ast/node/retry_node'
48
51
  require_relative 'ast/node/return_node'
49
52
  require_relative 'ast/node/self_class_node'
50
53
  require_relative 'ast/node/send_node'
@@ -56,7 +59,7 @@ require_relative 'ast/node/when_node'
56
59
  require_relative 'ast/node/while_node'
57
60
  require_relative 'ast/node/yield_node'
58
61
  require_relative 'ast/builder'
62
+ require_relative 'ast/processed_source'
63
+ require_relative 'ast/token'
59
64
  require_relative 'ast/traversal'
60
-
61
- require_relative 'token'
62
- require_relative 'processed_source'
65
+ require_relative 'ast/version'
@@ -14,6 +14,8 @@ module RuboCop
14
14
  # parser = Parser::Ruby25.new(builder)
15
15
  # root_node = parser.parse(buffer)
16
16
  class Builder < Parser::Builders::Default
17
+ self.emit_forward_arg = true
18
+
17
19
  NODE_MAP = {
18
20
  and: AndNode,
19
21
  alias: AliasNode,
@@ -35,15 +37,18 @@ module RuboCop
35
37
  hash: HashNode,
36
38
  if: IfNode,
37
39
  int: IntNode,
40
+ index: IndexNode,
41
+ indexasgn: IndexasgnNode,
38
42
  irange: RangeNode,
39
43
  erange: RangeNode,
40
44
  kwsplat: KeywordSplatNode,
45
+ lambda: LambdaNode,
41
46
  module: ModuleNode,
47
+ next: NextNode,
42
48
  or: OrNode,
43
49
  pair: PairNode,
44
50
  regexp: RegexpNode,
45
51
  resbody: ResbodyNode,
46
- retry: RetryNode,
47
52
  return: ReturnNode,
48
53
  csend: SendNode,
49
54
  send: SendNode,
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ module Ext
6
+ # Extensions to Parser::AST::Range
7
+ module Range
8
+ # @return [Range] the range of line numbers for the node
9
+ # If `exclude_end` is `true`, then the range will be exclusive.
10
+ #
11
+ # Assume that `node` corresponds to the following array literal:
12
+ #
13
+ # [
14
+ # :foo,
15
+ # :bar
16
+ # ]
17
+ #
18
+ # node.loc.begin.line_span # => 1..1
19
+ # node.loc.expression.line_span(exclude_end: true) # => 1...4
20
+ def line_span(exclude_end: false)
21
+ ::Range.new(first_line, last_line, exclude_end)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ ::Parser::Source::Range.include ::RuboCop::AST::Ext::Range
@@ -44,6 +44,8 @@ module RuboCop
44
44
 
45
45
  BASIC_CONDITIONALS = %i[if while until].freeze
46
46
  CONDITIONALS = [*BASIC_CONDITIONALS, :case].freeze
47
+ POST_CONDITION_LOOP_TYPES = %i[while_post until_post].freeze
48
+ LOOP_TYPES = (POST_CONDITION_LOOP_TYPES + %i[while until for]).freeze
47
49
  VARIABLES = %i[ivar gvar cvar lvar].freeze
48
50
  REFERENCES = %i[nth_ref back_ref].freeze
49
51
  KEYWORDS = %i[alias and break case class def defs defined?
@@ -53,6 +55,7 @@ module RuboCop
53
55
  yield].freeze
54
56
  OPERATOR_KEYWORDS = %i[and or].freeze
55
57
  SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].freeze
58
+ ARGUMENT_TYPES = %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg].freeze
56
59
 
57
60
  # @see https://www.rubydoc.info/gems/ast/AST/Node:initialize
58
61
  def initialize(type, children = [], properties = {})
@@ -310,8 +313,8 @@ module RuboCop
310
313
  def_node_matcher :defined_module0, <<~PATTERN
311
314
  {(class (const $_ $_) ...)
312
315
  (module (const $_ $_) ...)
313
- (casgn $_ $_ (send (const nil? {:Class :Module}) :new ...))
314
- (casgn $_ $_ (block (send (const nil? {:Class :Module}) :new ...) ...))}
316
+ (casgn $_ $_ (send #global_const?({:Class :Module}) :new ...))
317
+ (casgn $_ $_ (block (send #global_const?({:Class :Module}) :new ...) ...))}
315
318
  PATTERN
316
319
 
317
320
  private :defined_module0
@@ -425,6 +428,15 @@ module RuboCop
425
428
  CONDITIONALS.include?(type)
426
429
  end
427
430
 
431
+ def post_condition_loop?
432
+ POST_CONDITION_LOOP_TYPES.include?(type)
433
+ end
434
+
435
+ # Note: `loop { }` is a normal method call and thus not a loop keyword.
436
+ def loop_keyword?
437
+ LOOP_TYPES.include?(type)
438
+ end
439
+
428
440
  def keyword?
429
441
  return true if special_keyword? || send_type? && prefix_not?
430
442
  return false unless KEYWORDS.include?(type)
@@ -456,6 +468,10 @@ module RuboCop
456
468
  parent&.send_type? && parent.arguments.include?(self)
457
469
  end
458
470
 
471
+ def argument_type?
472
+ ARGUMENT_TYPES.include?(type)
473
+ end
474
+
459
475
  def boolean_type?
460
476
  true_type? || false_type?
461
477
  end
@@ -480,16 +496,33 @@ module RuboCop
480
496
 
481
497
  def_node_matcher :proc?, <<~PATTERN
482
498
  {(block (send nil? :proc) ...)
483
- (block (send (const nil? :Proc) :new) ...)
484
- (send (const nil? :Proc) :new)}
499
+ (block (send #global_const?(:Proc) :new) ...)
500
+ (send #global_const?(:Proc) :new)}
485
501
  PATTERN
486
502
 
487
503
  def_node_matcher :lambda?, '({block numblock} (send nil? :lambda) ...)'
488
504
  def_node_matcher :lambda_or_proc?, '{lambda? proc?}'
489
505
 
506
+ def_node_matcher :global_const?, '(const {nil? cbase} %1)'
507
+
490
508
  def_node_matcher :class_constructor?, <<~PATTERN
491
- { (send (const nil? {:Class :Module}) :new ...)
492
- (block (send (const nil? {:Class :Module}) :new ...) ...)}
509
+ { (send #global_const?({:Class :Module}) :new ...)
510
+ (block (send #global_const?({:Class :Module}) :new ...) ...)}
511
+ PATTERN
512
+
513
+ def_node_matcher :struct_constructor?, <<~PATTERN
514
+ (block (send #global_const?(:Struct) :new ...) _ $_)
515
+ PATTERN
516
+
517
+ def_node_matcher :class_definition?, <<~PATTERN
518
+ {(class _ _ $_)
519
+ (sclass _ $_)
520
+ (block (send #global_const?({:Struct :Class}) :new ...) _ $_)}
521
+ PATTERN
522
+
523
+ def_node_matcher :module_definition?, <<~PATTERN
524
+ {(module _ $_)
525
+ (block (send #global_const?(:Module) :new ...) _ $_)}
493
526
  PATTERN
494
527
 
495
528
  # Some expressions are evaluated for their value, some for their side
@@ -500,7 +533,7 @@ module RuboCop
500
533
  # So, does the return value of this node matter? If we changed it to
501
534
  # `(...; nil)`, might that affect anything?
502
535
  #
503
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
536
+ # rubocop:disable Metrics/MethodLength
504
537
  def value_used?
505
538
  # Be conservative and return true if we're not sure.
506
539
  return false if parent.nil?
@@ -522,7 +555,7 @@ module RuboCop
522
555
  true
523
556
  end
524
557
  end
525
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
558
+ # rubocop:enable Metrics/MethodLength
526
559
 
527
560
  # Some expressions are evaluated for their value, some for their side
528
561
  # effects, and some for both.
@@ -14,15 +14,9 @@ module RuboCop
14
14
  # Returns an array of all value nodes in the `array` literal.
15
15
  #
16
16
  # @return [Array<Node>] an array of value nodes
17
- def values
18
- each_child_node.to_a
19
- end
17
+ alias values children
20
18
 
21
- # Calls the given block for all values in the `array` literal.
22
- #
23
- # @yieldparam [Node] node each node
24
- # @return [self] if a block is given
25
- # @return [Enumerator] if no block is given
19
+ # @deprecated Use `values.each` (a.k.a. `children.each`)
26
20
  def each_value(&block)
27
21
  return to_enum(__method__) unless block_given?
28
22
 
@@ -6,12 +6,7 @@ module RuboCop
6
6
  # plain node when the builder constructs the AST, making its methods
7
7
  # available to all `break` nodes within RuboCop.
8
8
  class BreakNode < Node
9
- include MethodDispatchNode
10
- include ParameterizedNode
11
-
12
- def arguments
13
- []
14
- end
9
+ include ParameterizedNode::WrappedArguments
15
10
  end
16
11
  end
17
12
  end
@@ -15,17 +15,11 @@ module RuboCop
15
15
  'case'
16
16
  end
17
17
 
18
- # Calls the given block for each `in_pattern` node in the `in` statement.
19
- # If no block is given, an `Enumerator` is returned.
20
- #
21
- # @return [self] if a block is given
22
- # @return [Enumerator] if no block is given
23
- def each_in_pattern
18
+ # @deprecated Use `in_pattern_branches.each`
19
+ def each_in_pattern(&block)
24
20
  return in_pattern_branches.to_enum(__method__) unless block_given?
25
21
 
26
- in_pattern_branches.each do |condition|
27
- yield condition
28
- end
22
+ in_pattern_branches.each(&block)
29
23
 
30
24
  self
31
25
  end
@@ -15,17 +15,11 @@ module RuboCop
15
15
  'case'
16
16
  end
17
17
 
18
- # Calls the given block for each `when` node in the `case` statement.
19
- # If no block is given, an `Enumerator` is returned.
20
- #
21
- # @return [self] if a block is given
22
- # @return [Enumerator] if no block is given
23
- def each_when
18
+ # @deprecated Use `when_branches.each`
19
+ def each_when(&block)
24
20
  return when_branches.to_enum(__method__) unless block_given?
25
21
 
26
- when_branches.each do |condition|
27
- yield condition
28
- end
22
+ when_branches.each(&block)
29
23
 
30
24
  self
31
25
  end
@@ -37,6 +31,16 @@ module RuboCop
37
31
  node_parts[1...-1]
38
32
  end
39
33
 
34
+ # Returns an array of all the when branches in the `case` statement.
35
+ #
36
+ # @return [Array<Node, nil>] an array of the bodies of the when branches
37
+ # and the else (if any). Note that these bodies could be nil.
38
+ def branches
39
+ bodies = when_branches.map(&:body)
40
+ bodies.push(else_branch) if else?
41
+ bodies
42
+ end
43
+
40
44
  # Returns the else branch of the `case` statement, if any.
41
45
  #
42
46
  # @return [Node] the else branch node of the `case` statement
@@ -24,21 +24,21 @@ module RuboCop
24
24
  #
25
25
  # @return [Boolean] whether the `def` node uses argument forwarding
26
26
  def argument_forwarding?
27
- arguments.any?(&:forward_args_type?)
27
+ arguments.any?(&:forward_args_type?) || arguments.any?(&:forward_arg_type?)
28
28
  end
29
29
 
30
30
  # The name of the defined method as a symbol.
31
31
  #
32
32
  # @return [Symbol] the name of the defined method
33
33
  def method_name
34
- node_parts[2]
34
+ children[-3]
35
35
  end
36
36
 
37
37
  # An array containing the arguments of the method definition.
38
38
  #
39
39
  # @return [Array<Node>] the arguments of the method definition
40
40
  def arguments
41
- node_parts[1]
41
+ children[-2]
42
42
  end
43
43
 
44
44
  # The body of the method definition.
@@ -49,33 +49,14 @@ module RuboCop
49
49
  #
50
50
  # @return [Node] the body of the method definition
51
51
  def body
52
- node_parts[0]
52
+ children[-1]
53
53
  end
54
54
 
55
55
  # The receiver of the method definition, if any.
56
56
  #
57
57
  # @return [Node, nil] the receiver of the method definition, or `nil`.
58
58
  def receiver
59
- node_parts[3]
60
- end
61
-
62
- # Custom destructuring method. This can be used to normalize
63
- # destructuring for different variations of the node.
64
- #
65
- # In this case, the `def` node destructures into:
66
- #
67
- # `method_name, arguments, body`
68
- #
69
- # while the `defs` node destructures into:
70
- #
71
- # `receiver, method_name, arguments, body`
72
- #
73
- # so we reverse the destructured array to get the optional receiver
74
- # at the end, where it can be discarded.
75
- #
76
- # @return [Array] the different parts of the `def` or `defs` node
77
- def node_parts
78
- to_a.reverse
59
+ children[-4]
79
60
  end
80
61
  end
81
62
  end
@@ -12,6 +12,8 @@ module RuboCop
12
12
  def node_parts
13
13
  [nil, :defined?, *to_a]
14
14
  end
15
+
16
+ alias arguments children
15
17
  end
16
18
  end
17
19
  end
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # node when the builder constructs the AST, making its methods available to
7
7
  # all `float` nodes within RuboCop.
8
8
  class FloatNode < Node
9
+ include BasicLiteralNode
9
10
  include NumericNode
10
11
  end
11
12
  end
@@ -5,6 +5,21 @@ module RuboCop
5
5
  # A node extension for `forward-args` nodes. This will be used in place
6
6
  # of a plain node when the builder constructs the AST, making its methods
7
7
  # available to all `forward-args` nodes within RuboCop.
8
+ #
9
+ # Not used with modern emitters:
10
+ #
11
+ # $ ruby-parse -e "def foo(...); end"
12
+ # (def :foo
13
+ # (args
14
+ # (forward-arg)) nil)
15
+ # $ ruby-parse --legacy -e "->(foo) { bar }"
16
+ # (def :foo
17
+ # (forward-args) nil)
18
+ #
19
+ # Note the extra 's' with legacy form.
20
+ #
21
+ # The main RuboCop runs in legacy mode; this node is only used
22
+ # if user `AST::Builder.modernize` or `AST::Builder.emit_lambda=true`
8
23
  class ForwardArgsNode < Node
9
24
  include CollectionNode
10
25