Ruleguard by example: Text filters

package gorules

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

// Normally, all matching is done on the AST and types level.
// But sometimes it's necessary (or just easier) to tream the
// submatches as text.

func printFmt(m dsl.Matcher) {
	// Here we scan a $s string for %s, %d and %v.
	m.Match(`fmt.Println($s, $*_)`,
		`fmt.Print($s, $*_)`).
		Where(m["s"].Text.Matches(`%[sdv]`)).
		Report("found formatting directive in non-formatting call")
}

func wrongErrChecked(m dsl.Matcher) {
	// Here we check for both types and names.
	// Note that we can use `==` and `!=` with Text.
	m.Match("if $*_, $err0 := $*_; $err1 != nil { $*_ }").
		Where(m["err0"].Text == "err" && m["err0"].Type.Is("error") &&
			m["err1"].Text != "err" && m["err1"].Type.Is("error")).
		Report("maybe wrong err in error check")
}
$ ruleguard -c 0 -rules rules.go main.go
main.go:8:2: found formatting directive in non-formatting call
8		fmt.Println("error: %s", msg)
main.go:9:2: found formatting directive in non-formatting call
9		fmt.Print("Hello, %s!", "ruleguard")
main.go:14:2: maybe wrong err in error check
14		if v, err := f(); err2 != nil {
main.go
package main

import "fmt"

func main() {
	var msg string

	fmt.Println("error: %s", msg)
	fmt.Print("Hello, %s!", "ruleguard")
	fmt.Println("no formatting directives")

	var err2 error

	if v, err := f(); err2 != nil {
		fmt.Println(v, err)
	}
	if v, err2 := f(); err2 != nil {
		fmt.Println(v, err2)
	}
	if v, err := f(); err != nil {
		fmt.Println(v, err)
	}
}

func f() (int, error) { return 0, nil }

Notes:

To index Next: Constexpr evaluation Edit this page