golangci / golangci-lint

Fast linters runner for Go
https://golangci-lint.run
GNU General Public License v3.0
15.7k stars 1.39k forks source link

Linter request: go-ruleguard #912

Closed benjaminjkraft closed 4 years ago

benjaminjkraft commented 4 years ago

Ruleguard linter is a rules language for writing linters, based on gogrep. It looks very useful! But to make it maximally useful to us, we'd love to see it as a golangci-lint linter. (The idea would presumably be in your .golangci.yml config you specify the rules-file.) This could also be a nice lighter-weight complement to the fully customizable plugin-based linters from #473/#841 (cc @dbraley).

quasilyte commented 4 years ago

I can help if there will be any kinds of intergration issues.

Eun commented 4 years ago

Is anyone working on this? @quasilyte or @tpounds? Would be nice to get some status.

quasilyte commented 4 years ago

I think we need to get maintainers approval before working on this.

quasilyte commented 4 years ago

Meanwhile, go-critic may have ruleguard integrated pretty soon: https://github.com/go-critic/go-critic/pull/907

When golangci-lint updates the go-critic version it will be possible to use ruleguard through it.

tooolbox commented 4 years ago

I just tried to use ruleguard in golangci-lint via go-critic and found it's not in the list :(

Can we update?

EDIT: I'll do a PR.

tooolbox commented 4 years ago

Wow, new version with ruleguard was released 3 hours ago. 🎉 This ticket can be closed.

iwankgb commented 4 years ago

It was release that was long overdue ;)

tooolbox commented 4 years ago

I am curious if anyone has actually tried this and used it successfully. Setting up a rules.go file and trying to use ruleguard via golang-ci was extremely hit-or-miss for me yesterday to the point where I abandoned the attempt.

For example, at first I couldn't seem to get it to do anything, and then I put a really basic err != nil pattern in the matcher and it ran, and then I couldn't get it to stop even by commenting out the matcher. Obviously this is not necessarily a golang-ci problem, it could be ruleguard, but the problem is complicated by the fact that it's a few layers in and I have to try to understand where on the stack it's caching and/or borking.

quasilyte commented 4 years ago

@tooolbox, I'm sorry if the experience was frustrating. Let's try to fix it.

I couldn't get it to stop even by commenting out the matcher.

As you said, you may need to clean the golangci cache when updating the rules file:

golangci-lint cache clean

(It may be easier to debug the rules via gocritic or ruleguard itself if you don't want extra layers. But we'll stick to golangci-lint in this comment.)

Let's try to make ruleguard work, step-by-step.

  1. Make sure you have the latest golangci-lint. You need ruleguard checker to be included into the distribution.

  2. Prepare a test directory:

mkdir ruleguard_test
cd ruleguard_test
  1. Create a rules.go file in that test directory:
    
    // +build ignore

package gorules

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

func _(m fluent.Matcher) { m.Match(!($x != $y)).Report(can rewrite as $x == $y) }


3. Now create a Go file that we're going to check with our rule:

```go
// file example.go
package example

// Foo is our example function.
func Foo(xs, ys []int) bool {
    return !(xs[0] != ys[0])
}
  1. The next thing we need is .golangci.yml in that directory:
    linters:
    enable:
    - gocritic
    linters-settings:
    gocritic:
    enabled-checks:
      - ruleguard
    settings:
      ruleguard:
        rules: "rules.go"

Note that:

Also, keep in mind that you won't get any warnings if rules file is not found.

  1. Run golangci-lint on example.go:
$ golangci-lint run example.go 
example.go:5:9: ruleguard: can rewrite as xs[0] == ys[0] (gocritic)
    return !(xs[0] != ys[0])
           ^

Success!

I hope it helps. If you have more questions, please open an issue at gorcitic project.

If performance issues remain, please provide more info, preferably in form of an GitHub issue (both ruleguard and go-critic issue trackers can be used).


To see more rules examples, see rules.go.

More info on ruleguard: https://quasilyte.dev/blog/post/ruleguard/

tooolbox commented 4 years ago

Thanks @quasilyte for the detailed example, that's really helpful. I'll give another shot at it soon. The cache was the main thing I couldn't figure out, it's good to know that's a golang-ci thing and thanks for showing how to clean it.