2018-05-03 15:57:47 +00:00
|
|
|
require "./base_visitor"
|
|
|
|
|
|
|
|
module Ameba::AST
|
|
|
|
# List of nodes to be visited by Ameba's rules.
|
|
|
|
NODES = [
|
|
|
|
Alias,
|
2020-03-29 10:31:24 +00:00
|
|
|
IsA,
|
2018-05-03 15:57:47 +00:00
|
|
|
Assign,
|
|
|
|
Call,
|
2020-03-24 16:01:23 +00:00
|
|
|
Block,
|
2018-05-03 15:57:47 +00:00
|
|
|
Case,
|
|
|
|
ClassDef,
|
|
|
|
ClassVar,
|
|
|
|
Def,
|
|
|
|
EnumDef,
|
|
|
|
ExceptionHandler,
|
|
|
|
Expressions,
|
|
|
|
HashLiteral,
|
|
|
|
If,
|
|
|
|
InstanceVar,
|
|
|
|
LibDef,
|
|
|
|
ModuleDef,
|
|
|
|
NilLiteral,
|
|
|
|
StringInterpolation,
|
|
|
|
Unless,
|
|
|
|
Var,
|
|
|
|
When,
|
|
|
|
While,
|
2020-03-26 08:27:00 +00:00
|
|
|
Until,
|
2018-05-03 15:57:47 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
# An AST Visitor that traverses the source and allows all nodes
|
|
|
|
# to be inspected by rules.
|
|
|
|
#
|
|
|
|
# ```
|
|
|
|
# visitor = Ameba::AST::NodeVisitor.new(rule, source)
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
class NodeVisitor < BaseVisitor
|
2019-05-05 15:04:25 +00:00
|
|
|
@skip : Array(Crystal::ASTNode.class)?
|
|
|
|
|
|
|
|
def initialize(@rule, @source, skip = nil)
|
2021-01-17 17:12:10 +00:00
|
|
|
@skip = skip.try &.map(&.as(Crystal::ASTNode.class))
|
2019-05-05 15:04:25 +00:00
|
|
|
super @rule, @source
|
|
|
|
end
|
|
|
|
|
2018-05-03 15:57:47 +00:00
|
|
|
{% for name in NODES %}
|
|
|
|
# A visit callback for `Crystal::{{name}}` node.
|
|
|
|
# Returns true meaning that child nodes will be traversed as well.
|
|
|
|
def visit(node : Crystal::{{name}})
|
|
|
|
@rule.test @source, node
|
|
|
|
true
|
|
|
|
end
|
|
|
|
{% end %}
|
2019-05-05 15:04:25 +00:00
|
|
|
|
|
|
|
def visit(node)
|
2021-01-17 17:12:10 +00:00
|
|
|
return true unless skip = @skip
|
2019-05-05 15:04:25 +00:00
|
|
|
!skip.includes?(node.class)
|
|
|
|
end
|
2018-05-03 15:57:47 +00:00
|
|
|
end
|
|
|
|
end
|