unused: support passing in options (#4086)

Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
Fata Nugraha 2023-10-09 23:45:29 +08:00 committed by GitHub
parent 69d6cc93cb
commit bce3dfd460
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 25 deletions

View File

@ -2016,6 +2016,29 @@ linters-settings:
# Default: false
check-exported: true
unused:
# Mark all struct fields that have been written to as used.
# Default: true
field-writes-are-uses: false
# Treat IncDec statement (e.g. `i++` or `i--`) as both read and write operation instead of just write.
# Default: false
post-statements-are-reads: true
# Mark all exported identifiers as used.
# Default: true
exported-is-used: false
# Mark all exported fields as used.
# default: true
exported-fields-are-used: false
# Mark all function parameters as used.
# default: true
parameters-are-used: false
# Mark all local variables as used.
# default: true
local-variables-are-used: false
# Mark all identifiers inside generated files as used.
# Default: true
generated-is-used: false
varcheck:
# Check usage of exported fields and variables.
# Default: false

View File

@ -126,6 +126,15 @@ var defaultLintersSettings = LintersSettings{
Unparam: UnparamSettings{
Algo: "cha",
},
Unused: UnusedSettings{
FieldWritesAreUses: true,
PostStatementsAreReads: false,
ExportedIsUsed: true,
ExportedFieldsAreUsed: true,
ParametersAreUsed: true,
LocalVariablesAreUsed: true,
GeneratedIsUsed: true,
},
UseStdlibVars: UseStdlibVarsSettings{
HTTPMethod: true,
HTTPStatusCode: true,
@ -223,6 +232,7 @@ type LintersSettings struct {
Testpackage TestpackageSettings
Thelper ThelperSettings
Unparam UnparamSettings
Unused UnusedSettings
UseStdlibVars UseStdlibVarsSettings
Varcheck VarCheckSettings
Varnamelen VarnamelenSettings
@ -794,6 +804,16 @@ type UnparamSettings struct {
Algo string
}
type UnusedSettings struct {
FieldWritesAreUses bool `mapstructure:"field-writes-are-uses"`
PostStatementsAreReads bool `mapstructure:"post-statements-are-reads"`
ExportedIsUsed bool `mapstructure:"exported-is-used"`
ExportedFieldsAreUsed bool `mapstructure:"exported-fields-are-used"`
ParametersAreUsed bool `mapstructure:"parameters-are-used"`
LocalVariablesAreUsed bool `mapstructure:"local-variables-are-used"`
GeneratedIsUsed bool `mapstructure:"generated-is-used"`
}
type VarCheckSettings struct {
CheckExportedFields bool `mapstructure:"exported-fields"`
}

View File

@ -5,6 +5,9 @@ import (
"sync"
"golang.org/x/tools/go/analysis"
"honnef.co/go/tools/analysis/facts/directives"
"honnef.co/go/tools/analysis/facts/generated"
"honnef.co/go/tools/analysis/lint"
"honnef.co/go/tools/unused"
"github.com/golangci/golangci-lint/pkg/config"
@ -15,11 +18,7 @@ import (
const unusedName = "unused"
type UnusedSettings struct {
GoVersion string
}
func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
func NewUnused(settings *config.UnusedSettings, scSettings *config.StaticCheckSettings) *goanalysis.Linter {
var mu sync.Mutex
var resIssues []goanalysis.Issue
@ -28,11 +27,7 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
Doc: unused.Analyzer.Analyzer.Doc,
Requires: unused.Analyzer.Analyzer.Requires,
Run: func(pass *analysis.Pass) (any, error) {
issues, err := runUnused(pass)
if err != nil {
return nil, err
}
issues := runUnused(pass, settings)
if len(issues) == 0 {
return nil, nil
}
@ -45,7 +40,7 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
},
}
setAnalyzerGoVersion(analyzer, getGoVersion(settings))
setAnalyzerGoVersion(analyzer, getGoVersion(scSettings))
return goanalysis.NewLinter(
unusedName,
@ -57,21 +52,18 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
}
func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) {
res, err := unused.Analyzer.Analyzer.Run(pass)
if err != nil {
return nil, err
}
func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []goanalysis.Issue {
res := getUnusedResults(pass, cfg)
used := make(map[string]bool)
for _, obj := range res.(unused.Result).Used {
for _, obj := range res.Used {
used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true
}
var issues []goanalysis.Issue
// Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197
for _, object := range res.(unused.Result).Unused {
for _, object := range res.Unused {
if object.Kind == "type param" {
continue
}
@ -90,5 +82,31 @@ func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) {
issues = append(issues, issue)
}
return issues, nil
return issues
}
func getUnusedResults(pass *analysis.Pass, settings *config.UnusedSettings) unused.Result {
opts := unused.Options{
FieldWritesAreUses: settings.FieldWritesAreUses,
PostStatementsAreReads: settings.PostStatementsAreReads,
ExportedIsUsed: settings.ExportedIsUsed,
ExportedFieldsAreUsed: settings.ExportedFieldsAreUsed,
ParametersAreUsed: settings.ParametersAreUsed,
LocalVariablesAreUsed: settings.LocalVariablesAreUsed,
GeneratedIsUsed: settings.GeneratedIsUsed,
}
// ref: https://github.com/dominikh/go-tools/blob/4ec1f474ca6c0feb8e10a8fcca4ab95f5b5b9881/internal/cmd/unused/unused.go#L68
nodes := unused.Graph(pass.Fset,
pass.Files,
pass.Pkg,
pass.TypesInfo,
pass.ResultOf[directives.Analyzer].([]lint.Directive),
pass.ResultOf[generated.Analyzer].(map[string]generated.Generator),
opts,
)
sg := unused.SerializedGraph{}
sg.Merge(nodes)
return sg.Results()
}

View File

@ -137,7 +137,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
testpackageCfg *config.TestpackageSettings
thelperCfg *config.ThelperSettings
unparamCfg *config.UnparamSettings
unusedCfg *config.StaticCheckSettings
unusedCfg *config.UnusedSettings
usestdlibvars *config.UseStdlibVarsSettings
varcheckCfg *config.VarCheckSettings
varnamelenCfg *config.VarnamelenSettings
@ -218,7 +218,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
testpackageCfg = &m.cfg.LintersSettings.Testpackage
thelperCfg = &m.cfg.LintersSettings.Thelper
unparamCfg = &m.cfg.LintersSettings.Unparam
unusedCfg = new(config.StaticCheckSettings)
unusedCfg = &m.cfg.LintersSettings.Unused
usestdlibvars = &m.cfg.LintersSettings.UseStdlibVars
varcheckCfg = &m.cfg.LintersSettings.Varcheck
varnamelenCfg = &m.cfg.LintersSettings.Varnamelen
@ -247,9 +247,6 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
if stylecheckCfg != nil && stylecheckCfg.GoVersion != "" {
stylecheckCfg.GoVersion = trimGoVersion(m.cfg.Run.Go)
}
if unusedCfg != nil && unusedCfg.GoVersion == "" {
unusedCfg.GoVersion = trimGoVersion(m.cfg.Run.Go)
}
}
const megacheckName = "megacheck"
@ -846,7 +843,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithLoadForGoAnalysis().
WithURL("https://github.com/mvdan/unparam"),
linter.NewConfig(golinters.NewUnused(unusedCfg)).
linter.NewConfig(golinters.NewUnused(unusedCfg, staticcheckCfg)).
WithEnabledByDefault().
WithSince("v1.20.0").
WithLoadForGoAnalysis().