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

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"golang.org/x/tools/go/analysis"
     8  	"honnef.co/go/tools/unused"
     9  
    10  	"github.com/golangci/golangci-lint/pkg/config"
    11  	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
    12  	"github.com/golangci/golangci-lint/pkg/lint/linter"
    13  	"github.com/golangci/golangci-lint/pkg/result"
    14  )
    15  
    16  const unusedName = "unused"
    17  
    18  type UnusedSettings struct {
    19  	GoVersion string
    20  }
    21  
    22  func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
    23  	var mu sync.Mutex
    24  	var resIssues []goanalysis.Issue
    25  
    26  	analyzer := &analysis.Analyzer{
    27  		Name:     unusedName,
    28  		Doc:      unused.Analyzer.Analyzer.Doc,
    29  		Requires: unused.Analyzer.Analyzer.Requires,
    30  		Run: func(pass *analysis.Pass) (interface{}, error) {
    31  			issues, err := runUnused(pass)
    32  			if err != nil {
    33  				return nil, err
    34  			}
    35  
    36  			if len(issues) == 0 {
    37  				return nil, nil
    38  			}
    39  
    40  			mu.Lock()
    41  			resIssues = append(resIssues, issues...)
    42  			mu.Unlock()
    43  
    44  			return nil, nil
    45  		},
    46  	}
    47  
    48  	setAnalyzerGoVersion(analyzer, getGoVersion(settings))
    49  
    50  	return goanalysis.NewLinter(
    51  		unusedName,
    52  		"Checks Go code for unused constants, variables, functions and types",
    53  		[]*analysis.Analyzer{analyzer},
    54  		nil,
    55  	).WithIssuesReporter(func(lintCtx *linter.Context) []goanalysis.Issue {
    56  		return resIssues
    57  	}).WithLoadMode(goanalysis.LoadModeTypesInfo)
    58  }
    59  
    60  func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) {
    61  	res, err := unused.Analyzer.Analyzer.Run(pass)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	sr := unused.Serialize(pass, res.(unused.Result), pass.Fset)
    67  
    68  	used := make(map[string]bool)
    69  	for _, obj := range sr.Used {
    70  		used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true
    71  	}
    72  
    73  	var issues []goanalysis.Issue
    74  
    75  	// Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197
    76  	for _, object := range sr.Unused {
    77  		if object.Kind == "type param" {
    78  			continue
    79  		}
    80  
    81  		if object.InGenerated {
    82  			continue
    83  		}
    84  
    85  		key := fmt.Sprintf("%s %d %s", object.Position.Filename, object.Position.Line, object.Name)
    86  		if used[key] {
    87  			continue
    88  		}
    89  
    90  		issue := goanalysis.NewIssue(&result.Issue{
    91  			FromLinter: unusedName,
    92  			Text:       fmt.Sprintf("%s %s is unused", object.Kind, object.Name),
    93  			Pos:        object.Position,
    94  		}, pass)
    95  
    96  		issues = append(issues, issue)
    97  	}
    98  
    99  	return issues, nil
   100  }