diff --git a/.golangci.example.yml b/.golangci.example.yml index 7b96b313c2e6..f6deacaa2710 100644 --- a/.golangci.example.yml +++ b/.golangci.example.yml @@ -152,10 +152,10 @@ linters-settings: # Settings passed to gocritic. # The settings key is the name of a supported gocritic checker. # The list of supported checkers can be find in https://go-critic.github.io/overview. - settings: + settings: captLocal: # must be valid enabled check name # whether to restrict checker to params only (default true) - paramsOnly: true + paramsOnly: true elseif: # whether to skip balanced if-else pairs (default true) skipBalanced: true @@ -219,13 +219,13 @@ linters-settings: # # {{ AUTHOR }} {{ COMPANY }} {{ YEAR }} # SPDX-License-Identifier: Apache-2.0 - + # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: - + # http://www.apache.org/licenses/LICENSE-2.0 - + # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -321,6 +321,11 @@ linters-settings: simple: true range-loops: true # Report preallocation suggestions on range loops, true by default for-loops: false # Report preallocation suggestions on for loops, false by default + predeclared: + # comma-separated list of predeclared identifiers to not report on + ignore: "" + # include method names and field names (i.e., qualified names) in checks + q: false nolintlint: # Enable to ensure that nolint directives are all used. Default is true. allow-unused: false diff --git a/go.mod b/go.mod index 9c9894517a42..233d82eae79e 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/moricho/tparallel v0.2.1 github.com/nakabonne/nestif v0.3.0 github.com/nishanths/exhaustive v0.1.0 + github.com/nishanths/predeclared v0.2.1 github.com/pkg/errors v0.9.1 github.com/polyfloyd/go-errorlint v0.0.0-20201127212506-19bd8db6546f github.com/ryancurrah/gomodguard v1.2.0 @@ -69,7 +70,7 @@ require ( github.com/valyala/quicktemplate v1.6.3 golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect golang.org/x/text v0.3.4 // indirect - golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb + golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c gopkg.in/yaml.v2 v2.4.0 honnef.co/go/tools v0.0.1-2020.1.6 mvdan.cc/gofumpt v0.0.0-20201129102820-5c11c50e9475 diff --git a/go.sum b/go.sum index c33a60b41a69..4c448b5dc58a 100644 --- a/go.sum +++ b/go.sum @@ -289,6 +289,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.1.0 h1:kVlMw8h2LHPMGUVqUj6230oQjjTMFjwcZrnkhXzFfl8= github.com/nishanths/exhaustive v0.1.0/go.mod h1:S1j9110vxV1ECdCudXRkeMnFQ/DQk9ajLT0Uf2MYZQQ= +github.com/nishanths/predeclared v0.2.1 h1:1TXtjmy4f3YCFjTxRd8zcFHOmoUir+gp0ESzjFzG2sw= +github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -581,6 +583,10 @@ golang.org/x/tools v0.0.0-20201118003311-bd56c0adb394 h1:O3VD5Fds21mB1WVRTbkiz/H golang.org/x/tools v0.0.0-20201118003311-bd56c0adb394/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb h1:z5+u0pkAUPUWd3taoTialQ2JAMo4Wo1Z3L25U4ZV9r0= golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c h1:xx3+TTG3yS1I6Ola5Kapxr5vZu85vKkcwKyV6ke9fHA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c h1:dS09fXwOFF9cXBnIzZexIuUBj95U1NyQjkEhkgidDow= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/config/config.go b/pkg/config/config.go index 6474a04c1106..4281f75f28bd 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -270,6 +270,7 @@ type LintersSettings struct { Makezero MakezeroSettings Thelper ThelperSettings Forbidigo ForbidigoSettings + Predeclared PredeclaredSettings Custom map[string]CustomLinterSettings } @@ -411,6 +412,11 @@ type ForbidigoSettings struct { Forbid []string `mapstructure:"forbid"` } +type PredeclaredSettings struct { + Ignore string `mapstructure:"ignore"` + Qualified bool `mapstructure:"q"` +} + var defaultLintersSettings = LintersSettings{ Lll: LllSettings{ LineLength: 120, @@ -471,6 +477,10 @@ var defaultLintersSettings = LintersSettings{ ErrorLint: ErrorLintSettings{ Errorf: true, }, + Predeclared: PredeclaredSettings{ + Ignore: "", + Qualified: false, + }, } type CustomLinterSettings struct { diff --git a/pkg/golinters/predeclared.go b/pkg/golinters/predeclared.go new file mode 100644 index 000000000000..caccd482397f --- /dev/null +++ b/pkg/golinters/predeclared.go @@ -0,0 +1,26 @@ +package golinters + +import ( + "github.com/nishanths/predeclared/passes/predeclared" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewPredeclared(settings *config.PredeclaredSettings) *goanalysis.Linter { + a := predeclared.Analyzer + + var cfg map[string]map[string]interface{} + if settings != nil { + cfg = map[string]map[string]interface{}{ + a.Name: { + predeclared.IgnoreFlag: settings.Ignore, + predeclared.QualifiedFlag: settings.Qualified, + }, + } + } + + return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 5bec998854d5..510b834b32bb 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -94,12 +94,14 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { var exhaustiveCfg *config.ExhaustiveSettings var errorlintCfg *config.ErrorLintSettings var thelperCfg *config.ThelperSettings + var predeclaredCfg *config.PredeclaredSettings if m.cfg != nil { govetCfg = &m.cfg.LintersSettings.Govet testpackageCfg = &m.cfg.LintersSettings.Testpackage exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive errorlintCfg = &m.cfg.LintersSettings.ErrorLint thelperCfg = &m.cfg.LintersSettings.Thelper + predeclaredCfg = &m.cfg.LintersSettings.Predeclared } const megacheckName = "megacheck" lcs := []*linter.Config{ @@ -342,6 +344,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.NewForbidigo()). WithPresets(linter.PresetStyle). WithURL("https://github.com/ashanbrown/forbidigo"), + linter.NewConfig(golinters.NewPredeclared(predeclaredCfg)). + WithPresets(linter.PresetStyle). + WithURL("https://github.com/nishanths/predeclared"), // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives linter.NewConfig(golinters.NewNoLintLint()). diff --git a/test/testdata/configs/predeclared.yml b/test/testdata/configs/predeclared.yml new file mode 100644 index 000000000000..227775858212 --- /dev/null +++ b/test/testdata/configs/predeclared.yml @@ -0,0 +1,4 @@ +linters-settings: + predeclared: + ignore: "real,recover" + q: true diff --git a/test/testdata/predeclared.go b/test/testdata/predeclared.go new file mode 100644 index 000000000000..41bbc10151cd --- /dev/null +++ b/test/testdata/predeclared.go @@ -0,0 +1,27 @@ +//args: -Epredeclared +package testdata + +func hello() { + var real int // ERROR "variable real has same name as predeclared identifier" + a := A{} + copy := Clone(a) // ERROR "variable copy has same name as predeclared identifier" + + // suppress any "declared but not used" errors + _ = real + _ = a + _ = copy +} + +type A struct { + true bool + foo int +} + +func Clone(a A) A { + return A{ + true: a.true, + foo: a.foo, + } +} + +func recover() {} // ERROR "function recover has same name as predeclared identifier" diff --git a/test/testdata/predeclared_custom.go b/test/testdata/predeclared_custom.go new file mode 100644 index 000000000000..f5b6c0c89428 --- /dev/null +++ b/test/testdata/predeclared_custom.go @@ -0,0 +1,28 @@ +//args: -Epredeclared +//config_path: testdata/configs/predeclared.yml +package testdata + +func hello() { + var real int + a := A{} + copy := Clone(a) // ERROR "variable copy has same name as predeclared identifier" + + // suppress any "declared but not used" errors + _ = real + _ = a + _ = copy +} + +type A struct { + true bool // ERROR "field true has same name as predeclared identifier" + foo int +} + +func Clone(a A) A { + return A{ + true: a.true, + foo: a.foo, + } +} + +func recover() {}