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

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"go/token"
     6  	"sync"
     7  
     8  	duplAPI "github.com/golangci/dupl"
     9  	"github.com/pkg/errors"
    10  	"golang.org/x/tools/go/analysis"
    11  
    12  	"github.com/golangci/golangci-lint/pkg/config"
    13  	"github.com/golangci/golangci-lint/pkg/fsutils"
    14  	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
    15  	"github.com/golangci/golangci-lint/pkg/lint/linter"
    16  	"github.com/golangci/golangci-lint/pkg/result"
    17  )
    18  
    19  const duplName = "dupl"
    20  
    21  //nolint:dupl
    22  func NewDupl(settings *config.DuplSettings) *goanalysis.Linter {
    23  	var mu sync.Mutex
    24  	var resIssues []goanalysis.Issue
    25  
    26  	analyzer := &analysis.Analyzer{
    27  		Name: duplName,
    28  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    29  		Run: func(pass *analysis.Pass) (interface{}, error) {
    30  			issues, err := runDupl(pass, settings)
    31  			if err != nil {
    32  				return nil, err
    33  			}
    34  
    35  			if len(issues) == 0 {
    36  				return nil, nil
    37  			}
    38  
    39  			mu.Lock()
    40  			resIssues = append(resIssues, issues...)
    41  			mu.Unlock()
    42  
    43  			return nil, nil
    44  		},
    45  	}
    46  
    47  	return goanalysis.NewLinter(
    48  		duplName,
    49  		"Tool for code clone detection",
    50  		[]*analysis.Analyzer{analyzer},
    51  		nil,
    52  	).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    53  		return resIssues
    54  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    55  }
    56  
    57  func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]goanalysis.Issue, error) {
    58  	fileNames := getFileNames(pass)
    59  
    60  	issues, err := duplAPI.Run(fileNames, settings.Threshold)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	if len(issues) == 0 {
    66  		return nil, nil
    67  	}
    68  
    69  	res := make([]goanalysis.Issue, 0, len(issues))
    70  
    71  	for _, i := range issues {
    72  		toFilename, err := fsutils.ShortestRelPath(i.To.Filename(), "")
    73  		if err != nil {
    74  			return nil, errors.Wrapf(err, "failed to get shortest rel path for %q", i.To.Filename())
    75  		}
    76  
    77  		dupl := fmt.Sprintf("%s:%d-%d", toFilename, i.To.LineStart(), i.To.LineEnd())
    78  		text := fmt.Sprintf("%d-%d lines are duplicate of %s",
    79  			i.From.LineStart(), i.From.LineEnd(),
    80  			formatCode(dupl, nil))
    81  
    82  		res = append(res, goanalysis.NewIssue(&result.Issue{
    83  			Pos: token.Position{
    84  				Filename: i.From.Filename(),
    85  				Line:     i.From.LineStart(),
    86  			},
    87  			LineRange: &result.Range{
    88  				From: i.From.LineStart(),
    89  				To:   i.From.LineEnd(),
    90  			},
    91  			Text:       text,
    92  			FromLinter: duplName,
    93  		}, pass))
    94  	}
    95  
    96  	return res, nil
    97  }