/
redundant_control_expression_visitor.cr
60 lines (49 loc) · 1.75 KB
/
redundant_control_expression_visitor.cr
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
module Ameba::AST
# A class that utilizes a logic to traverse AST nodes and
# fire a source test callback if a redundant `Crystal::ControlExpression`
# is reached.
class RedundantControlExpressionVisitor
# A corresponding rule that uses this visitor.
getter rule : Rule::Base
# A source that needs to be traversed.
getter source : Source
# A node to run traversal on.
getter node : Crystal::ASTNode
def initialize(@rule, @source, @node)
traverse_node node
end
private def traverse_control_expression(node)
@rule.test(@source, node, self)
end
private def traverse_node(node)
case node
when Crystal::ControlExpression then traverse_control_expression node
when Crystal::Expressions then traverse_expressions node
when Crystal::If, Crystal::Unless then traverse_condition node
when Crystal::Case then traverse_case node
when Crystal::BinaryOp then traverse_binary_op node
when Crystal::ExceptionHandler then traverse_exception_handler node
end
end
private def traverse_expressions(node)
traverse_node node.expressions.last?
end
private def traverse_condition(node)
return if node.else.nil? || node.else.nop?
traverse_node(node.then)
traverse_node(node.else)
end
private def traverse_case(node)
node.whens.each { |when_node| traverse_node when_node.body }
traverse_node(node.else)
end
private def traverse_binary_op(node)
traverse_node(node.right)
end
private def traverse_exception_handler(node)
traverse_node node.body
traverse_node node.else
node.rescues.try &.each { |rescue_node| traverse_node rescue_node.body }
end
end
end