function bitwiseOps() {
/**
* @warning maybe && is intended?
* @fix $x && $y
* @type bool $x
* @type bool $y
*/
$x & $y;
}
Type filters
Slide 54
Slide 54 text
T T typed expression
object Arbitrary object type
T[] Array of T-typed elements
!T Any type except T
!(A|B) Any type except A and B
?T Same as (T|null)
Type matching examples
function match(Node $pat, Node $n)
$pat is a compiled pattern
$n is a node being matched
Matching AST
Slide 63
Slide 63 text
● Both $pat and $n are traversed
● Non-meta nodes are compared normally
● $pat meta nodes are separate cases
● Named matches are collected (capture)
Algorithm
Slide 64
Slide 64 text
● $x is a simple “match any” named match
● $_ is a “match any” unnamed match
● ${"str"} matches string literals
● ${"str:x"} is a capturing form of ${"str"}
● ${"*"} matches zero or more nodes
Valid PHP Syntax!
Meta node examples
Slide 65
Slide 65 text
$_ = ${"str"}
matches
$foo->x = "abc";
$x = '';
Slide 66
Slide 66 text
$_ = ${"str"}
rejects
$foo->x = f();
$x = $y;
Slide 67
Slide 67 text
f()
matches
f()
F()
Unless explicitly marked as case-sensitive
Slide 68
Slide 68 text
new T()
matches
new T()
new t()
Unless explicitly marked as case-sensitive
● Local: run rules only inside functions
● Root: run rules only inside global scope
● Universal: run rules everywhere
Extra registry layer: scopes
Slide 97
Slide 97 text
rule
PHP
file
...
Assign
rule
...
TernaryExpr
Global
scope
rule
...
Assign
rule
...
TernaryExpr
Local
scope
Slide 98
Slide 98 text
rule
PHP
file
...
Assign
rule
...
TernaryExpr
Global
scope
rule
...
Assign
rule
...
TernaryExpr
Local
scope
Scoped group
Slide 99
Slide 99 text
● Expression can’t contain a statement
● Some statements are top-level only
We don’t use this knowledge right now.
Extra registry layer: expr vs stmt
Slide 100
Slide 100 text
If any rule from a group matched, all other
rules inside the group are skipped for the
current node.
● Helps to avoid matching conflicts
● Improves performance
Group cutoff
● No need to re-compile NoVerify
Dynamic rules advantages
Slide 106
Slide 106 text
● No need to re-compile NoVerify
● Simple things are simple
Dynamic rules advantages
Slide 107
Slide 107 text
● No need to re-compile NoVerify
● Simple things are simple
● No Go coding required
Dynamic rules advantages
Slide 108
Slide 108 text
● No need to re-compile NoVerify
● Simple things are simple
● No Go coding required
● Rules are declarative
Dynamic rules advantages
Slide 109
Slide 109 text
● No need to re-compile NoVerify
● Simple things are simple
● No Go coding required
● Rules are declarative
● No need to know linter internals
Dynamic rules advantages
Slide 110
Slide 110 text
● Not very composable
● Too verbose for non-trivial cases
● Hard to get the autocompletion working
PHPDoc-based attributes
Slide 111
Slide 111 text
● Hard to express flow-based rules
● PHP syntax limitations
● Recursive block search is problematic
AST pattern limitations
Slide 112
Slide 112 text
Comparison with Ruleguard
Slide 113
Slide 113 text
No content
Slide 114
Slide 114 text
Rule group name
Slide 115
Slide 115 text
gogrep pattern
Slide 116
Slide 116 text
Type filter
Slide 117
Slide 117 text
Auto fix action
Slide 118
Slide 118 text
No content
Slide 119
Slide 119 text
Target language
go-ruleguard Go
NoVerify rules PHP
NoVerify vs Ruleguard
Slide 120
Slide 120 text
DSL core
go-ruleguard Fluent API DSL
NoVerify rules Top-level patterns + PHPDoc
NoVerify vs Ruleguard
Slide 121
Slide 121 text
Filtering mechanism
go-ruleguard Go expressions
NoVerify rules PHPDoc annotations
NoVerify vs Ruleguard
Slide 122
Slide 122 text
Type filters
go-ruleguard Type matching patterns
NoVerify rules Simple type expressions
NoVerify vs Ruleguard
Slide 123
Slide 123 text
● NoVerify - static analyzer (linter)
● phpgrep - structural PHP search
● phpgrep VS Code extension
● Dynamic rules example
● Dynamic rules for static analysis article
● Ruleguard - dynamic rules for Go
Links