github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  
     8  	"github.com/songshiyun/revive/formatter"
     9  
    10  	"github.com/BurntSushi/toml"
    11  	"github.com/songshiyun/revive/lint"
    12  	"github.com/songshiyun/revive/rule"
    13  )
    14  
    15  var defaultRules = []lint.Rule{
    16  	&rule.VarDeclarationsRule{},
    17  	&rule.PackageCommentsRule{},
    18  	&rule.DotImportsRule{},
    19  	&rule.BlankImportsRule{},
    20  	&rule.ExportedRule{},
    21  	&rule.VarNamingRule{},
    22  	&rule.IndentErrorFlowRule{},
    23  	&rule.RangeRule{},
    24  	&rule.ErrorfRule{},
    25  	&rule.ErrorNamingRule{},
    26  	&rule.ErrorStringsRule{},
    27  	&rule.ReceiverNamingRule{},
    28  	&rule.IncrementDecrementRule{},
    29  	&rule.ErrorReturnRule{},
    30  	&rule.UnexportedReturnRule{},
    31  	&rule.TimeNamingRule{},
    32  	&rule.ContextKeysType{},
    33  	&rule.ContextAsArgumentRule{},
    34  }
    35  
    36  var allRules = append([]lint.Rule{
    37  	&rule.ArgumentsLimitRule{},
    38  	&rule.CyclomaticRule{},
    39  	&rule.FileHeaderRule{},
    40  	&rule.EmptyBlockRule{},
    41  	&rule.SuperfluousElseRule{},
    42  	&rule.ConfusingNamingRule{},
    43  	&rule.GetReturnRule{},
    44  	&rule.ModifiesParamRule{},
    45  	&rule.ConfusingResultsRule{},
    46  	&rule.DeepExitRule{},
    47  	&rule.UnusedParamRule{},
    48  	&rule.UnreachableCodeRule{},
    49  	&rule.AddConstantRule{},
    50  	&rule.FlagParamRule{},
    51  	&rule.UnnecessaryStmtRule{},
    52  	&rule.StructTagRule{},
    53  	&rule.ModifiesValRecRule{},
    54  	&rule.ConstantLogicalExprRule{},
    55  	&rule.BoolLiteralRule{},
    56  	&rule.RedefinesBuiltinIDRule{},
    57  	&rule.ImportsBlacklistRule{},
    58  	&rule.FunctionResultsLimitRule{},
    59  	&rule.MaxPublicStructsRule{},
    60  	&rule.RangeValInClosureRule{},
    61  	&rule.RangeValAddress{},
    62  	&rule.WaitGroupByValueRule{},
    63  	&rule.AtomicRule{},
    64  	&rule.EmptyLinesRule{},
    65  	&rule.LineLengthLimitRule{},
    66  	&rule.CallToGCRule{},
    67  	&rule.DuplicatedImportsRule{},
    68  	&rule.ImportShadowingRule{},
    69  	&rule.BareReturnRule{},
    70  	&rule.UnusedReceiverRule{},
    71  	&rule.UnhandledErrorRule{},
    72  	&rule.CognitiveComplexityRule{},
    73  	&rule.StringOfIntRule{},
    74  	&rule.StringFormatRule{},
    75  	&rule.EarlyReturnRule{},
    76  	&rule.UnconditionalRecursionRule{},
    77  	&rule.IdenticalBranchesRule{},
    78  	&rule.DeferRule{},
    79  	&rule.UnexportedNamingRule{},
    80  	&rule.FunctionLength{},
    81  	&rule.NestedStructs{},
    82  	&rule.IfReturnRule{},
    83  	&rule.UselessBreak{},
    84  	&rule.TimeEqualRule{},
    85  	&rule.BannedCharsRule{},
    86  	&rule.OptimizeOperandsOrderRule{},
    87  }, defaultRules...)
    88  
    89  var allFormatters = []lint.Formatter{
    90  	&formatter.Stylish{},
    91  	&formatter.Friendly{},
    92  	&formatter.JSON{},
    93  	&formatter.NDJSON{},
    94  	&formatter.Default{},
    95  	&formatter.Unix{},
    96  	&formatter.Checkstyle{},
    97  	&formatter.Plain{},
    98  	&formatter.Sarif{},
    99  }
   100  
   101  func getFormatters() map[string]lint.Formatter {
   102  	result := map[string]lint.Formatter{}
   103  	for _, f := range allFormatters {
   104  		result[f.Name()] = f
   105  	}
   106  	return result
   107  }
   108  
   109  // GetLintingRules yields the linting rules that must be applied by the linter
   110  func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, error) {
   111  	rulesMap := map[string]lint.Rule{}
   112  	for _, r := range allRules {
   113  		rulesMap[r.Name()] = r
   114  	}
   115  	for _, r := range extraRules {
   116  		if _, ok := rulesMap[r.Name()]; ok {
   117  			continue
   118  		}
   119  		rulesMap[r.Name()] = r
   120  	}
   121  
   122  	var lintingRules []lint.Rule
   123  	for name, ruleConfig := range config.Rules {
   124  		rule, ok := rulesMap[name]
   125  		if !ok {
   126  			return nil, fmt.Errorf("cannot find rule: %s", name)
   127  		}
   128  
   129  		if ruleConfig.Disabled {
   130  			continue // skip disabled rules
   131  		}
   132  
   133  		lintingRules = append(lintingRules, rule)
   134  	}
   135  
   136  	return lintingRules, nil
   137  }
   138  
   139  func parseConfig(path string, config *lint.Config) error {
   140  	file, err := ioutil.ReadFile(path)
   141  	if err != nil {
   142  		return errors.New("cannot read the config file")
   143  	}
   144  	_, err = toml.Decode(string(file), config)
   145  	if err != nil {
   146  		return fmt.Errorf("cannot parse the config file: %v", err)
   147  	}
   148  	return nil
   149  }
   150  
   151  func normalizeConfig(config *lint.Config) {
   152  	if len(config.Rules) == 0 {
   153  		config.Rules = map[string]lint.RuleConfig{}
   154  	}
   155  	if config.EnableAllRules {
   156  		// Add to the configuration all rules not yet present in it
   157  		for _, rule := range allRules {
   158  			ruleName := rule.Name()
   159  			_, alreadyInConf := config.Rules[ruleName]
   160  			if alreadyInConf {
   161  				continue
   162  			}
   163  			// Add the rule with an empty conf for
   164  			config.Rules[ruleName] = lint.RuleConfig{}
   165  		}
   166  	}
   167  
   168  	severity := config.Severity
   169  	if severity != "" {
   170  		for k, v := range config.Rules {
   171  			if v.Severity == "" {
   172  				v.Severity = severity
   173  			}
   174  			config.Rules[k] = v
   175  		}
   176  		for k, v := range config.Directives {
   177  			if v.Severity == "" {
   178  				v.Severity = severity
   179  			}
   180  			config.Directives[k] = v
   181  		}
   182  	}
   183  }
   184  
   185  const defaultConfidence = 0.8
   186  
   187  func LoadDefaultConfig(data []byte) (*lint.Config, error) {
   188  	config := &lint.Config{}
   189  	config.Confidence = defaultConfidence
   190  	_, err := toml.Decode(string(data), config)
   191  	if err != nil {
   192  		return nil, fmt.Errorf("cannot parse the config file: %v", err)
   193  	}
   194  	normalizeConfig(config)
   195  	return config, err
   196  }
   197  
   198  // GetConfig yields the configuration
   199  func GetConfig(configPath string) (*lint.Config, error) {
   200  	config := &lint.Config{}
   201  	switch {
   202  	case configPath != "":
   203  		config.Confidence = defaultConfidence
   204  		err := parseConfig(configPath, config)
   205  		if err != nil {
   206  			return nil, err
   207  		}
   208  
   209  	default: // no configuration provided
   210  		config = defaultConfig()
   211  	}
   212  
   213  	normalizeConfig(config)
   214  	return config, nil
   215  }
   216  
   217  // GetFormatter yields the formatter for lint failures
   218  func GetFormatter(formatterName string) (lint.Formatter, error) {
   219  	formatters := getFormatters()
   220  	formatter := formatters["default"]
   221  	if formatterName != "" {
   222  		f, ok := formatters[formatterName]
   223  		if !ok {
   224  			return nil, fmt.Errorf("unknown formatter %v", formatterName)
   225  		}
   226  		formatter = f
   227  	}
   228  	return formatter, nil
   229  }
   230  
   231  func defaultConfig() *lint.Config {
   232  	defaultConfig := lint.Config{
   233  		Confidence: defaultConfidence,
   234  		Severity:   lint.SeverityWarning,
   235  		Rules:      map[string]lint.RuleConfig{},
   236  	}
   237  	for _, r := range defaultRules {
   238  		defaultConfig.Rules[r.Name()] = lint.RuleConfig{}
   239  	}
   240  	return &defaultConfig
   241  }