github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/gocognit.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync"
     7  
     8  	"github.com/uudashr/gocognit"
     9  	"golang.org/x/tools/go/analysis"
    10  
    11  	"github.com/elek/golangci-lint/pkg/golinters/goanalysis"
    12  	"github.com/elek/golangci-lint/pkg/lint/linter"
    13  	"github.com/elek/golangci-lint/pkg/result"
    14  )
    15  
    16  const gocognitName = "gocognit"
    17  
    18  func NewGocognit() *goanalysis.Linter {
    19  	var mu sync.Mutex
    20  	var resIssues []goanalysis.Issue
    21  
    22  	analyzer := &analysis.Analyzer{
    23  		Name: goanalysis.TheOnlyAnalyzerName,
    24  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    25  	}
    26  	return goanalysis.NewLinter(
    27  		gocognitName,
    28  		"Computes and checks the cognitive complexity of functions",
    29  		[]*analysis.Analyzer{analyzer},
    30  		nil,
    31  	).WithContextSetter(func(lintCtx *linter.Context) {
    32  		analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
    33  			var stats []gocognit.Stat
    34  			for _, f := range pass.Files {
    35  				stats = gocognit.ComplexityStats(f, pass.Fset, stats)
    36  			}
    37  			if len(stats) == 0 {
    38  				return nil, nil
    39  			}
    40  
    41  			sort.SliceStable(stats, func(i, j int) bool {
    42  				return stats[i].Complexity > stats[j].Complexity
    43  			})
    44  
    45  			res := make([]goanalysis.Issue, 0, len(stats))
    46  			for _, s := range stats {
    47  				if s.Complexity <= lintCtx.Settings().Gocognit.MinComplexity {
    48  					break // Break as the stats is already sorted from greatest to least
    49  				}
    50  
    51  				res = append(res, goanalysis.NewIssue(&result.Issue{
    52  					Pos: s.Pos,
    53  					Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)",
    54  						s.Complexity, formatCode(s.FuncName, lintCtx.Cfg), lintCtx.Settings().Gocognit.MinComplexity),
    55  					FromLinter: gocognitName,
    56  				}, pass))
    57  			}
    58  
    59  			mu.Lock()
    60  			resIssues = append(resIssues, res...)
    61  			mu.Unlock()
    62  
    63  			return nil, nil
    64  		}
    65  	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    66  		return resIssues
    67  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    68  }