
Linter Go baseado em análise que executa regras carregadas dinamicamente.
Você escreve as regras, ruleguard verifica se elas estão satisfeitas.
ruleguard tem algumas semelhanças com o GitHub CodeQL, mas é dedicado apenas a ir.
Características:
Também pode ser facilmente incorporado a outros analisadores estáticos. Go-crítico pode ser usado como exemplo.
É aconselhável que você obtenha um binário da versão mais recente {Linux/AMD64, Linux/Arm64, Darwin/AMD64, Darwin/Arm64, Windows/AMD64, Windows/Arm64}.
Se você deseja instalar o regulamento da fonte, é tão simples quanto:
# Installs a `ruleguard` binary under your `$(go env GOPATH)/bin`
$ go install -v github.com/quasilyte/go-ruleguard/cmd/ruleguard@latest
# Get the DSL package (needed to execute the ruleguard files)
$ go get -v -u github.com/quasilyte/go-ruleguard/dsl@latestSe dentro de um módulo Go, o pacote
dslserá instalado para o módulo atual, caso contrário, ele instalar o pacote no $ gopath e estará disponível globalmente.
Se $GOPATH/bin estiver no seu sistema $PATH , o comando ruleguard deve estar disponível depois disso:
$ ruleguard -help
ruleguard: execute dynamic gogrep-based rules
Usage: ruleguard [-flag] [package]
Flags:
-rules string
comma-separated list of ruleguard file paths
-e string
execute a single rule from a given string
-fix
apply all suggested fixes
-c int
display offending line with this many lines of context (default -1)
-json
emit JSON output Crie um arquivo de rules.go .
//go:build ruleguard
// +build ruleguard
package gorules
import "github.com/quasilyte/go-ruleguard/dsl"
func dupSubExpr ( m dsl. Matcher ) {
m . Match ( `$x || $x` ,
`$x && $x` ,
`$x | $x` ,
`$x & $x` ).
Where ( m [ "x" ]. Pure ).
Report ( `suspicious identical LHS and RHS` )
}
func boolExprSimplify ( m dsl. Matcher ) {
m . Match ( `!($x != $y)` ). Suggest ( `$x == $y` )
m . Match ( `!($x == $y)` ). Suggest ( `$x != $y` )
}
func exposedMutex ( m dsl. Matcher ) {
isExported := func ( v dsl. Var ) bool {
return v . Text . Matches ( `^p{Lu}` )
}
m . Match ( `type $name struct { $*_; sync.Mutex; $*_ }` ).
Where ( isExported ( m [ "name" ])).
Report ( "do not embed sync.Mutex" )
m . Match ( `type $name struct { $*_; sync.RWMutex; $*_ }` ).
Where ( isExported ( m [ "name" ])).
Report ( "do not embed sync.RWMutex" )
} Crie um example.go de teste.
package main
import "sync"
type EmbedsMutex struct {
key int
sync. Mutex
}
func main () {
var v1 , v2 int
println ( ! ( v1 != v2 ))
println ( ! ( v1 == v2 ))
if v1 == 0 && v1 == 0 {
println ( "hello, world!" )
}
} Execute ruleguard nesse arquivo de destino:
$ ruleguard -rules rules.go -fix example.go
example.go:5:1: exposedMutex: do not embed sync.Mutex (rules.go:24)
example.go:12:10: boolExprSimplify: suggestion: v1 == v2 (rules.go:15)
example.go:13:10: boolExprSimplify: suggestion: v1 ! = v2 (rules.go:16)
example.go:14:5: dupSubExpr: suspicious identical LHS and RHS (rules.go:7) Como executamos ruleguard com o argumento -fix , ambas as alterações sugeridas são aplicadas ao example.go .
Há também um modo -e que é útil durante a depuração de padrões:
$ ruleguard -e ' m.Match(`!($x != $y)`) ' example.go
example.go:12:10: ! (v1 ! = v2) Ele insere automaticamente Report("$$") no padrão especificado.
Você pode usar o sinalizador -debug-group <name> para ver explicações sobre por que algumas regras rejeitaram a correspondência (por exemplo, que a condição Where() falhou).
A regra -e gerada terá nome e , para que possa ser depurado também.
Primeiro, ele analisa os arquivos do RuleGuard (por exemplo, rules.go ) durante o início para carregar o conjunto de regras.
As regras carregadas são usadas para verificar os alvos especificados (arquivos Go, pacotes).
O arquivo rules.go é escrito em termos da API dsl . Os arquivos RuleGuard contêm um conjunto de funções que servem como um grupo de regras. Cada função aceita um único argumento dsl.Matcher que é usado para definir e configurar regras dentro do grupo.
Uma definição de regra sempre começa com Match(patterns...) Chamada e termina com a chamada do método Report(message) .
Pode haver chamadas adicionais entre esses dois. Por exemplo, uma chamada Where(cond) aplica restrições a uma correspondência para decidir se é aceita ou rejeitada. Portanto, mesmo que haja uma correspondência para um padrão, ele não produzirá uma mensagem de relatório, a menos que satisfaz uma condição Where() .
Para que o RuleGuard trabalhe, o pacote dsl deve estar disponível em tempo de execução . Se não for, você verá um erro como:
$ ruleguard -rules rules.go .
ruleguard: load rules: parse rules file: typechecker error: rules.go:6:8: could not import github.com/quasilyte/go-ruleguard/dsl (can't find import: "github.com/quasilyte/go-ruleguard/dsl")
Isso é corrigido adicionando o pacote DSL ao módulo:
$ ruleguard-test go get github.com/quasilyte/go-ruleguard/dsl
go: downloading github.com/quasilyte/go-ruleguard v0.3.18
go: downloading github.com/quasilyte/go-ruleguard/dsl v0.3.21
go: added github.com/quasilyte/go-ruleguard/dsl v0.3.21
$ ruleguard-test ruleguard -rules rules.go .
.../test.go:6:5: boolExprSimplify: suggestion: 1 == 0 (rules.go:9)
Se você acompanhou o uso anterior de usar uma restrição de construção no arquivo regras.go, como este:
$ ruleguard-test head -4 rules.go
//go:build ignore
// +build ignore
package gorules
Você vai notar que o arquivo go.mod lista o DSL como uma dependência indireta:
$ grep dsl go.mod
require github.com/quasilyte/go-ruleguard/dsl v0.3.21 // indirect
Se você correr, go mod tidy agora, você notará que o pacote DSL desaparece do arquivo go.mod :
$ go mod tidy
$ grep dsl go.mod
$
Isso ocorre porque go mod tidy se comporta como se todas as restrições de construção estivessem em vigor, com exceção de ignore . Isso está documentado no site Go.
Isso é corrigido usando uma restrição de construção diferente, como ruleguard ou rules .
NOTA: Incorporar as regras go-critic e go-perfguard usando o recurso de pré-compilação de IR.