File: traversal.rb

package info (click to toggle)
ruby-rubocop-ast 0.3.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 892 kB
  • sloc: ruby: 10,886; makefile: 4
file content (204 lines) | stat: -rw-r--r-- 6,145 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# frozen_string_literal: true

# rubocop:disable Metrics/ModuleLength
module RuboCop
  module AST
    # Provides methods for traversing an AST.
    # Does not transform an AST; for that, use Parser::AST::Processor.
    # Override methods to perform custom processing. Remember to call `super`
    # if you want to recursively process descendant nodes.
    module Traversal
      def walk(node)
        return if node.nil?

        send(:"on_#{node.type}", node)
        nil
      end

      NO_CHILD_NODES    = %i[true false nil int float complex
                             rational str sym regopt self lvar
                             ivar cvar gvar nth_ref back_ref cbase
                             arg restarg blockarg shadowarg
                             kwrestarg zsuper redo retry
                             forward_args forwarded_args
                             match_var match_nil_pattern empty_else
                             forward_arg lambda procarg0 __ENCODING__].freeze
      ONE_CHILD_NODE    = %i[splat kwsplat block_pass not break next
                             preexe postexe match_current_line defined?
                             arg_expr pin match_rest if_guard unless_guard
                             match_with_trailing_comma].freeze
      MANY_CHILD_NODES  = %i[dstr dsym xstr regexp array hash pair
                             mlhs masgn or_asgn and_asgn
                             undef alias args super yield or and
                             while_post until_post iflipflop eflipflop
                             match_with_lvasgn begin kwbegin return
                             in_match match_alt
                             match_as array_pattern array_pattern_with_tail
                             hash_pattern const_pattern find_pattern
                             index indexasgn].freeze
      SECOND_CHILD_ONLY = %i[lvasgn ivasgn cvasgn gvasgn optarg kwarg
                             kwoptarg].freeze

      NO_CHILD_NODES.each do |type|
        module_eval("def on_#{type}(node); end", __FILE__, __LINE__)
      end

      ONE_CHILD_NODE.each do |type|
        module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
          def on_#{type}(node)
            if (child = node.children[0])
              send(:"on_\#{child.type}", child)
            end
          end
        RUBY
      end

      MANY_CHILD_NODES.each do |type|
        module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
          def on_#{type}(node)
            node.children.each { |child| send(:"on_\#{child.type}", child) }
            nil
          end
        RUBY
      end

      SECOND_CHILD_ONLY.each do |type|
        # Guard clause is for nodes nested within mlhs
        module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
          def on_#{type}(node)
            if (child = node.children[1])
              send(:"on_\#{child.type}", child)
            end
          end
        RUBY
      end

      def on_const(node)
        return unless (child = node.children[0])

        send(:"on_#{child.type}", child)
      end

      def on_casgn(node)
        children = node.children
        if (child = children[0]) # always const???
          send(:"on_#{child.type}", child)
        end
        return unless (child = children[2])

        send(:"on_#{child.type}", child)
      end

      def on_class(node)
        children = node.children
        child = children[0] # always const???
        send(:"on_#{child.type}", child)
        if (child = children[1])
          send(:"on_#{child.type}", child)
        end
        return unless (child = children[2])

        send(:"on_#{child.type}", child)
      end

      def on_def(node)
        children = node.children
        on_args(children[1])
        return unless (child = children[2])

        send(:"on_#{child.type}", child)
      end

      def on_send(node)
        node.children.each_with_index do |child, i|
          next if i == 1

          send(:"on_#{child.type}", child) if child
        end
        nil
      end

      alias on_csend on_send

      def on_op_asgn(node)
        children = node.children
        child = children[0]
        send(:"on_#{child.type}", child)
        child = children[2]
        send(:"on_#{child.type}", child)
      end

      def on_defs(node)
        children = node.children
        child = children[0]
        send(:"on_#{child.type}", child)
        on_args(children[2])
        return unless (child = children[3])

        send(:"on_#{child.type}", child)
      end

      def on_if(node)
        children = node.children
        child = children[0]
        send(:"on_#{child.type}", child)
        if (child = children[1])
          send(:"on_#{child.type}", child)
        end
        return unless (child = children[2])

        send(:"on_#{child.type}", child)
      end

      def on_while(node)
        children = node.children
        child = children[0]
        send(:"on_#{child.type}", child)
        return unless (child = children[1])

        send(:"on_#{child.type}", child)
      end

      alias on_until  on_while
      alias on_module on_while
      alias on_sclass on_while

      def on_block(node)
        children = node.children
        child = children[0]
        send(:"on_#{child.type}", child) # can be send, zsuper...
        on_args(children[1])
        return unless (child = children[2])

        send(:"on_#{child.type}", child)
      end

      def on_case(node)
        node.children.each do |child|
          send(:"on_#{child.type}", child) if child
        end
        nil
      end

      alias on_rescue     on_case
      alias on_resbody    on_case
      alias on_ensure     on_case
      alias on_for        on_case
      alias on_when       on_case
      alias on_case_match on_case
      alias on_in_pattern on_case
      alias on_irange     on_case
      alias on_erange     on_case

      def on_numblock(node)
        children = node.children
        child = children[0]
        send(:"on_#{child.type}", child)
        return unless (child = children[2])

        send(:"on_#{child.type}", child)
      end
    end
  end
end
# rubocop:enable Metrics/ModuleLength