package gorules
import "github.com/quasilyte/go-ruleguard/dsl"
// When ruleguard inspects the program and tries to match your rules,
// it walks over the AST created from the target files source code.
// The AST consists of the nodes that are defined in "go/ast" package.
//
// These node types are not connected to the "expression types" directly,
// but they're useful when you want to assert the shape of the match.
func formatLiteral(m dsl.Matcher) {
// The following rule tries to find the formatting calls
// that use non-literal arguments for the formatting string.
// So, variables, named constants and everything else is a no-no.
m.Match(`fmt.Sprintf($format, $*_)`,
`fmt.Fprintf($_, $format, $*_)`,
`fmt.Printf($format, $*_)`).
Where(!m["format"].Node.Is(`BasicLit`)).
Report("non-literal formatting string is used")
}
package main
import "fmt"
func main() {
formatStringVar := "%d"
const formatStringConst = "%d"
_ = fmt.Sprintf(formatStringVar, 1)
_ = fmt.Sprintf(formatStringConst, 2)
_ = fmt.Sprintf("%s: %d", "the answer is", 42) // OK
fmt.Printf("%"+"d", -5)
fmt.Printf("%d", 10) // OK
}
Notes:
Is()
argument is a go/ast
type namem["$$"].Parent()
to add filters based on the AST context