10 |
11 | You just hit a route that doesn't exist... the sadness.
12 |
13 | If you'd like to go back to homepage, click here
14 | .
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/test/testdata/fix/in/nolintlint.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Enolintlint -Elll
2 | //golangcitest:expected_linter nolintlint
3 | package p
4 |
5 | import "fmt"
6 |
7 | func nolintlint() {
8 | fmt.Println() // nolint:bob // leading space should be dropped
9 | fmt.Println() // nolint:bob // leading spaces should be dropped
10 |
11 | // note that the next lines will retain trailing whitespace when fixed
12 | fmt.Println() //nolint:all // nolint should be dropped
13 | fmt.Println() //nolint:lll // nolint should be dropped
14 |
15 | fmt.Println() //nolint:alice,lll // we don't drop individual linters from lists
16 | }
17 |
--------------------------------------------------------------------------------
/test/testdata/unused.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eunused
2 | package testdata
3 |
4 | func fn1() {} // want "func `fn1` is unused"
5 |
6 | //nolint:unused
7 | func fn2() { fn3() }
8 |
9 | func fn3() {} // want "func `fn3` is unused"
10 |
11 | func fn4() { fn5() } // want "func `fn4` is unused"
12 |
13 | func fn5() {} // want "func `fn5` is unused"
14 |
15 | func fn6() { fn4() } // want "func `fn6` is unused"
16 |
17 | type unusedStruct struct{} // want "type `unusedStruct` is unused"
18 |
19 | type unusedStructNolintUnused struct{} //nolint:unused
20 |
21 | type unusedStructNolintMegacheck struct{} //nolint:megacheck
22 |
--------------------------------------------------------------------------------
/test/testdata/errcheck_ignore_default.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eerrcheck
2 | //golangcitest:config_path testdata/configs/errcheck_ignore_default.yml
3 | package testdata
4 |
5 | import (
6 | "crypto/sha256"
7 | "fmt"
8 | "os"
9 | )
10 |
11 | func TestErrcheckIgnoreHashWriteByDefault() []byte {
12 | h := sha256.New()
13 | h.Write([]byte("food"))
14 | return h.Sum(nil)
15 | }
16 |
17 | func TestErrcheckIgnoreFmtByDefault(s string) int {
18 | n, _ := fmt.Println(s)
19 | return n
20 | }
21 |
22 | func TestErrcheckNoIgnoreOs() {
23 | _, _ = os.Open("f.txt") // want "Error return value of `os.Open` is not checked"
24 | }
25 |
--------------------------------------------------------------------------------
/test/testdata/exhaustive_ignore_enum_members.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eexhaustive
2 | //golangcitest:config_path testdata/configs/exhaustive_ignore_enum_members.yml
3 | package testdata
4 |
5 | type Direction int
6 |
7 | const (
8 | North Direction = iota
9 | East
10 | South
11 | West
12 | )
13 |
14 | // Should only report East as missing because the enum member West is ignored
15 | // using the ignore-enum-members setting.
16 |
17 | func processDirectionIgnoreEnumMembers(d Direction) {
18 | switch d { // want "missing cases in switch of type testdata.Direction: testdata.East"
19 | case North, South:
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/testdata/staticcheck_in_megacheck.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Emegacheck
2 | package testdata
3 |
4 | import "fmt"
5 |
6 | func StaticcheckInMegacheck() {
7 | var x int
8 | x = x // want staticcheck:"self-assignment of x to x"
9 | fmt.Printf("%d", x)
10 | }
11 |
12 | func StaticcheckNolintStaticcheckInMegacheck() {
13 | var x int
14 | x = x //nolint:staticcheck
15 | }
16 |
17 | func StaticcheckNolintMegacheckInMegacheck() {
18 | var x int
19 | x = x //nolint:megacheck
20 | }
21 |
22 | func Staticcheck2() {
23 | var x int
24 | x = x // want staticcheck:"self-assignment of x to x"
25 | fmt.Printf("%d", x)
26 | }
27 |
--------------------------------------------------------------------------------
/test/testdata/gocyclo.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egocyclo
2 | //golangcitest:config_path testdata/configs/gocyclo.yml
3 | package testdata
4 |
5 | import "net/http"
6 |
7 | func GocycloBigComplexity(s string) { // want "cyclomatic complexity .* of func .* is high .*"
8 | if s == http.MethodGet || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
9 | return
10 | }
11 |
12 | if s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
13 | return
14 | }
15 |
16 | if s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
17 | return
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/testdata/gosimple.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egosimple
2 | package testdata
3 |
4 | import (
5 | "log"
6 | )
7 |
8 | func Gosimple(ss []string) {
9 | if ss != nil { // want "S1031: unnecessary nil check around range"
10 | for _, s := range ss {
11 | log.Printf(s)
12 | }
13 | }
14 | }
15 |
16 | func GosimpleNolintGosimple(ss []string) {
17 | if ss != nil { //nolint:gosimple
18 | for _, s := range ss {
19 | log.Printf(s)
20 | }
21 | }
22 | }
23 |
24 | func GosimpleNolintMegacheck(ss []string) {
25 | if ss != nil { //nolint:megacheck
26 | for _, s := range ss {
27 | log.Printf(s)
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/testdata/loggercheck/loggercheck_noprintflike.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eloggercheck
2 | //golangcitest:config_path configs/loggercheck_noprintflike.yml
3 | package loggercheck
4 |
5 | import (
6 | "github.com/go-logr/logr"
7 | )
8 |
9 | func ExampleNoPrintfLike() {
10 | log := logr.Discard()
11 |
12 | log.Info("This message is ok")
13 | log.Info("Should not contains printf like format specifiers: %s %d %w") // want `logging message should not use format specifier "%s"`
14 | log.Info("It also checks for the key value pairs", "key", "value %.2f") // want `logging message should not use format specifier "%\.2f"`
15 | }
16 |
--------------------------------------------------------------------------------
/test/testdata/exhaustive_generated.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eexhaustive
2 | //golangcitest:expected_exitcode 0
3 | package testdata
4 |
5 | // Code generated by some program. DO NOT EDIT.
6 |
7 | // Should not report missing cases in the switch statement below, because this
8 | // is a generated file as indicated by the above comment
9 | // (golang.org/s/generatedcode), and check-generated setting is false.
10 |
11 | type Direction int
12 |
13 | const (
14 | North Direction = iota
15 | East
16 | South
17 | West
18 | )
19 |
20 | func processDirectionGenerated(d Direction) {
21 | switch d {
22 | case North, South:
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/src/@rocketseat/gatsby-theme-docs/src/util/slug.js:
--------------------------------------------------------------------------------
1 | export default function(string) {
2 | return string
3 | .toString() // Cast to string
4 | .toLowerCase() // Convert the string to lowercase letters
5 | .trim() // Remove whitespace from both sides of a string
6 | .replace(/\s/g, '-') // Replace each space with -
7 | .replace(
8 | /[^\w\-\u00b4\u00C0-\u00C3\u00c7\u00C9-\u00CA\u00CD\u00D3-\u00D5\u00DA\u00E0-\u00E3\u00E7\u00E9-\u00EA\u00ED\u00F3-\u00F5\u00FA]+/g,
9 | '',
10 | ); // Removes all chars that aren't words, -, ´ or some latin characters (À Á Â Ã Ç É Ê Í Ó Ô Õ Ú à á â ã ç é ê í ó ô õ ú)
11 | }
12 |
--------------------------------------------------------------------------------
/test/testdata/musttag.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Emusttag
2 | package testdata
3 |
4 | import (
5 | "encoding/asn1"
6 | "encoding/json"
7 | )
8 |
9 | // builtin functions:
10 | func musttagJSON() {
11 | var user struct { // want "`anonymous struct` should be annotated with the `json` tag as it is passed to `json.Marshal` at test(/|\\\\)testdata(/|\\\\)musttag.go:15:2"
12 | Name string
13 | Email string `json:"email"`
14 | }
15 | json.Marshal(user)
16 | }
17 |
18 | // custom functions from config:
19 | func musttagASN1() {
20 | var user struct {
21 | Name string
22 | Email string `asn1:"email"`
23 | }
24 | asn1.Marshal(user)
25 | }
26 |
--------------------------------------------------------------------------------
/test/testdata/predeclared.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Epredeclared
2 | package testdata
3 |
4 | func hello() {
5 | var real int // want "variable real has same name as predeclared identifier"
6 | a := A{}
7 | copy := Clone(a) // want "variable copy has same name as predeclared identifier"
8 |
9 | // suppress any "declared but not used" errors
10 | _ = real
11 | _ = a
12 | _ = copy
13 | }
14 |
15 | type A struct {
16 | true bool
17 | foo int
18 | }
19 |
20 | func Clone(a A) A {
21 | return A{
22 | true: a.true,
23 | foo: a.foo,
24 | }
25 | }
26 |
27 | func recover() {} // want "function recover has same name as predeclared identifier"
28 |
--------------------------------------------------------------------------------
/docs/src/docs/contributing/debug.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Debugging
3 | ---
4 |
5 | You can see a verbose output of linter by using `-v` option.
6 |
7 | ```bash
8 | golangci-lint run -v
9 | ```
10 |
11 | If you would like to see more detailed logs you can use the environment variable `GL_DEBUG`.
12 | Its value is a list of debug tags.
13 |
14 | The existing debug tags are documented in the following file: https://github.com/golangci/golangci-lint/blob/master/pkg/logutils/logutils.go
15 |
16 | For example:
17 |
18 | ```bash
19 | GL_DEBUG="loader,gocritic" golangci-lint run
20 | ```
21 |
22 | ```bash
23 | GL_DEBUG="loader,env" golangci-lint run
24 | ```
25 |
--------------------------------------------------------------------------------
/pkg/packages/skip.go:
--------------------------------------------------------------------------------
1 | package packages
2 |
3 | import (
4 | "fmt"
5 | "path/filepath"
6 | "regexp"
7 | )
8 |
9 | func pathElemReImpl(e string, sep rune) string {
10 | escapedSep := regexp.QuoteMeta(string(sep)) // needed for windows sep '\\'
11 | return fmt.Sprintf(`(^|%s)%s($|%s)`, escapedSep, e, escapedSep)
12 | }
13 |
14 | func pathElemRe(e string) string {
15 | return pathElemReImpl(e, filepath.Separator)
16 | }
17 |
18 | var StdExcludeDirRegexps = []string{
19 | pathElemRe("vendor"),
20 | pathElemRe("third_party"),
21 | pathElemRe("testdata"),
22 | pathElemRe("examples"),
23 | pathElemRe("Godeps"),
24 | pathElemRe("builtin"),
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/result/processors/max_same_issues_test.go:
--------------------------------------------------------------------------------
1 | package processors
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/golangci/golangci-lint/pkg/config"
7 | "github.com/golangci/golangci-lint/pkg/logutils"
8 | "github.com/golangci/golangci-lint/pkg/result"
9 | )
10 |
11 | func TestMaxSameIssues(t *testing.T) {
12 | p := NewMaxSameIssues(1, logutils.NewStderrLog(logutils.DebugKeyEmpty), &config.Config{})
13 | i1 := result.Issue{
14 | Text: "1",
15 | }
16 | i2 := result.Issue{
17 | Text: "2",
18 | }
19 |
20 | processAssertSame(t, p, i1) // ok
21 | processAssertSame(t, p, i2) // ok: another
22 | processAssertEmpty(t, p, i1) // skip
23 | }
24 |
--------------------------------------------------------------------------------
/test/testdata/predeclared_custom.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Epredeclared
2 | //golangcitest:config_path testdata/configs/predeclared.yml
3 | package testdata
4 |
5 | func hello() {
6 | var real int
7 | a := A{}
8 | copy := Clone(a) // want "variable copy has same name as predeclared identifier"
9 |
10 | // suppress any "declared but not used" errors
11 | _ = real
12 | _ = a
13 | _ = copy
14 | }
15 |
16 | type A struct {
17 | true bool // want "field true has same name as predeclared identifier"
18 | foo int
19 | }
20 |
21 | func Clone(a A) A {
22 | return A{
23 | true: a.true,
24 | foo: a.foo,
25 | }
26 | }
27 |
28 | func recover() {}
29 |
--------------------------------------------------------------------------------
/docs/src/docs/contributing/quick-start.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Contributing Quick Start
3 | ---
4 |
5 | 1. [Contributing workflow](/contributing/workflow/): about our workflow and environment setup.
6 | 2. [Architecture of golangci-lint](/contributing/architecture/)
7 | 3. [How to add new linters](/contributing/new-linters/)
8 | 4. [Debugging golangci-lint](/contributing/debug/)
9 | 5. [Contributing FAQ](/contributing/faq/)
10 | 6. [Contributing to the website](/contributing/website/)
11 |
12 | We have [good issues for first-time contributing](https://github.com/golangci/golangci-lint/issues?q=is%3Aopen+label%3A%22good+first+issue%22+sort%3Areactions-%2B1-desc).
13 |
--------------------------------------------------------------------------------
/pkg/golinters/typecheck.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "golang.org/x/tools/go/analysis"
5 |
6 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
7 | )
8 |
9 | func NewTypecheck() *goanalysis.Linter {
10 | const linterName = "typecheck"
11 |
12 | analyzer := &analysis.Analyzer{
13 | Name: linterName,
14 | Doc: goanalysis.TheOnlyanalyzerDoc,
15 | Run: goanalysis.DummyRun,
16 | }
17 |
18 | return goanalysis.NewLinter(
19 | linterName,
20 | "Like the front-end of a Go compiler, parses and type-checks Go code",
21 | []*analysis.Analyzer{analyzer},
22 | nil,
23 | ).WithLoadMode(goanalysis.LoadModeTypesInfo)
24 | }
25 |
--------------------------------------------------------------------------------
/test/testdata/depguard_additional_guards.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Edepguard
2 | //golangcitest:config_path testdata/configs/depguard_additional_guards.yml
3 | package testdata
4 |
5 | import (
6 | "compress/gzip" // want "`compress/gzip` is in the denylist"
7 | "fmt" // want "`fmt` is in the denylist"
8 | "log" // want "`log` is in the denylist: don't use log"
9 | "strings" // want "`strings` is in the denylist: disallowed in additional guard"
10 | )
11 |
12 | func SpewDebugInfo() {
13 | log.Println(gzip.BestCompression)
14 | log.Println(fmt.Sprintf("SpewDebugInfo"))
15 | log.Println(strings.ToLower("SpewDebugInfo"))
16 | }
17 |
--------------------------------------------------------------------------------
/docs/src/@rocketseat/gatsby-theme-docs/src/templates/docs-query.js:
--------------------------------------------------------------------------------
1 | import { graphql } from "gatsby";
2 | import DocsComponent from "../components/Docs-wrapper";
3 |
4 | export default DocsComponent;
5 |
6 | export const query = graphql`
7 | query($slug: String!) {
8 | mdx(fields: { slug: { eq: $slug } }) {
9 | id
10 | excerpt(pruneLength: 160)
11 | fields {
12 | slug
13 | }
14 | frontmatter {
15 | title
16 | description
17 | image
18 | disableTableOfContents
19 | }
20 | body
21 | headings {
22 | depth
23 | value
24 | }
25 | }
26 | }
27 | `;
28 |
--------------------------------------------------------------------------------
/internal/robustio/robustio_other.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | //go:build !windows && !darwin
6 |
7 | package robustio
8 |
9 | import (
10 | "os"
11 | )
12 |
13 | func rename(oldpath, newpath string) error {
14 | return os.Rename(oldpath, newpath)
15 | }
16 |
17 | func readFile(filename string) ([]byte, error) {
18 | return os.ReadFile(filename)
19 | }
20 |
21 | func removeAll(path string) error {
22 | return os.RemoveAll(path)
23 | }
24 |
25 | func isEphemeralError(err error) bool {
26 | return false
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/golinters/gosimple.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "honnef.co/go/tools/simple"
5 |
6 | "github.com/golangci/golangci-lint/pkg/config"
7 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
8 | )
9 |
10 | func NewGosimple(settings *config.StaticCheckSettings) *goanalysis.Linter {
11 | cfg := staticCheckConfig(settings)
12 |
13 | analyzers := setupStaticCheckAnalyzers(simple.Analyzers, getGoVersion(settings), cfg.Checks)
14 |
15 | return goanalysis.NewLinter(
16 | "gosimple",
17 | "Linter for Go source code that specializes in simplifying code",
18 | analyzers,
19 | nil,
20 | ).WithLoadMode(goanalysis.LoadModeTypesInfo)
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/golinters/goanalysis/load/guard.go:
--------------------------------------------------------------------------------
1 | package load
2 |
3 | import (
4 | "sync"
5 |
6 | "golang.org/x/tools/go/packages"
7 | )
8 |
9 | type Guard struct {
10 | loadMutexes map[*packages.Package]*sync.Mutex
11 | mutex sync.Mutex
12 | }
13 |
14 | func NewGuard() *Guard {
15 | return &Guard{
16 | loadMutexes: map[*packages.Package]*sync.Mutex{},
17 | }
18 | }
19 |
20 | func (g *Guard) AddMutexForPkg(pkg *packages.Package) {
21 | g.loadMutexes[pkg] = &sync.Mutex{}
22 | }
23 |
24 | func (g *Guard) MutexForPkg(pkg *packages.Package) *sync.Mutex {
25 | return g.loadMutexes[pkg]
26 | }
27 |
28 | func (g *Guard) Mutex() *sync.Mutex {
29 | return &g.mutex
30 | }
31 |
--------------------------------------------------------------------------------
/.github/contributors/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contributors",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "gen": "tsc && node --trace-warnings ./generate.js",
9 | "rewrite_readme": "tsc && node --trace-warnings ./rewrite_readme.js",
10 | "all": "npm run gen && npm run rewrite_readme"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "type": "module",
15 | "dependencies": {
16 | "@octokit/graphql": "^4.4.0",
17 | "@types/node": "^14.0.1",
18 | "name-your-contributors": "^3.8.3",
19 | "typescript": "^3.9.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/testdata/errcheck_ignore.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eerrcheck
2 | //golangcitest:config_path testdata/configs/ignore_config.yml
3 | package testdata
4 |
5 | import (
6 | "fmt"
7 | "io/ioutil"
8 | "os"
9 | )
10 |
11 | func TestErrcheckIgnoreOs() {
12 | _, _ = os.Open("f.txt")
13 | }
14 |
15 | func TestErrcheckIgnoreFmt(s string) int {
16 | n, _ := fmt.Println(s)
17 | return n
18 | }
19 |
20 | func TestErrcheckIgnoreIoutil() []byte {
21 | ret, _ := ioutil.ReadFile("f.txt")
22 | return ret
23 | }
24 |
25 | func TestErrcheckNoIgnoreIoutil() []byte {
26 | ret, _ := ioutil.ReadAll(nil) // want "Error return value of `ioutil.ReadAll` is not checked"
27 | return ret
28 | }
29 |
--------------------------------------------------------------------------------
/test/testdata/exhaustive_default.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eexhaustive
2 | //golangcitest:config_path testdata/configs/exhaustive_default.yml
3 | //golangcitest:expected_exitcode 0
4 | package testdata
5 |
6 | type Direction int
7 |
8 | const (
9 | North Direction = iota
10 | East
11 | South
12 | West
13 | )
14 |
15 | // Should not report missing cases in the switch statement below even though
16 | // some enum members (East, West) are not listed, because the switch statement
17 | // has a 'default' case and the default-signifies-exhaustive setting is true.
18 |
19 | func processDirectionDefault(d Direction) {
20 | switch d {
21 | case North, South:
22 | default:
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/test/testdata/godox.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egodox
2 | //golangcitest:config_path testdata/configs/godox.yml
3 | package testdata
4 |
5 | func todoLeftInCode() {
6 | // TODO implement me // want `Line contains FIXME/TODO: "TODO implement me`
7 | //TODO no space // want `Line contains FIXME/TODO: "TODO no space`
8 | // TODO(author): 123 // want `Line contains FIXME/TODO: "TODO\(author\): 123`
9 | //TODO(author): 123 // want `Line contains FIXME/TODO: "TODO\(author\): 123`
10 | //TODO(author) 456 // want `Line contains FIXME/TODO: "TODO\(author\) 456`
11 | // TODO: qwerty // want `Line contains FIXME/TODO: "TODO: qwerty`
12 | // todo 789 // want `Line contains FIXME/TODO: "todo 789`
13 | }
14 |
--------------------------------------------------------------------------------
/test/testdata/golint.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egolint --internal-cmd-test
2 | package testdata
3 |
4 | var Go_lint string // want "don't use underscores in Go names; var `Go_lint` should be `GoLint`"
5 |
6 | func ExportedFuncWithNoComment() {
7 | }
8 |
9 | var ExportedVarWithNoComment string
10 |
11 | type ExportedStructWithNoComment struct{}
12 |
13 | type ExportedInterfaceWithNoComment interface{}
14 |
15 | // Bad comment
16 | func ExportedFuncWithBadComment() {}
17 |
18 | type GolintTest struct{}
19 |
20 | func (receiver1 GolintTest) A() {}
21 |
22 | func (receiver2 GolintTest) B() {} // want "receiver name receiver2 should be consistent with previous receiver name receiver1 for GolintTest"
23 |
--------------------------------------------------------------------------------
/test/testdata/asasalint.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Easasalint
2 | package testdata
3 |
4 | import "fmt"
5 |
6 | func getArgsLength(args ...interface{}) int {
7 | // this line will not report as error
8 | fmt.Println(args)
9 | return len(args)
10 | }
11 |
12 | func checkArgsLength(args ...interface{}) int {
13 | return getArgsLength(args) // want `pass \[\]any as any to func getArgsLength func\(args \.\.\.interface\{\}\)`
14 | }
15 |
16 | func someCall() {
17 | var a = []interface{}{1, 2, 3}
18 | fmt.Println(checkArgsLength(a...) == getArgsLength(a)) // want `pass \[\]any as any to func getArgsLength func\(args \.\.\.interface\{\}\)`
19 | fmt.Println(checkArgsLength(a...) == getArgsLength(a...))
20 | }
21 |
--------------------------------------------------------------------------------
/test/testdata/goerr113.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egoerr113
2 | package testdata
3 |
4 | import "os"
5 |
6 | func SimpleEqual(e1, e2 error) bool {
7 | return e1 == e2 // want `err113: do not compare errors directly "e1 == e2", use "errors.Is\(e1, e2\)" instead`
8 | }
9 |
10 | func SimpleNotEqual(e1, e2 error) bool {
11 | return e1 != e2 // want `err113: do not compare errors directly "e1 != e2", use "!errors.Is\(e1, e2\)" instead`
12 | }
13 |
14 | func CheckGoerr13Import(e error) bool {
15 | f, err := os.Create("f.txt")
16 | if err != nil {
17 | return err == e // want `err113: do not compare errors directly "err == e", use "errors.Is\(err, e\)" instead`
18 | }
19 | f.Close()
20 | return false
21 | }
22 |
--------------------------------------------------------------------------------
/test/testdata/thelper_go118.go:
--------------------------------------------------------------------------------
1 | //go:build go1.18
2 |
3 | //golangcitest:args -Ethelper
4 | package testdata
5 |
6 | import "testing"
7 |
8 | func fhelperWithHelperAfterAssignment(f *testing.F) { // want "test helper function should start from f.Helper()"
9 | _ = 0
10 | f.Helper()
11 | }
12 |
13 | func fhelperWithNotFirst(s string, f *testing.F, i int) { // want `parameter \*testing.F should be the first`
14 | f.Helper()
15 | }
16 |
17 | func fhelperWithIncorrectName(o *testing.F) { // want `parameter \*testing.F should have name f`
18 | o.Helper()
19 | }
20 |
21 | func FuzzSubtestShouldNotBeChecked(f *testing.F) {
22 | f.Add(5, "hello")
23 | f.Fuzz(func(t *testing.T, a int, b string) {})
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/golinters/contextcheck.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/kkHAIKE/contextcheck"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
8 | "github.com/golangci/golangci-lint/pkg/lint/linter"
9 | )
10 |
11 | func NewContextCheck() *goanalysis.Linter {
12 | analyzer := contextcheck.NewAnalyzer(contextcheck.Configuration{})
13 |
14 | return goanalysis.NewLinter(
15 | analyzer.Name,
16 | analyzer.Doc,
17 | []*analysis.Analyzer{analyzer},
18 | nil,
19 | ).WithContextSetter(func(lintCtx *linter.Context) {
20 | analyzer.Run = contextcheck.NewRun(lintCtx.Packages, false)
21 | }).WithLoadMode(goanalysis.LoadModeTypesInfo)
22 | }
23 |
--------------------------------------------------------------------------------
/.github/workflows/pr-extra.yml:
--------------------------------------------------------------------------------
1 | name: Extra
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 |
8 | jobs:
9 | vulns:
10 | name: Vulnerability scanner
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: actions/setup-go@v3
15 | with:
16 | # https://github.com/actions/setup-go#supported-version-syntax
17 | # ex:
18 | # - 1.18beta1 -> 1.18.0-beta.1
19 | # - 1.18rc1 -> 1.18.0-rc.1
20 | go-version: '1.20'
21 | - name: Run go list
22 | run: go list -json -m all > go.list
23 | - name: Nancy
24 | uses: sonatype-nexus-community/nancy-github-action@v1.0.2
25 |
--------------------------------------------------------------------------------
/.nancy-ignore:
--------------------------------------------------------------------------------
1 | # Skip for indirect dependency github.com/coreos/etcd@3.3.13
2 | CVE-2020-15114
3 | CVE-2020-15115
4 | CVE-2020-15136
5 |
6 | # Skip for indirect dependency github.com/gogo/protobuf@1.3.1
7 | CVE-2021-3121
8 |
9 | # Skip for indirect dependency github.com/dgrijalva/jwt-go@3.2.0
10 | CVE-2020-26160
11 |
12 | # Skip for indirect dependencies:
13 | # golang/github.com/hashicorp/consul/api@v1.12.0
14 | # golang/github.com/hashicorp/consul/sdk@v0.8.0
15 | CVE-2022-29153
16 | CVE-2022-24687
17 | CVE-2021-41803
18 |
19 | # Skip for indirect dependencies golang/github.com/valyala/fasthttp@v1.30.0
20 | CVE-2022-21221
21 |
22 | # Skip for indirect dependencies golang/golang.org/x/net@v0.6.0
23 | CVE-2022-41723
24 |
--------------------------------------------------------------------------------
/pkg/golinters/goanalysis/issue.go:
--------------------------------------------------------------------------------
1 | package goanalysis
2 |
3 | import (
4 | "go/token"
5 |
6 | "golang.org/x/tools/go/analysis"
7 |
8 | "github.com/golangci/golangci-lint/pkg/result"
9 | )
10 |
11 | type Issue struct {
12 | result.Issue
13 | Pass *analysis.Pass
14 | }
15 |
16 | func NewIssue(i *result.Issue, pass *analysis.Pass) Issue {
17 | return Issue{
18 | Issue: *i,
19 | Pass: pass,
20 | }
21 | }
22 |
23 | type EncodingIssue struct {
24 | FromLinter string
25 | Text string
26 | Pos token.Position
27 | LineRange *result.Range
28 | Replacement *result.Replacement
29 | ExpectNoLint bool
30 | ExpectedNoLintLinter string
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/report/data.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | type Warning struct {
4 | Tag string `json:",omitempty"`
5 | Text string
6 | }
7 |
8 | type LinterData struct {
9 | Name string
10 | Enabled bool `json:",omitempty"`
11 | EnabledByDefault bool `json:",omitempty"`
12 | }
13 |
14 | type Data struct {
15 | Warnings []Warning `json:",omitempty"`
16 | Linters []LinterData `json:",omitempty"`
17 | Error string `json:",omitempty"`
18 | }
19 |
20 | func (d *Data) AddLinter(name string, enabled, enabledByDefault bool) {
21 | d.Linters = append(d.Linters, LinterData{
22 | Name: name,
23 | Enabled: enabled,
24 | EnabledByDefault: enabledByDefault,
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/golinters/tenv.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/sivchari/tenv"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewTenv(settings *config.TenvSettings) *goanalysis.Linter {
12 | a := tenv.Analyzer
13 |
14 | var cfg map[string]map[string]interface{}
15 | if settings != nil {
16 | cfg = map[string]map[string]interface{}{
17 | a.Name: {
18 | tenv.A: settings.All,
19 | },
20 | }
21 | }
22 |
23 | return goanalysis.NewLinter(
24 | a.Name,
25 | a.Doc,
26 | []*analysis.Analyzer{a},
27 | cfg,
28 | ).WithLoadMode(goanalysis.LoadModeSyntax)
29 | }
30 |
--------------------------------------------------------------------------------
/test/ruleguard/strings_simplify.go:
--------------------------------------------------------------------------------
1 | // go:build ruleguard
2 | package ruleguard
3 |
4 | import "github.com/quasilyte/go-ruleguard/dsl"
5 |
6 | func StringsSimplify(m dsl.Matcher) {
7 | // Some issues have simple fixes that can be expressed as
8 | // a replacement pattern. Rules can use Suggest() function
9 | // to add a quickfix action for such issues.
10 | m.Match(`strings.Replace($s, $old, $new, -1)`).
11 | Report(`this Replace call can be simplified`).
12 | Suggest(`strings.ReplaceAll($s, $old, $new)`)
13 |
14 | // Suggest() can be used without Report().
15 | // It'll print the suggested template to the user.
16 | m.Match(`strings.Count($s1, $s2) == 0`).
17 | Suggest(`!strings.Contains($s1, $s2)`)
18 | }
19 |
--------------------------------------------------------------------------------
/test/testdata/makezero.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Emakezero
2 | package testdata
3 |
4 | import "math"
5 |
6 | func Makezero() []int {
7 | x := make([]int, math.MaxInt8)
8 | return append(x, 1) // want "append to slice `x` with non-zero initialized length"
9 | }
10 |
11 | func MakezeroMultiple() []int {
12 | x, y := make([]int, math.MaxInt8), make([]int, math.MaxInt8)
13 | return append(x, // want "append to slice `x` with non-zero initialized length"
14 | append(y, 1)...) // want "append to slice `y` with non-zero initialized length"
15 | }
16 |
17 | func MakezeroNolint() []int {
18 | x := make([]int, math.MaxInt8)
19 | return append(x, 1) //nolint:makezero // ok that we're appending to an uninitialized slice
20 | }
21 |
--------------------------------------------------------------------------------
/test/testdata/nilerr.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Enilerr
2 | package testdata
3 |
4 | import "os"
5 |
6 | func nilErr1() error {
7 | err := nilErrDo()
8 | if err == nil {
9 | return err // want `error is nil \(line 7\) but it returns error`
10 | }
11 |
12 | return nil
13 | }
14 |
15 | func nilErr2() error {
16 | err := nilErrDo()
17 | if err == nil {
18 | return err // want `error is nil \(line 16\) but it returns error`
19 | }
20 |
21 | return nil
22 | }
23 |
24 | func nilErr3() error {
25 | err := nilErrDo()
26 | if err != nil {
27 | return nil // want `error is not nil \(line 25\) but it returns nil`
28 | }
29 |
30 | return nil
31 | }
32 |
33 | func nilErrDo() error {
34 | return os.ErrNotExist
35 | }
36 |
--------------------------------------------------------------------------------
/test/testdata/asciicheck.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Easciicheck
2 | package testdata
3 |
4 | import (
5 | "fmt"
6 | "time"
7 | )
8 |
9 | type AsciicheckTеstStruct struct { // want `identifier "AsciicheckTеstStruct" contain non-ASCII character: U\+0435 'е'`
10 | Date time.Time
11 | }
12 |
13 | type AsciicheckField struct{}
14 |
15 | type AsciicheckJustStruct struct {
16 | Tеst AsciicheckField // want `identifier "Tеst" contain non-ASCII character: U\+0435 'е'`
17 | }
18 |
19 | func AsciicheckTеstFunc() { // want `identifier "AsciicheckTеstFunc" contain non-ASCII character: U\+0435 'е'`
20 | var tеstVar int // want `identifier "tеstVar" contain non-ASCII character: U\+0435 'е'`
21 | tеstVar = 0
22 | fmt.Println(tеstVar)
23 | }
24 |
--------------------------------------------------------------------------------
/test/testdata/importas.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eimportas
2 | //golangcitest:config_path testdata/configs/importas.yml
3 | package testdata
4 |
5 | import (
6 | wrong_alias "fmt" // want `import "fmt" imported as "wrong_alias" but must be "fff" according to config`
7 | "os"
8 | wrong_alias_again "os" // want `import "os" imported as "wrong_alias_again" but must be "std_os" according to config`
9 |
10 | wrong "github.com/pkg/errors" // want `import "github.com/pkg/errors" imported as "wrong" but must be "pkgerr" according to config`
11 | )
12 |
13 | func ImportAsWrongAlias() {
14 | wrong_alias.Println("foo")
15 | wrong_alias_again.Stdout.WriteString("bar")
16 | os.Stdout.WriteString("test")
17 | _ = wrong.New("baz")
18 | }
19 |
--------------------------------------------------------------------------------
/test/testdata/stylecheck.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Estylecheck
2 | package testdata
3 |
4 | func Stylecheck(x int) {
5 | switch x {
6 | case 1:
7 | return
8 | default: // want "ST1015: default case should be first or last in switch statement"
9 | return
10 | case 2:
11 | return
12 | }
13 | }
14 |
15 | func StylecheckNolintStylecheck(x int) {
16 | switch x {
17 | case 1:
18 | return
19 | default: //nolint:stylecheck
20 | return
21 | case 2:
22 | return
23 | }
24 | }
25 |
26 | func StylecheckNolintMegacheck(x int) {
27 | switch x {
28 | case 1:
29 | return
30 | default: //nolint:megacheck // want "ST1015: default case should be first or last in switch statement"
31 | return
32 | case 2:
33 | return
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/golinters/rowserrcheck.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/jingyugao/rowserrcheck/passes/rowserr"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewRowsErrCheck(settings *config.RowsErrCheckSettings) *goanalysis.Linter {
12 | var pkgs []string
13 | if settings != nil {
14 | pkgs = settings.Packages
15 | }
16 |
17 | analyzer := rowserr.NewAnalyzer(pkgs...)
18 |
19 | return goanalysis.NewLinter(
20 | "rowserrcheck",
21 | "checks whether Err of rows is checked successfully",
22 | []*analysis.Analyzer{analyzer},
23 | nil,
24 | ).WithLoadMode(goanalysis.LoadModeTypesInfo)
25 | }
26 |
--------------------------------------------------------------------------------
/test/testdata/configs/gomodguard.yml:
--------------------------------------------------------------------------------
1 | linters-settings:
2 | gomodguard:
3 | allowed:
4 | modules: # List of allowed modules
5 | - golang.org/x/mod/modfile
6 | blocked:
7 | modules: # List of blocked modules
8 | - gopkg.in/yaml.v3: # Blocked module
9 | recommendations: # Recommended modules that should be used instead (Optional)
10 | - github.com/kylelemons/go-gypsy
11 | reason: "This is an example of recommendations." # Reason why the recommended module should be used (Optional)
12 |
--------------------------------------------------------------------------------
/test/testdata/revive_default.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Erevive
2 | package testdata
3 |
4 | import (
5 | "net/http"
6 | "time"
7 | )
8 |
9 | func testReviveDefault(t *time.Duration) error {
10 | if t == nil {
11 | return nil
12 | } else { // want "indent-error-flow: if block ends with a return statement, .*"
13 | return nil
14 | }
15 | }
16 |
17 | func testReviveComplexityDefault(s string) {
18 | if s == http.MethodGet || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
19 | return
20 | }
21 |
22 | if s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
23 | return
24 | }
25 |
26 | if s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
27 | return
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/testdata/rowserrcheck.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Erowserrcheck
2 | package testdata
3 |
4 | import (
5 | "database/sql"
6 | "fmt"
7 | "math/rand"
8 | )
9 |
10 | func RowsErrNotChecked(db *sql.DB) {
11 | rows, _ := db.Query("select id from tb") // want "rows.Err must be checked"
12 | for rows.Next() {
13 |
14 | }
15 | }
16 |
17 | func issue943(db *sql.DB) {
18 | var rows *sql.Rows
19 | var err error
20 |
21 | if rand.Float64() < 0.5 {
22 | rows, err = db.Query("select 1")
23 | } else {
24 | rows, err = db.Query("select 2")
25 | }
26 | if err != nil {
27 | panic(err)
28 | }
29 |
30 | defer rows.Close()
31 |
32 | for rows.Next() {
33 | fmt.Println("new rows")
34 | }
35 |
36 | if err := rows.Err(); err != nil {
37 | panic(err)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/test/testdata/funlen.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Efunlen
2 | //golangcitest:config_path testdata/configs/funlen.yml
3 | package testdata
4 |
5 | func TooManyLines() { // want `Function 'TooManyLines' is too long \(22 > 20\)`
6 | t := struct {
7 | A string
8 | B string
9 | C string
10 | D string
11 | E string
12 | F string
13 | G string
14 | H string
15 | I string
16 | }{
17 | `a`,
18 | `b`,
19 | `c`,
20 | `d`,
21 | `e`,
22 | `f`,
23 | `g`,
24 | `h`,
25 | `i`,
26 | }
27 | _ = t
28 | }
29 |
30 | func TooManyStatements() { // want `Function 'TooManyStatements' has too many statements \(11 > 10\)`
31 | a := 1
32 | b := a
33 | c := b
34 | d := c
35 | e := d
36 | f := e
37 | g := f
38 | h := g
39 | i := h
40 | j := i
41 | _ = j
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/golinters/musttag.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/junk1tm/musttag"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewMustTag(setting *config.MustTagSettings) *goanalysis.Linter {
12 | var funcs []musttag.Func
13 |
14 | if setting != nil {
15 | for _, fn := range setting.Functions {
16 | funcs = append(funcs, musttag.Func{
17 | Name: fn.Name,
18 | Tag: fn.Tag,
19 | ArgPos: fn.ArgPos,
20 | })
21 | }
22 | }
23 |
24 | a := musttag.New(funcs...)
25 |
26 | return goanalysis.
27 | NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil).
28 | WithLoadMode(goanalysis.LoadModeTypesInfo)
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/golinters/maintidx.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/yagipy/maintidx"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewMaintIdx(cfg *config.MaintIdxSettings) *goanalysis.Linter {
12 | analyzer := maintidx.Analyzer
13 |
14 | cfgMap := map[string]map[string]interface{}{
15 | analyzer.Name: {"under": 20},
16 | }
17 |
18 | if cfg != nil {
19 | cfgMap[analyzer.Name] = map[string]interface{}{
20 | "under": cfg.Under,
21 | }
22 | }
23 |
24 | return goanalysis.NewLinter(
25 | analyzer.Name,
26 | analyzer.Doc,
27 | []*analysis.Analyzer{analyzer},
28 | cfgMap,
29 | ).WithLoadMode(goanalysis.LoadModeSyntax)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/printers/json.go:
--------------------------------------------------------------------------------
1 | package printers
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "io"
7 |
8 | "github.com/golangci/golangci-lint/pkg/report"
9 | "github.com/golangci/golangci-lint/pkg/result"
10 | )
11 |
12 | type JSON struct {
13 | rd *report.Data
14 | w io.Writer
15 | }
16 |
17 | func NewJSON(rd *report.Data, w io.Writer) *JSON {
18 | return &JSON{
19 | rd: rd,
20 | w: w,
21 | }
22 | }
23 |
24 | type JSONResult struct {
25 | Issues []result.Issue
26 | Report *report.Data
27 | }
28 |
29 | func (p JSON) Print(ctx context.Context, issues []result.Issue) error {
30 | res := JSONResult{
31 | Issues: issues,
32 | Report: p.rd,
33 | }
34 | if res.Issues == nil {
35 | res.Issues = []result.Issue{}
36 | }
37 |
38 | return json.NewEncoder(p.w).Encode(res)
39 | }
40 |
--------------------------------------------------------------------------------
/test/testdata/goconst.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egoconst
2 | package testdata
3 |
4 | import "fmt"
5 |
6 | func GoconstA() {
7 | a := "needconst" // want "string `needconst` has 5 occurrences, make it a constant"
8 | fmt.Print(a)
9 | b := "needconst"
10 | fmt.Print(b)
11 | c := "needconst"
12 | fmt.Print(c)
13 | }
14 |
15 | func GoconstB() {
16 | a := "needconst"
17 | fmt.Print(a)
18 | b := "needconst"
19 | fmt.Print(b)
20 | }
21 |
22 | const AlreadyHasConst = "alreadyhasconst"
23 |
24 | func GoconstC() {
25 | a := "alreadyhasconst" // want "string `alreadyhasconst` has 3 occurrences, but such constant `AlreadyHasConst` already exists"
26 | fmt.Print(a)
27 | b := "alreadyhasconst"
28 | fmt.Print(b)
29 | c := "alreadyhasconst"
30 | fmt.Print(c)
31 | fmt.Print("alreadyhasconst")
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/golinters/dupword.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/Abirdcfly/dupword"
7 | "golang.org/x/tools/go/analysis"
8 |
9 | "github.com/golangci/golangci-lint/pkg/config"
10 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
11 | )
12 |
13 | func NewDupWord(setting *config.DupWordSettings) *goanalysis.Linter {
14 | a := dupword.NewAnalyzer()
15 |
16 | cfgMap := map[string]map[string]interface{}{}
17 | if setting != nil {
18 | cfgMap[a.Name] = map[string]interface{}{
19 | "keyword": strings.Join(setting.Keywords, ","),
20 | }
21 | }
22 |
23 | return goanalysis.NewLinter(
24 | a.Name,
25 | "checks for duplicate words in the source code",
26 | []*analysis.Analyzer{a},
27 | cfgMap,
28 | ).WithLoadMode(goanalysis.LoadModeSyntax)
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/golinters/interfacebloat.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/sashamelentyev/interfacebloat/pkg/analyzer"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewInterfaceBloat(settings *config.InterfaceBloatSettings) *goanalysis.Linter {
12 | a := analyzer.New()
13 |
14 | var cfg map[string]map[string]interface{}
15 | if settings != nil {
16 | cfg = map[string]map[string]interface{}{
17 | a.Name: {
18 | analyzer.InterfaceMaxMethodsFlag: settings.Max,
19 | },
20 | }
21 | }
22 |
23 | return goanalysis.NewLinter(
24 | a.Name,
25 | a.Doc,
26 | []*analysis.Analyzer{a},
27 | cfg,
28 | ).WithLoadMode(goanalysis.LoadModeSyntax)
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/golinters/nilnil.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/Antonboom/nilnil/pkg/analyzer"
7 | "golang.org/x/tools/go/analysis"
8 |
9 | "github.com/golangci/golangci-lint/pkg/config"
10 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
11 | )
12 |
13 | func NewNilNil(cfg *config.NilNilSettings) *goanalysis.Linter {
14 | a := analyzer.New()
15 |
16 | cfgMap := make(map[string]map[string]interface{})
17 | if cfg != nil && len(cfg.CheckedTypes) != 0 {
18 | cfgMap[a.Name] = map[string]interface{}{
19 | "checked-types": strings.Join(cfg.CheckedTypes, ","),
20 | }
21 | }
22 |
23 | return goanalysis.NewLinter(
24 | a.Name,
25 | a.Doc,
26 | []*analysis.Analyzer{a},
27 | cfgMap,
28 | ).
29 | WithLoadMode(goanalysis.LoadModeTypesInfo)
30 | }
31 |
--------------------------------------------------------------------------------
/test/testdata/loggercheck/loggercheck_logronly.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Eloggercheck
2 | //golangcitest:config_path configs/loggercheck_logronly.yml
3 | package loggercheck
4 |
5 | import (
6 | "fmt"
7 |
8 | "github.com/go-logr/logr"
9 | "go.uber.org/zap"
10 | "k8s.io/klog/v2"
11 | )
12 |
13 | func ExampleLogrOnly() {
14 | log := logr.Discard()
15 | log.Info("message", "key1", "value1", "key2", "value2", "key3") // want `odd number of arguments passed as key-value pairs for logging`
16 |
17 | klog.InfoS("message", "key1")
18 |
19 | sugar := zap.NewExample().Sugar()
20 | sugar.Infow("message", "key1", "value1", "key2")
21 | sugar.Errorw("error message", "key1")
22 |
23 | // Will not check by default (-requirestringkey)
24 | log.Error(fmt.Errorf("error"), "message", []byte("key1"), "value1")
25 | }
26 |
--------------------------------------------------------------------------------
/test/testdata/nolintlint.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Enolintlint -Emisspell
2 | //golangcitest:expected_linter nolintlint
3 | //golangcitest:config_path testdata/configs/nolintlint.yml
4 | package testdata
5 |
6 | import "fmt"
7 |
8 | func Foo() {
9 | fmt.Println("not specific") //nolint // want "directive `.*` should mention specific linter such as `//nolint:my-linter`"
10 | fmt.Println("not machine readable") // nolint // want "directive `.*` should be written as `//nolint`"
11 | fmt.Println("extra spaces") // nolint:unused // because // want "directive `.*` should not have more than one leading space"
12 |
13 | // test expanded range
14 | //nolint:misspell // deliberate misspelling to trigger nolintlint
15 | func() {
16 | mispell := true
17 | fmt.Println(mispell)
18 | }()
19 | }
20 |
--------------------------------------------------------------------------------
/test/testshared/runner_unix.go:
--------------------------------------------------------------------------------
1 | //go:build !windows
2 |
3 | package testshared
4 |
5 | import (
6 | "path/filepath"
7 | "testing"
8 | )
9 |
10 | // SkipOnWindows it's a noop function on Unix.
11 | func SkipOnWindows(_ testing.TB) {}
12 |
13 | // NormalizeFilePathInJSON it's a noop function on Unix.
14 | func NormalizeFilePathInJSON(in string) string {
15 | return in
16 | }
17 |
18 | // NormalizeFileInString it's a noop function on Unix.
19 | func NormalizeFileInString(in string) string {
20 | return in
21 | }
22 |
23 | // defaultBinaryName returns the path to the default binary.
24 | func defaultBinaryName() string {
25 | return filepath.Join("..", "golangci-lint")
26 | }
27 |
28 | // normalizeFilePath it's a noop function on Unix.
29 | func normalizeFilePath(in string) string {
30 | return in
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/golinters/nonamedreturns.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/firefart/nonamedreturns/analyzer"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewNoNamedReturns(settings *config.NoNamedReturnsSettings) *goanalysis.Linter {
12 | a := analyzer.Analyzer
13 |
14 | var cfg map[string]map[string]interface{}
15 | if settings != nil {
16 | cfg = map[string]map[string]interface{}{
17 | a.Name: {
18 | analyzer.FlagReportErrorInDefer: settings.ReportErrorInDefer,
19 | },
20 | }
21 | }
22 |
23 | return goanalysis.NewLinter(
24 | a.Name,
25 | a.Doc,
26 | []*analysis.Analyzer{a},
27 | cfg,
28 | ).WithLoadMode(goanalysis.LoadModeTypesInfo)
29 | }
30 |
--------------------------------------------------------------------------------
/test/testdata/lll.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Elll
2 | //golangcitest:config_path testdata/configs/lll.yml
3 | package testdata
4 |
5 | import (
6 | _ "unsafe"
7 | )
8 |
9 | func Lll() {
10 | // In my experience, long lines are the lines with comments, not the code. So this is a long comment // want "line is 137 characters"
11 | }
12 |
13 | //go:generate mockgen -source lll.go -destination a_verylong_generate_mock_my_lll_interface.go --package testdata -self_package github.com/golangci/golangci-lint/test/testdata
14 | type MyLllInterface interface {
15 | }
16 |
17 | //go:linkname VeryLongNameForTestAndLinkNameFunction github.com/golangci/golangci-lint/test/testdata.VeryLongNameForTestAndLinkedNameFunction
18 | func VeryLongNameForTestAndLinkNameFunction()
19 |
20 | func VeryLongNameForTestAndLinkedNameFunction() {}
21 |
--------------------------------------------------------------------------------
/test/testdata/revive.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Erevive
2 | //golangcitest:config_path testdata/configs/revive.yml
3 | package testdata
4 |
5 | import (
6 | "net/http"
7 | "time"
8 | )
9 |
10 | func SampleRevive(t *time.Duration) error {
11 | if t == nil {
12 | return nil
13 | } else {
14 | return nil
15 | }
16 | }
17 |
18 | func testReviveComplexity(s string) { // want "cyclomatic: function testReviveComplexity has cyclomatic complexity 22"
19 | if s == http.MethodGet || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
20 | return
21 | }
22 |
23 | if s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
24 | return
25 | }
26 |
27 | if s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" {
28 | return
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gomod
4 | directory: "/"
5 | schedule:
6 | interval: weekly
7 | day: "sunday"
8 | time: "11:00" # 11am UTC
9 | ignore:
10 | # ignore forked linters because of their versioning issues. TODO: fix it.
11 | - dependency-name: "github.com/golangci/*"
12 | - package-ecosystem: github-actions
13 | directory: "/"
14 | schedule:
15 | interval: weekly
16 | - package-ecosystem: docker
17 | directory: "/build"
18 | schedule:
19 | interval: weekly
20 | - package-ecosystem: gomod
21 | directory: "/scripts/gen_github_action_config"
22 | schedule:
23 | interval: weekly
24 | - package-ecosystem: npm
25 | directory: "/docs"
26 | schedule:
27 | interval: monthly
28 |
--------------------------------------------------------------------------------
/pkg/golinters/ireturn.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/butuzov/ireturn/analyzer"
7 | "golang.org/x/tools/go/analysis"
8 |
9 | "github.com/golangci/golangci-lint/pkg/config"
10 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
11 | )
12 |
13 | func NewIreturn(settings *config.IreturnSettings) *goanalysis.Linter {
14 | a := analyzer.NewAnalyzer()
15 |
16 | cfg := map[string]map[string]interface{}{}
17 | if settings != nil {
18 | cfg[a.Name] = map[string]interface{}{
19 | "allow": strings.Join(settings.Allow, ","),
20 | "reject": strings.Join(settings.Reject, ","),
21 | }
22 | }
23 |
24 | return goanalysis.NewLinter(
25 | a.Name,
26 | a.Doc,
27 | []*analysis.Analyzer{a},
28 | cfg,
29 | ).WithLoadMode(goanalysis.LoadModeTypesInfo)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/golinters/nlreturn.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/ssgreg/nlreturn/v2/pkg/nlreturn"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewNLReturn(settings *config.NlreturnSettings) *goanalysis.Linter {
12 | a := nlreturn.NewAnalyzer()
13 |
14 | cfg := map[string]map[string]interface{}{}
15 | if settings != nil {
16 | cfg[a.Name] = map[string]interface{}{
17 | "block-size": settings.BlockSize,
18 | }
19 | }
20 |
21 | return goanalysis.NewLinter(
22 | a.Name,
23 | "nlreturn checks for a new line before return and branch statements to increase code clarity",
24 | []*analysis.Analyzer{a},
25 | cfg,
26 | ).WithLoadMode(goanalysis.LoadModeSyntax)
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/golinters/predeclared.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "github.com/nishanths/predeclared/passes/predeclared"
5 | "golang.org/x/tools/go/analysis"
6 |
7 | "github.com/golangci/golangci-lint/pkg/config"
8 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9 | )
10 |
11 | func NewPredeclared(settings *config.PredeclaredSettings) *goanalysis.Linter {
12 | a := predeclared.Analyzer
13 |
14 | var cfg map[string]map[string]interface{}
15 | if settings != nil {
16 | cfg = map[string]map[string]interface{}{
17 | a.Name: {
18 | predeclared.IgnoreFlag: settings.Ignore,
19 | predeclared.QualifiedFlag: settings.Qualified,
20 | },
21 | }
22 | }
23 |
24 | return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg).
25 | WithLoadMode(goanalysis.LoadModeSyntax)
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/golinters/staticcheck.go:
--------------------------------------------------------------------------------
1 | package golinters
2 |
3 | import (
4 | "honnef.co/go/tools/staticcheck"
5 |
6 | "github.com/golangci/golangci-lint/pkg/config"
7 | "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
8 | )
9 |
10 | func NewStaticcheck(settings *config.StaticCheckSettings) *goanalysis.Linter {
11 | cfg := staticCheckConfig(settings)
12 | analyzers := setupStaticCheckAnalyzers(staticcheck.Analyzers, getGoVersion(settings), cfg.Checks)
13 |
14 | return goanalysis.NewLinter(
15 | "staticcheck",
16 | "It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary."+
17 | " The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint.",
18 | analyzers,
19 | nil,
20 | ).WithLoadMode(goanalysis.LoadModeTypesInfo)
21 | }
22 |
--------------------------------------------------------------------------------
/test/testdata/goconst_ignore_test.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egoconst
2 | //golangcitest:config_path testdata/configs/goconst_ignore.yml
3 | //golangcitest:expected_exitcode 0
4 | package testdata
5 |
6 | import (
7 | "fmt"
8 | "testing"
9 | )
10 |
11 | func TestGoConstA(t *testing.T) {
12 | a := "needconst"
13 | fmt.Print(a)
14 | b := "needconst"
15 | fmt.Print(b)
16 | c := "needconst"
17 | fmt.Print(c)
18 | }
19 |
20 | func TestGoConstB(t *testing.T) {
21 | a := "needconst"
22 | fmt.Print(a)
23 | b := "needconst"
24 | fmt.Print(b)
25 | }
26 |
27 | const AlreadyHasConst = "alreadyhasconst"
28 |
29 | func TestGoConstC(t *testing.T) {
30 | a := "alreadyhasconst"
31 | fmt.Print(a)
32 | b := "alreadyhasconst"
33 | fmt.Print(b)
34 | c := "alreadyhasconst"
35 | fmt.Print(c)
36 | fmt.Print("alreadyhasconst")
37 | }
38 |
--------------------------------------------------------------------------------
/test/testdata/gomnd.go:
--------------------------------------------------------------------------------
1 | //golangcitest:args -Egomnd
2 | package testdata
3 |
4 | import (
5 | "log"
6 | "net/http"
7 | "time"
8 | )
9 |
10 | func UseMagicNumber() {
11 | c := &http.Client{
12 | Timeout: 2 * time.Second, // want "Magic number: 2, in