github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/pkg/golinters/goconst.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	goconstAPI "github.com/jgautheron/goconst"
     8  	"golang.org/x/tools/go/analysis"
     9  
    10  	"github.com/vanstinator/golangci-lint/pkg/config"
    11  	"github.com/vanstinator/golangci-lint/pkg/golinters/goanalysis"
    12  	"github.com/vanstinator/golangci-lint/pkg/lint/linter"
    13  	"github.com/vanstinator/golangci-lint/pkg/result"
    14  )
    15  
    16  const goconstName = "goconst"
    17  
    18  //nolint:dupl
    19  func NewGoconst(settings *config.GoConstSettings) *goanalysis.Linter {
    20  	var mu sync.Mutex
    21  	var resIssues []goanalysis.Issue
    22  
    23  	analyzer := &analysis.Analyzer{
    24  		Name: goconstName,
    25  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    26  		Run: func(pass *analysis.Pass) (any, error) {
    27  			issues, err := runGoconst(pass, settings)
    28  			if err != nil {
    29  				return nil, err
    30  			}
    31  
    32  			if len(issues) == 0 {
    33  				return nil, nil
    34  			}
    35  
    36  			mu.Lock()
    37  			resIssues = append(resIssues, issues...)
    38  			mu.Unlock()
    39  
    40  			return nil, nil
    41  		},
    42  	}
    43  
    44  	return goanalysis.NewLinter(
    45  		goconstName,
    46  		"Finds repeated strings that could be replaced by a constant",
    47  		[]*analysis.Analyzer{analyzer},
    48  		nil,
    49  	).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    50  		return resIssues
    51  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    52  }
    53  
    54  func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanalysis.Issue, error) {
    55  	cfg := goconstAPI.Config{
    56  		IgnoreStrings:      settings.IgnoreStrings,
    57  		IgnoreTests:        settings.IgnoreTests,
    58  		MatchWithConstants: settings.MatchWithConstants,
    59  		MinStringLength:    settings.MinStringLen,
    60  		MinOccurrences:     settings.MinOccurrencesCount,
    61  		ParseNumbers:       settings.ParseNumbers,
    62  		NumberMin:          settings.NumberMin,
    63  		NumberMax:          settings.NumberMax,
    64  		ExcludeTypes:       map[goconstAPI.Type]bool{},
    65  	}
    66  
    67  	if settings.IgnoreCalls {
    68  		cfg.ExcludeTypes[goconstAPI.Call] = true
    69  	}
    70  
    71  	lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, &cfg)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	if len(lintIssues) == 0 {
    77  		return nil, nil
    78  	}
    79  
    80  	res := make([]goanalysis.Issue, 0, len(lintIssues))
    81  	for _, i := range lintIssues {
    82  		text := fmt.Sprintf("string %s has %d occurrences", formatCode(i.Str, nil), i.OccurrencesCount)
    83  
    84  		if i.MatchingConst == "" {
    85  			text += ", make it a constant"
    86  		} else {
    87  			text += fmt.Sprintf(", but such constant %s already exists", formatCode(i.MatchingConst, nil))
    88  		}
    89  
    90  		res = append(res, goanalysis.NewIssue(&result.Issue{
    91  			Pos:        i.Pos,
    92  			Text:       text,
    93  			FromLinter: goconstName,
    94  		}, pass))
    95  	}
    96  
    97  	return res, nil
    98  }