1
0
mirror of https://github.com/mgechev/revive.git synced 2025-11-23 22:04:49 +02:00
Files
revive/config/config.go

275 lines
6.6 KiB
Go
Raw Normal View History

// Package config implements revive's configuration data structures and related methods
2020-10-29 14:11:52 +01:00
package config
2018-01-27 16:22:17 -08:00
import (
2020-10-29 14:11:52 +01:00
"errors"
2018-01-27 16:22:17 -08:00
"fmt"
"os"
2018-02-03 18:56:45 -08:00
2020-10-29 14:11:52 +01:00
"github.com/BurntSushi/toml"
"github.com/mgechev/revive/formatter"
2018-01-27 16:22:17 -08:00
"github.com/mgechev/revive/lint"
"github.com/mgechev/revive/rule"
)
var defaultRules = []lint.Rule{
&rule.VarDeclarationsRule{},
&rule.PackageCommentsRule{},
&rule.DotImportsRule{},
&rule.BlankImportsRule{},
&rule.ExportedRule{},
2018-05-26 21:28:31 -07:00
&rule.VarNamingRule{},
2018-05-26 16:14:36 -07:00
&rule.IndentErrorFlowRule{},
2018-01-27 16:22:17 -08:00
&rule.RangeRule{},
&rule.ErrorfRule{},
2018-05-26 21:28:31 -07:00
&rule.ErrorNamingRule{},
2018-01-27 16:22:17 -08:00
&rule.ErrorStringsRule{},
2018-05-26 21:28:31 -07:00
&rule.ReceiverNamingRule{},
2018-01-27 16:22:17 -08:00
&rule.IncrementDecrementRule{},
&rule.ErrorReturnRule{},
&rule.UnexportedReturnRule{},
2018-05-26 21:28:31 -07:00
&rule.TimeNamingRule{},
&rule.ContextKeysType{},
&rule.ContextAsArgumentRule{},
&rule.EmptyBlockRule{},
&rule.SuperfluousElseRule{},
&rule.UnusedParamRule{},
&rule.UnreachableCodeRule{},
&rule.RedefinesBuiltinIDRule{},
2018-01-27 16:22:17 -08:00
}
var allRules = append([]lint.Rule{
&rule.ArgumentsLimitRule{},
&rule.CyclomaticRule{},
2018-05-26 21:28:31 -07:00
&rule.FileHeaderRule{},
&rule.ConfusingNamingRule{},
&rule.GetReturnRule{},
&rule.ModifiesParamRule{},
&rule.ConfusingResultsRule{},
&rule.DeepExitRule{},
2018-07-17 21:21:27 +02:00
&rule.AddConstantRule{},
&rule.FlagParamRule{},
&rule.UnnecessaryStmtRule{},
2018-07-28 18:07:31 +02:00
&rule.StructTagRule{},
&rule.ModifiesValRecRule{},
&rule.ConstantLogicalExprRule{},
&rule.BoolLiteralRule{},
&rule.ImportsBlocklistRule{},
&rule.FunctionResultsLimitRule{},
&rule.MaxPublicStructsRule{},
&rule.RangeValInClosureRule{},
&rule.RangeValAddress{},
&rule.WaitGroupByValueRule{},
&rule.AtomicRule{},
&rule.EmptyLinesRule{},
&rule.LineLengthLimitRule{},
2018-10-31 15:32:23 +01:00
&rule.CallToGCRule{},
&rule.DuplicatedImportsRule{},
&rule.ImportShadowingRule{},
&rule.BareReturnRule{},
&rule.UnusedReceiverRule{},
&rule.UnhandledErrorRule{},
2019-12-14 08:27:06 +01:00
&rule.CognitiveComplexityRule{},
&rule.StringOfIntRule{},
&rule.StringFormatRule{},
&rule.EarlyReturnRule{},
2020-05-09 17:10:34 +02:00
&rule.UnconditionalRecursionRule{},
&rule.IdenticalBranchesRule{},
2020-05-24 20:49:49 +02:00
&rule.DeferRule{},
&rule.UnexportedNamingRule{},
2021-03-20 23:45:30 +01:00
&rule.FunctionLength{},
&rule.NestedStructs{},
2021-08-16 00:30:08 +02:00
&rule.UselessBreak{},
&rule.UncheckedTypeAssertionRule{},
2021-10-03 15:35:13 +02:00
&rule.TimeEqualRule{},
&rule.TimeDateRule{},
&rule.BannedCharsRule{},
&rule.OptimizeOperandsOrderRule{},
2022-03-29 20:25:38 +02:00
&rule.UseAnyRule{},
2022-04-18 18:45:42 +02:00
&rule.DataRaceRule{},
&rule.CommentSpacingsRule{},
Drop if-return from default ruleset (#843) The `if-return` rule was originally a golint rule which was removed from their ruleset for being out of scope. Similarly, it was dropped from revive intentionally as a result of #537. More recently, it was reintroduced into the default ruleset as a result of #799 due to a discrepancy in documentation without a discussion of whether this rule in particular belonged as a part of that default rule set. While it is no longer a goal of this project to align 100% with the golint defaults, I believe that this rule gives bad advice often enough that it should not be enabled by default. For example, consider the following code: ```go if err := func1(); err != nil { return err } if err := func2(); err != nil { return err } if err := func3(); err != nil { return err } return nil ``` The `if-return` rule considers this a violation of style, and instead suggests the following: ```go if err := func1(); err != nil { return err } if err := func2(); err != nil { return err } return func3() ``` While this is more terse, it has a few shortcomings compared to the original. In particular, it means extending the size of the diff if changing the order of checks, adding logic after the call that currently happens to be last, or choosing to wrap the error. And in that last case, it can make it less obvious that there is an unwrapped error being propagated up the call stack. This in practice has a very similar effect to disabling trailing commas; while it is not necessarily wrong as a style choice, I don't believe it warrants a position as part of the default ruleset here. See-also: https://github.com/golang/lint/issues/363
2023-06-26 12:43:19 -04:00
&rule.IfReturnRule{},
&rule.RedundantImportAlias{},
&rule.ImportAliasNamingRule{},
&rule.EnforceMapStyleRule{},
&rule.EnforceRepeatedArgTypeStyleRule{},
&rule.EnforceSliceStyleRule{},
2024-01-28 12:22:41 +01:00
&rule.MaxControlNestingRule{},
2024-04-20 10:20:56 +02:00
&rule.CommentsDensityRule{},
&rule.FileLengthLimitRule{},
2024-11-02 14:23:46 -03:00
&rule.FilenameFormatRule{},
&rule.RedundantBuildTagRule{},
&rule.UseErrorsNewRule{},
&rule.RedundantTestMainExitRule{},
&rule.UnnecessaryFormatRule{},
2018-01-27 16:22:17 -08:00
}, defaultRules...)
// allFormatters is a list of all available formatters to output the linting results.
// Keep the list sorted and in sync with available formatters in README.md.
2018-01-27 16:22:17 -08:00
var allFormatters = []lint.Formatter{
&formatter.Checkstyle{},
&formatter.Default{},
2018-05-26 13:47:13 -07:00
&formatter.Friendly{},
2018-01-27 17:01:18 -08:00
&formatter.JSON{},
&formatter.NDJSON{},
&formatter.Plain{},
2021-04-05 20:54:33 +02:00
&formatter.Sarif{},
&formatter.Stylish{},
&formatter.Unix{},
2018-01-27 16:22:17 -08:00
}
func getFormatters() map[string]lint.Formatter {
result := map[string]lint.Formatter{}
for _, f := range allFormatters {
result[f.Name()] = f
}
return result
}
// GetLintingRules yields the linting rules that must be applied by the linter
func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, error) {
2018-01-27 16:22:17 -08:00
rulesMap := map[string]lint.Rule{}
for _, r := range allRules {
rulesMap[r.Name()] = r
}
for _, r := range extraRules {
if _, ok := rulesMap[r.Name()]; ok {
continue
}
rulesMap[r.Name()] = r
}
2018-01-27 16:22:17 -08:00
var lintingRules []lint.Rule
for name, ruleConfig := range config.Rules {
actualName := actualRuleName(name)
r, ok := rulesMap[actualName]
2018-01-27 16:22:17 -08:00
if !ok {
2020-10-29 14:11:52 +01:00
return nil, fmt.Errorf("cannot find rule: %s", name)
2018-01-27 16:22:17 -08:00
}
if ruleConfig.Disabled {
continue // skip disabled rules
}
if r, ok := r.(lint.ConfigurableRule); ok {
if err := r.Configure(ruleConfig.Arguments); err != nil {
return nil, fmt.Errorf("cannot configure rule: %q: %w", name, err)
}
}
2022-04-10 11:55:13 +02:00
lintingRules = append(lintingRules, r)
2018-01-27 16:22:17 -08:00
}
2020-10-29 14:11:52 +01:00
return lintingRules, nil
2018-01-27 16:22:17 -08:00
}
func actualRuleName(name string) string {
switch name {
case "imports-blacklist":
return "imports-blocklist"
default:
return name
}
}
func parseConfig(path string, config *lint.Config) error {
file, err := os.ReadFile(path)
2018-01-27 16:22:17 -08:00
if err != nil {
return errors.New("cannot read the config file")
2018-01-27 16:22:17 -08:00
}
err = toml.Unmarshal(file, config)
2018-01-27 16:22:17 -08:00
if err != nil {
refactor: fix linting issues (#1188) * refactor: fix thelper issues test/utils_test.go:19:6 thelper test helper function should start from t.Helper() test/utils_test.go:42:6 thelper test helper function should start from t.Helper() test/utils_test.go:63:6 thelper test helper function should start from t.Helper() test/utils_test.go:146:6 thelper test helper function should start from t.Helper() * refactor: fix govet issues rule/error_strings.go:50:21 govet printf: non-constant format string in call to fmt.Errorf * refactor: fix gosimple issue rule/bare_return.go:52:9 gosimple S1016: should convert w (type lintBareReturnRule) to bareReturnFinder instead of using struct literal * refactor: fix errorlint issues lint/filefilter.go:70:86 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/filefilter.go:113:104 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/filefilter.go:125:89 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/linter.go:166:72 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/linter.go:171:73 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors config/config.go:174:57 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors config/config.go:179:64 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors * refactor: fix revive issue about comment spacing cli/main.go:31:2 revive comment-spacings: no space between comment delimiter and comment text * refactor: fix revive issue about unused-receiver revivelib/core_test.go:77:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ revivelib/core_test.go:81:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/context_as_argument.go:76:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/var_naming.go:73:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/modifies_value_receiver.go:59:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/filename_format.go:43:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ * refactor: fix revive issues about unused-parameter revivelib/core_test.go:81:24 revive unused-parameter: parameter 'file' seems to be unused, consider removing or renaming it as _ revivelib/core_test.go:81:41 revive unused-parameter: parameter 'arguments' seems to be unused, consider removing or renaming it as _ * refactor: fix gocritic issues about commentedOutCode test/utils_test.go:119:5 gocritic commentedOutCode: may want to remove commented-out code rule/unreachable_code.go:65:3 gocritic commentedOutCode: may want to remove commented-out code
2024-12-12 08:42:41 +01:00
return fmt.Errorf("cannot parse the config file: %w", err)
2018-01-27 16:22:17 -08:00
}
for k, r := range config.Rules {
err := r.Initialize()
if err != nil {
refactor: fix linting issues (#1188) * refactor: fix thelper issues test/utils_test.go:19:6 thelper test helper function should start from t.Helper() test/utils_test.go:42:6 thelper test helper function should start from t.Helper() test/utils_test.go:63:6 thelper test helper function should start from t.Helper() test/utils_test.go:146:6 thelper test helper function should start from t.Helper() * refactor: fix govet issues rule/error_strings.go:50:21 govet printf: non-constant format string in call to fmt.Errorf * refactor: fix gosimple issue rule/bare_return.go:52:9 gosimple S1016: should convert w (type lintBareReturnRule) to bareReturnFinder instead of using struct literal * refactor: fix errorlint issues lint/filefilter.go:70:86 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/filefilter.go:113:104 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/filefilter.go:125:89 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/linter.go:166:72 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors lint/linter.go:171:73 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors config/config.go:174:57 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors config/config.go:179:64 errorlint non-wrapping format verb for fmt.Errorf. Use `%w` to format errors * refactor: fix revive issue about comment spacing cli/main.go:31:2 revive comment-spacings: no space between comment delimiter and comment text * refactor: fix revive issue about unused-receiver revivelib/core_test.go:77:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ revivelib/core_test.go:81:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/context_as_argument.go:76:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/var_naming.go:73:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/modifies_value_receiver.go:59:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ rule/filename_format.go:43:7 revive unused-receiver: method receiver 'r' is not referenced in method's body, consider removing or renaming it as _ * refactor: fix revive issues about unused-parameter revivelib/core_test.go:81:24 revive unused-parameter: parameter 'file' seems to be unused, consider removing or renaming it as _ revivelib/core_test.go:81:41 revive unused-parameter: parameter 'arguments' seems to be unused, consider removing or renaming it as _ * refactor: fix gocritic issues about commentedOutCode test/utils_test.go:119:5 gocritic commentedOutCode: may want to remove commented-out code rule/unreachable_code.go:65:3 gocritic commentedOutCode: may want to remove commented-out code
2024-12-12 08:42:41 +01:00
return fmt.Errorf("error in config of rule [%s] : [%w]", k, err)
}
config.Rules[k] = r
}
return nil
2018-01-27 16:22:17 -08:00
}
func normalizeConfig(config *lint.Config) {
2021-09-30 22:37:44 +02:00
if len(config.Rules) == 0 {
config.Rules = map[string]lint.RuleConfig{}
2018-01-27 17:01:18 -08:00
}
2021-09-30 22:37:44 +02:00
if config.EnableAllRules {
// Add to the configuration all rules not yet present in it
2022-04-10 11:55:13 +02:00
for _, r := range allRules {
ruleName := r.Name()
2021-09-30 22:37:44 +02:00
_, alreadyInConf := config.Rules[ruleName]
if alreadyInConf {
continue
}
// Add the rule with an empty conf for
config.Rules[ruleName] = lint.RuleConfig{}
}
}
2018-01-27 16:22:17 -08:00
severity := config.Severity
if severity != "" {
for k, v := range config.Rules {
if v.Severity == "" {
v.Severity = severity
}
config.Rules[k] = v
}
for k, v := range config.Directives {
if v.Severity == "" {
v.Severity = severity
}
config.Directives[k] = v
}
2018-01-27 16:22:17 -08:00
}
}
const defaultConfidence = 0.8
2020-10-29 14:11:52 +01:00
// GetConfig yields the configuration
func GetConfig(configPath string) (*lint.Config, error) {
config := &lint.Config{}
switch {
case configPath != "":
config.Confidence = defaultConfidence
err := parseConfig(configPath, config)
2020-10-29 14:11:52 +01:00
if err != nil {
return nil, err
}
default: // no configuration provided
config = defaultConfig()
2018-01-27 16:22:17 -08:00
}
2018-01-27 16:22:17 -08:00
normalizeConfig(config)
2020-10-29 14:11:52 +01:00
return config, nil
2018-01-27 16:22:17 -08:00
}
2020-10-29 14:11:52 +01:00
// GetFormatter yields the formatter for lint failures
func GetFormatter(formatterName string) (lint.Formatter, error) {
2018-01-27 16:22:17 -08:00
formatters := getFormatters()
if formatterName == "" {
return formatters["default"], nil
}
f, ok := formatters[formatterName]
if !ok {
return nil, fmt.Errorf("unknown formatter %v", formatterName)
2018-01-27 16:22:17 -08:00
}
return f, nil
}
2018-01-27 16:22:17 -08:00
func defaultConfig() *lint.Config {
defaultConfig := lint.Config{
Confidence: defaultConfidence,
2018-01-27 16:22:17 -08:00
Severity: lint.SeverityWarning,
Rules: map[string]lint.RuleConfig{},
}
for _, r := range defaultRules {
defaultConfig.Rules[r.Name()] = lint.RuleConfig{}
}
return &defaultConfig
}