github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/golinters/interfacer.go (about)

     1  package golinters
     2  
     3  import (
     4  	"sync"
     5  
     6  	"golang.org/x/tools/go/analysis"
     7  	"golang.org/x/tools/go/analysis/passes/buildssa"
     8  	"mvdan.cc/interfacer/check"
     9  
    10  	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
    11  	"github.com/golangci/golangci-lint/pkg/lint/linter"
    12  	"github.com/golangci/golangci-lint/pkg/result"
    13  )
    14  
    15  const interfacerName = "interfacer"
    16  
    17  func NewInterfacer() *goanalysis.Linter {
    18  	var mu sync.Mutex
    19  	var resIssues []goanalysis.Issue
    20  
    21  	analyzer := &analysis.Analyzer{
    22  		Name:     interfacerName,
    23  		Doc:      goanalysis.TheOnlyanalyzerDoc,
    24  		Requires: []*analysis.Analyzer{buildssa.Analyzer},
    25  		Run: func(pass *analysis.Pass) (interface{}, error) {
    26  			issues, err := runInterfacer(pass)
    27  			if err != nil {
    28  				return nil, err
    29  			}
    30  
    31  			if len(issues) == 0 {
    32  				return nil, nil
    33  			}
    34  
    35  			mu.Lock()
    36  			resIssues = append(resIssues, issues...)
    37  			mu.Unlock()
    38  
    39  			return nil, nil
    40  		},
    41  	}
    42  
    43  	return goanalysis.NewLinter(
    44  		interfacerName,
    45  		"Linter that suggests narrower interface types",
    46  		[]*analysis.Analyzer{analyzer},
    47  		nil,
    48  	).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    49  		return resIssues
    50  	}).WithLoadMode(goanalysis.LoadModeTypesInfo)
    51  }
    52  
    53  func runInterfacer(pass *analysis.Pass) ([]goanalysis.Issue, error) {
    54  	c := &check.Checker{}
    55  
    56  	prog := goanalysis.MakeFakeLoaderProgram(pass)
    57  	c.Program(prog)
    58  
    59  	ssa := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
    60  	ssaPkg := ssa.Pkg
    61  	c.ProgramSSA(ssaPkg.Prog)
    62  
    63  	lintIssues, err := c.Check()
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	if len(lintIssues) == 0 {
    68  		return nil, nil
    69  	}
    70  
    71  	issues := make([]goanalysis.Issue, 0, len(lintIssues))
    72  	for _, i := range lintIssues {
    73  		pos := pass.Fset.Position(i.Pos())
    74  		issues = append(issues, goanalysis.NewIssue(&result.Issue{
    75  			Pos:        pos,
    76  			Text:       i.Message(),
    77  			FromLinter: interfacerName,
    78  		}, pass))
    79  	}
    80  
    81  	return issues, nil
    82  }