golangci / golangci-lint

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

Custom Linter vs --fix #1728

Open MeenaAlfons opened 3 years ago

MeenaAlfons commented 3 years ago

Thank you for creating the issue!

Please include the following information:

Version v1.33.0 of golangci-lint ```console $ golangci-lint --version golangci-lint has version v1.33.0 built from (unknown, mod sum: "h1:/o4OtOR3Idim4FHKBJXcy+6ZjNDm82gwK/v6+gWyH9U=") on (unknown) ```
Config file ```console $ cat .golangci.yml run: concurrency: 8 timeout: 5m deadline: 5m skip-dirs: - vendor skip-files: - ".*?_with_.*?_gen\\.go" - "mock_.*?_gen\\.go" linters: disable-all: true enable: # find all here: https://github.com/golangci/golangci-lint#enabled-by-default-linters # - unused # finds unused constants, variables, functions and types - deadcode # finds unused code # - godox # find TODO/FIXME messages - errcheck # finds unchecked errors - varcheck # finds unused global - ineffassign # Detects when assignments to existing variables are not used - unconvert # Remove unnecessary type conversions # - goconst # Finds repeated strings that could be replaced by a constant # - gocyclo # Computes and checks the cyclomatic complexity of functions - maligned # Tool to detect Go structs that would take less memory if their fields were sorted - prealloc # Finds slice declarations that could potentially be preallocated - govet # Vet examines Go source code and reports suspicious constructs - gosec # Inspects source code for security problems # - gosimple # Advocates simple code - lll # Max line length - depguard # Checks imports for packages not used - go-routine-recover issues: max-issues-per-linter: 3 max-same-issues: 3 fix: true linters-settings: lll: maxlength: 120 depguard: list-type: blacklist include-go-root: true packages: - github.com/pkg/errors - log - go.uber.org/zap - go.uber.org/zap/zapcore custom: go-routine-recover: path: /golangci-lint-plugins/go-routine-recover.so description: Linter to find go-routines without recovery original-url: my.private.domain/path/to/go-routine-recover ```
Go environment ```console $ go version && go env go version go1.15 darwin/amd64 GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/Users/username/Library/Caches/go-build" GOENV="/Users/username/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/username/.gvm/pkgsets/go1.15/global/pkg/mod" GONOPROXY="my.private.domain/*" GONOSUMDB="my.private.domain/*" GOOS="darwin" GOPATH="/Users/username/.gvm/pkgsets/go1.15/global" GOPRIVATE="my.private.domain/*" GOPROXY="https://proxy.golang.org,direct" GOROOT="/Users/username/.gvm/gos/go1.15" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/Users/username/.gvm/gos/go1.15/pkg/tool/darwin_amd64" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="/Users/path/to/project/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/wh/4mp4d6g92tl09bxq79bxk_cw0000gp/T/go-build761519529=/tmp/go-build -gno-record-gcc-switches -fno-common" ```
Verbose output of running ```console $ golangci-lint cache clean $ golangci-lint run -v INFO [config_reader] Used config file build/configs/lint-required.yml INFO Loaded ../../path/to/go-routine-recover.so: go-routine-recover INFO [lintersdb] Active 12 linters: [deadcode depguard errcheck go-routine-recover gosec govet ineffassign lll maligned prealloc unconvert varcheck] INFO [loader] Go packages loading at mode 575 (compiled_files|deps|name|exports_file|files|imports|types_sizes) took 1.234498455s INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 121.649298ms INFO [linters context/goanalysis] analyzers took 0s with no stages INFO [runner/max_same_issues] 16/19 issues with text "goroutinerecover: go-routine must contain a deferred call to r := recover()" were hidden, use --max-same-issues INFO [runner] Issues before processing: 5552, after processing: 3 INFO [runner] Processors filtering stat (out/in): cgo: 5552/5552, exclude-rules: 352/429, max_from_linter: 3/3, diff: 19/19, skip_files: 4055/5552, skip_dirs: 4055/4055, exclude: 429/429, uniq_by_line: 19/19, source_code: 3/3, path_prefixer: 3/3, filename_unadjuster: 5552/5552, autogenerated_exclude: 429/4055, nolint: 19/352, max_per_file_from_linter: 19/19, severity-rules: 3/3, sort_results: 3/3, path_prettifier: 5552/5552, identifier_marker: 429/429, max_same_issues: 3/19, path_shortener: 3/3 INFO [runner] processing took 80.277958ms with stages: nolint: 49.574238ms, path_prettifier: 12.55607ms, skip_files: 6.205368ms, identifier_marker: 3.48771ms, autogenerated_exclude: 3.461421ms, exclude-rules: 3.192881ms, skip_dirs: 887.802µs, cgo: 460.26µs, filename_unadjuster: 266.448µs, source_code: 142.412µs, max_same_issues: 29.346µs, uniq_by_line: 6.723µs, max_per_file_from_linter: 3.39µs, path_shortener: 1.356µs, max_from_linter: 1.282µs, diff: 330ns, exclude: 300ns, sort_results: 286ns, severity-rules: 212ns, path_prefixer: 123ns INFO [runner] linters took 247.044792ms with stages: goanalysis_metalinter: 166.628682ms INFO fixer took 0s with no stages path/to/file1.go:41:2: goroutinerecover: go-routine must contain a deferred call to r := recover() (go-routine-recover) go func() { ^ path/to/file2.go:755:2: goroutinerecover: go-routine must contain a deferred call to r := recover() (go-routine-recover) go func() { ^ path/to/file3.go:204:2: goroutinerecover: go-routine must contain a deferred call to r := recover() (go-routine-recover) go func() { ^ INFO File cache stats: 3 entries of total size 48.3KiB INFO Memory: 18 samples, avg is 72.6MB, max is 74.0MB INFO Execution took 1.629181407s ```

We created a custom linter that works great. Right now we are trying to add suggested fixes to this linter. There is no example of such a thing in the New Linter tutorial on the website. However, we found SuggestedFix in the documentation of golang.org/x/tools/go/analysis. We used it but we still can't see any fixes happening.

        pass.Report(analysis.Diagnostic{
            Pos:     node.Pos(),
            End:     node.End(),
            Message: "go-routine must contain a deferred call to r := recover()",
            SuggestedFixes: []analysis.SuggestedFix{
                {
                    Message: "add recover() with log message",
                    TextEdits: []analysis.TextEdit{{
                        Pos:     funcLit.Body.Lbrace,
                        End:     funcLit.Body.Lbrace + 1,
                        NewText: []byte(suggestedText),
                    }},
                },
            },
        })

Is this the right way to support fixes in a custom linter ☝️ ? Or is there a different way we should use?

boring-cyborg[bot] commented 3 years ago

Hey, thank you for opening your first Issue ! 🙂 If you would like to contribute we have a guide for contributors.

StevenACoffman commented 3 years ago

@MeenaAlfons If you figured this out, I would love to hear how!

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

polds commented 4 months ago

Any progress in this area? I've run into this now where golangci-lint running a compiled .so cannot apply a fix, but crafting a custom main.go using singlechecker.Main() can run with fix:

package main

import (
    "fmt"

    "golang.org/x/tools/go/analysis/singlechecker"
    "mylinter"
)

func main() {
    p, err := mylinter.New(nil)
    if err != nil {
        fmt.Printf("Unable to initialize linter: %v\n", err)
        return
    }
    a, err := p.BuildAnalyzers()
    if err != nil {
        fmt.Printf("Unable to build analyzers: %v\n", err)
        return
    }
    singlechecker.Main(a[0])
}

go run cmd/mylinter/main.go -fix ./...

This works but a Plugin with a New func:

// New returns a new instance of the linter.
func New(any) ([]*analysis.Analyzer, error) {
    p, err := mylinter.New(nil)
    if err != nil {
        return nil, err
    }
    return p.BuildAnalyzers()
}

When I run:

GL_DEBUG="runner" golangci-lint run -v --config=.golangci.yaml --enable mylinter --max-same-issues 0 --fix

I see:

INFO [runner] fixer took 0s with no stages

ldez commented 4 months ago

This issue will be fixed when #1779 will be fixed.

I've started working on it again, and I hope to be able to finalize it.