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
|