The behaviour implemented by a lint rule.
A rule declares its diagnostic code, its default severity and a description, and implements one or both callbacks:
visit/3is invoked for every node of every statement during the traversal performed byTptp.Lint. Local conditions belong here: a role outside the permitted set, a$-word outside the vocabulary.review/2runs after the traversal, against the symbol table it produced. Conditions requiring more than one statement belong here: an undeclared symbol, a duplicate name, an absent inference parent.
Single traversal
Tptp.Lint traverses once and offers each node to every enabled rule, so the
cost of an additional rule is a function call rather than a further pass. A rule
per traversal would require eight traversals of a tree that does not fit in
cache.
It follows that visit/3 must be inexpensive and must not itself traverse. A
rule requiring a subtree is either asking for something the node determines, or
belongs in review/2 where the table is available.
Severity
severity/0 is the rule's default, which the caller may override per code. A
rule that applies to conforming library files must not report an error; a corpus
test enforces this. :info is appropriate where the finding is a property of the
file rather than a defect in it.
Summary
Callbacks
The diagnostic code this rule raises, "TPTP0401" and the like.
A one-line description, shown when a caller lists the available rules.
Look at the whole unit once the traversal is done.
What the rule thinks its findings are worth, before any caller override.
Look at one node. Called for every node of every statement, so keep it cheap.
Callbacks
@callback code() :: binary()
The diagnostic code this rule raises, "TPTP0401" and the like.
@callback describe() :: binary()
A one-line description, shown when a caller lists the available rules.
@callback review(Tptp.Lint.Table.t(), Tptp.Lint.Context.t()) :: [Tptp.Diagnostic.t()]
Look at the whole unit once the traversal is done.
@callback severity() :: Tptp.Diagnostic.severity()
What the rule thinks its findings are worth, before any caller override.
@callback visit(Tptp.Node.t(), Tptp.Lint.Context.t(), term()) :: [Tptp.Diagnostic.t()]
Look at one node. Called for every node of every statement, so keep it cheap.