1package golinters // nolint:dupl
2
3import (
4	"fmt"
5	"sync"
6
7	structcheckAPI "github.com/golangci/check/cmd/structcheck"
8	"golang.org/x/tools/go/analysis"
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
15func NewStructcheck() *goanalysis.Linter {
16	const linterName = "structcheck"
17	var mu sync.Mutex
18	var res []goanalysis.Issue
19	analyzer := &analysis.Analyzer{
20		Name: linterName,
21		Doc:  goanalysis.TheOnlyanalyzerDoc,
22	}
23	return goanalysis.NewLinter(
24		linterName,
25		"Finds unused struct fields",
26		[]*analysis.Analyzer{analyzer},
27		nil,
28	).WithContextSetter(func(lintCtx *linter.Context) {
29		checkExported := lintCtx.Settings().Structcheck.CheckExportedFields
30		analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
31			prog := goanalysis.MakeFakeLoaderProgram(pass)
32
33			structcheckIssues := structcheckAPI.Run(prog, checkExported)
34			if len(structcheckIssues) == 0 {
35				return nil, nil
36			}
37
38			issues := make([]goanalysis.Issue, 0, len(structcheckIssues))
39			for _, i := range structcheckIssues {
40				issues = append(issues, goanalysis.NewIssue(&result.Issue{
41					Pos:        i.Pos,
42					Text:       fmt.Sprintf("%s is unused", formatCode(i.FieldName, lintCtx.Cfg)),
43					FromLinter: linterName,
44				}, pass))
45			}
46
47			mu.Lock()
48			res = append(res, issues...)
49			mu.Unlock()
50			return nil, nil
51		}
52	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
53		return res
54	}).WithLoadMode(goanalysis.LoadModeTypesInfo)
55}
56