CodeQL-like analyzer for Go

go-ruleguard

Overview

analysis -based Go linter that runs dynamically loaded rules.

You write the rules, ruleguard checks whether they are satisfied.

ruleguard has some similarities with GitHub CodeQL , but only focuses on Go code queries.

Features:

  • Custom linting rules without re-compilation and Go plugins.
  • Diagnostics are written in a declarative way.
  • Quickfix actions support.
  • Powerful match filtering features, like expression type pattern matching .

ruleguard comes with rules.go file that can be used as a foundation to write your own rules file.

Quick start

To install ruleguard binary under your $(go env GOPATH)/bin :

$ go get -v -u github.com/quasilyte/go-ruleguard/...

If $GOPATH/bin is under your system $PATH , ruleguard command should be available after that.

$ ruleguard -help
ruleguard: execute dynamic gogrep-based rules

Usage: ruleguard [-flag] [package]

Flags:
  -rules string
    	path to a rules.go file
  -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

Create a test example.rules.go file:

// +build ignore

package gorules

import "github.com/quasilyte/go-ruleguard/dsl/fluent"

func _(m fluent.Matcher) {
	m.Match(`$x || $x`,
		`$x && $x`).
		Where(m["x"].Pure).
		Report(`suspicious identical LHS and RHS`)

	m.Match(`!($x != $y)`).Suggest(`$x == $y`)
	m.Match(`!($x == $y)`).Suggest(`$x != $y`)
}

Create a test example.go target file:

package main

func main() {
	var v1, v2 int
	println(!(v1 != v2))
	println(!(v1 == v2))
	if v1 == 0 && v1 == 0 {
		println("hello, world!")
	}
}

Run ruleguard on that target file:

$ ruleguard -rules example.rules.go -fix example.go
example.go:5:10: hint: suggested: v1 == v2
example.go:6:10: hint: suggested: v1 != v2
example.go:7:5: error: suspicious identical LHS and RHS

Since we ran ruleguard with -fix argument, both suggested changes are applied to example.go .

There is also a -e mode that is useful during pattern debugging:

$ ruleguard -e 'm.Match(`!($x != $y)`)' example.go
example.go:5:10: !(v1 != v2)

It automatically inserts Report("$$") into the specified pattern.

How does it work?

ruleguard parses gorules (e.g. rules.go ) during the start to load the rule set.

Loaded rules are then used to check the specified targets (Go files, packages).

The rules.go file itself is never compiled, nor executed.

A rules.go file, as interpreted by a dsl/fluent API, is a set of functions that serve as a rule groups. Every function accepts a single fluent.Matcher argument that is then used to define and configure rules inside the group.

A rule definition always starts from a Match(patterns...) method call and ends with a Report(message) method call.

There can be additional calls in between these two. For example, a Where(cond) call applies constraints to a match to decide whether its accepted or rejected. So even if there is a match for a pattern, it won't produce a report message unless it satisfies a Where() condition.

To learn more, check out the documentation and/or the source code.

Documentation

Extra references

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章