Ruleguard by example: Optional submatches

package gorules

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

// The special `*` modifier can be used to match 0 or more nodes.

func nilValReturn(m dsl.Matcher) {
	// $*_ is used to make init clause inside if statement optional,
	// so our pattern can match all if statements.
	m.Match(`if $*_; $x == nil { return $x }`).
		Report(`returned $x value is always nil`)
}

func fprintStdout(m dsl.Matcher) {
	// `*` can be used with a name other than "_".
	// This is especially useful for variadic functions matching.
	// The named $* submatch can be used in both Report() and Suggest() templates.
	m.Match(`fmt.Fprint(os.Stdout, $*args)`).
		Suggest(`fmt.Print($args)`)
}
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Fprint(os.Stdout, "Hello", "world!")
	foo()
}

func foo() error {
	err := os.Chdir("/example1")
	if err == nil { // No init clause
		return err
	}
	if err := os.Chdir("/example2"); err == nil {
		return err
	}
	if err == nil {
		return nil // Doesn't match
	}
	return nil
}

Notes: