github.com/nozzle/golangci-lint@v1.49.0-nz3/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/golangci/golangci-lint/pkg/config"
    12  	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
    13  	"github.com/golangci/golangci-lint/pkg/lint/linter"
    14  	"github.com/golangci/golangci-lint/pkg/result"
    15  )
    16  
    17  const gocognitName = "gocognit"
    18  
    19  //nolint:dupl
    20  func NewGocognit(settings *config.GocognitSettings) *goanalysis.Linter {
    21  	var mu sync.Mutex
    22  	var resIssues []goanalysis.Issue
    23  
    24  	analyzer := &analysis.Analyzer{
    25  		Name: goanalysis.TheOnlyAnalyzerName,
    26  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    27  		Run: func(pass *analysis.Pass) (interface{}, error) {
    28  			issues := runGocognit(pass, settings)
    29  
    30  			if len(issues) == 0 {
    31  				return nil, nil
    32  			}
    33  
    34  			mu.Lock()
    35  			resIssues = append(resIssues, issues...)
    36  			mu.Unlock()
    37  
    38  			return nil, nil
    39  		},
    40  	}
    41  
    42  	return goanalysis.NewLinter(
    43  		gocognitName,
    44  		"Computes and checks the cognitive complexity of functions",
    45  		[]*analysis.Analyzer{analyzer},
    46  		nil,
    47  	).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    48  		return resIssues
    49  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    50  }
    51  
    52  func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []goanalysis.Issue {
    53  	var stats []gocognit.Stat
    54  	for _, f := range pass.Files {
    55  		stats = gocognit.ComplexityStats(f, pass.Fset, stats)
    56  	}
    57  	if len(stats) == 0 {
    58  		return nil
    59  	}
    60  
    61  	sort.SliceStable(stats, func(i, j int) bool {
    62  		return stats[i].Complexity > stats[j].Complexity
    63  	})
    64  
    65  	issues := make([]goanalysis.Issue, 0, len(stats))
    66  	for _, s := range stats {
    67  		if s.Complexity <= settings.MinComplexity {
    68  			break // Break as the stats is already sorted from greatest to least
    69  		}
    70  
    71  		issues = append(issues, goanalysis.NewIssue(&result.Issue{
    72  			Pos: s.Pos,
    73  			Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)",
    74  				s.Complexity, formatCode(s.FuncName, nil), settings.MinComplexity),
    75  			FromLinter: gocognitName,
    76  		}, pass))
    77  	}
    78  
    79  	return issues
    80  }