github.com/chenfeining/golangci-lint@v1.0.2-0.20230730162517-14c6c67868df/pkg/golinters/goimports.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	goimportsAPI "github.com/golangci/gofmt/goimports"
     8  	"golang.org/x/tools/go/analysis"
     9  	"golang.org/x/tools/imports"
    10  
    11  	"github.com/chenfeining/golangci-lint/pkg/config"
    12  	"github.com/chenfeining/golangci-lint/pkg/golinters/goanalysis"
    13  	"github.com/chenfeining/golangci-lint/pkg/lint/linter"
    14  )
    15  
    16  const goimportsName = "goimports"
    17  
    18  func NewGoimports(settings *config.GoImportsSettings) *goanalysis.Linter {
    19  	var mu sync.Mutex
    20  	var resIssues []goanalysis.Issue
    21  
    22  	analyzer := &analysis.Analyzer{
    23  		Name: goimportsName,
    24  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    25  		Run:  goanalysis.DummyRun,
    26  	}
    27  
    28  	return goanalysis.NewLinter(
    29  		goimportsName,
    30  		"Check import statements are formatted according to the 'goimport' command. "+
    31  			"Reformat imports in autofix mode.",
    32  		[]*analysis.Analyzer{analyzer},
    33  		nil,
    34  	).WithContextSetter(func(lintCtx *linter.Context) {
    35  		imports.LocalPrefix = settings.LocalPrefixes
    36  
    37  		analyzer.Run = func(pass *analysis.Pass) (any, error) {
    38  			issues, err := runGoImports(lintCtx, pass)
    39  			if err != nil {
    40  				return nil, err
    41  			}
    42  
    43  			if len(issues) == 0 {
    44  				return nil, nil
    45  			}
    46  
    47  			mu.Lock()
    48  			resIssues = append(resIssues, issues...)
    49  			mu.Unlock()
    50  
    51  			return nil, nil
    52  		}
    53  	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    54  		return resIssues
    55  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    56  }
    57  
    58  func runGoImports(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) {
    59  	fileNames := getFileNames(pass)
    60  
    61  	var issues []goanalysis.Issue
    62  
    63  	for _, f := range fileNames {
    64  		diff, err := goimportsAPI.Run(f)
    65  		if err != nil { // TODO: skip
    66  			return nil, err
    67  		}
    68  		if diff == nil {
    69  			continue
    70  		}
    71  
    72  		is, err := extractIssuesFromPatch(string(diff), lintCtx, goimportsName)
    73  		if err != nil {
    74  			return nil, fmt.Errorf("can't extract issues from gofmt diff output %q: %w", string(diff), err)
    75  		}
    76  
    77  		for i := range is {
    78  			issues = append(issues, goanalysis.NewIssue(&is[i], pass))
    79  		}
    80  	}
    81  
    82  	return issues, nil
    83  }