Skip to content

Commit

Permalink
checkers: add ruleguard checker (#907)
Browse files Browse the repository at this point in the history
This is part of the ruleguard integration experiment.

Hopefully, we can get some feedback to improve the way it's integrated.

The simplest way to try it out:
	gocritic check -enable ruleguard -@ruleguard.rules <gorules> <target>

Where:
	<gorules> is a path to a Go rules file
	<target> is a linting target

An example gorules file can be found here:
	https://github.com/quasilyte/go-ruleguard/blob/master/rules.go

Visit https://github.com/quasilyte/go-ruleguard for more info on the ruleguard.

Updates #873
Updates #869
Updates #837
Updates #836
Updates #831

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>
  • Loading branch information
quasilyte committed Mar 18, 2020
1 parent 0d5eff4 commit 8c5f841
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 0 deletions.
95 changes: 95 additions & 0 deletions checkers/ruleguard_checker.go
@@ -0,0 +1,95 @@
package checkers

import (
"bytes"
"go/ast"
"go/token"
"io/ioutil"
"log"

"github.com/go-lintpack/lintpack"
"github.com/quasilyte/go-ruleguard/ruleguard"
)

func init() {
var info lintpack.CheckerInfo
info.Name = "ruleguard"
info.Tags = []string{"style", "experimental"}
info.Params = lintpack.CheckerParams{
"rules": {
Value: "",
Usage: "path to a gorules file",
},
}
info.Summary = "Runs user-defined rules using ruleguard linter"
info.Details = "Reads a rules file and turns them into go-critic checkers."
info.Before = `N/A`
info.After = `N/A`
info.Note = "See https://github.com/quasilyte/go-ruleguard."

collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
return newRuleguardChecker(&info, ctx)
})
}

func newRuleguardChecker(info *lintpack.CheckerInfo, ctx *lintpack.CheckerContext) *ruleguardChecker {
c := &ruleguardChecker{ctx: ctx}
rulesFilename := info.Params.String("rules")
if rulesFilename == "" {
return c
}

// TODO(quasilyte): handle initialization errors better when we make
// a transition to the go/analysis framework.
//
// For now, we log error messages and return a ruleguard checker
// with an empty rules set.

data, err := ioutil.ReadFile(rulesFilename)
if err != nil {
log.Printf("ruleguard init error: %+v", err)
return c
}

fset := token.NewFileSet()
rset, err := ruleguard.ParseRules(rulesFilename, fset, bytes.NewReader(data))
if err != nil {
log.Printf("ruleguard init error: %+v", err)
return c
}

c.rset = rset
return c
}

type ruleguardChecker struct {
ctx *lintpack.CheckerContext

rset *ruleguard.GoRuleSet
}

func (c *ruleguardChecker) WalkFile(f *ast.File) {
if c.rset == nil {
return
}

ctx := &ruleguard.Context{
Pkg: c.ctx.Pkg,
Types: c.ctx.TypesInfo,
Sizes: c.ctx.SizesInfo,
Fset: c.ctx.FileSet,
Report: func(n ast.Node, msg string, _ *ruleguard.Suggestion) {
// TODO(quasilyte): investigate whether we should add a rule name as
// a message prefix here.
c.ctx.Warn(n, msg)
},
}

err := ruleguard.RunRules(ctx, f, c.rset)
if err != nil {
// Normally this should never happen, but since
// we don't have a better mechanism to report errors,
// emit a warning.
c.ctx.Warn(f, "execution error: %v", err)
}
}
10 changes: 10 additions & 0 deletions checkers/testdata/_integration/ruleguard/f1.go
@@ -0,0 +1,10 @@
package foo

import "fmt"

type myError error

func _() {
var s1, s2 string
var _ = fmt.Sprintf("%s%s", s1, s2)
}
3 changes: 3 additions & 0 deletions checkers/testdata/_integration/ruleguard/linttest.golden
@@ -0,0 +1,3 @@
exit status 1
./f1.go:5:1: ruleguard: error as an underlying type is probably a mistake
./f1.go:9:10: ruleguard: suggestion: s1+s2
1 change: 1 addition & 0 deletions checkers/testdata/_integration/ruleguard/linttest.params
@@ -0,0 +1 @@
check -@ruleguard.rules ./rules.go -enable ruleguard ./... | linttest.golden
15 changes: 15 additions & 0 deletions checkers/testdata/_integration/ruleguard/rules.go
@@ -0,0 +1,15 @@
// +build ignore

package gorules

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

func _(m fluent.Matcher) {
m.Match(`type $x error`).
Report(`error as an underlying type is probably a mistake`).
Suggest(`type $x struct { error }`)

m.Match(`fmt.Sprintf("%s%s", $a, $b)`).
Where(m["a"].Type.Is(`string`) && m["b"].Type.Is(`string`)).
Suggest(`$a+$b`)
}
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -14,5 +14,6 @@ require (
github.com/mattn/goveralls v0.0.2
github.com/pborman/uuid v1.2.0 // indirect
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd
)
6 changes: 6 additions & 0 deletions go.sum
Expand Up @@ -35,6 +35,12 @@ github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c h1:JoUA0uz9U0FVFq5p4LjEq4C0VgQ0El320s3Ms0V4eww=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quasilyte/go-ruleguard v0.1.1 h1:L+vAaUaPT/iI7p6vl1691zTC5EAAOZE+Fous1k6e9IE=
github.com/quasilyte/go-ruleguard v0.1.1/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318181856-dc8aae974065 h1:JViY6/0dUURSKOyIRZZo1wSn5fbQzB8Y4uSIrV8gIT0=
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318181856-dc8aae974065/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8 h1:DvnesvLtRPQOvaUbfXfh0tpMHg29by0H7F2U+QIkSu8=
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down

0 comments on commit 8c5f841

Please sign in to comment.