1package golinters
2
3import (
4	"sync"
5
6	"github.com/bombsimon/wsl/v3"
7	"golang.org/x/tools/go/analysis"
8
9	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
10	"github.com/golangci/golangci-lint/pkg/lint/linter"
11	"github.com/golangci/golangci-lint/pkg/result"
12)
13
14const (
15	name = "wsl"
16)
17
18// NewWSL returns a new WSL linter.
19func NewWSL() *goanalysis.Linter {
20	var (
21		issues   []goanalysis.Issue
22		mu       = sync.Mutex{}
23		analyzer = &analysis.Analyzer{
24			Name: goanalysis.TheOnlyAnalyzerName,
25			Doc:  goanalysis.TheOnlyanalyzerDoc,
26		}
27	)
28
29	return goanalysis.NewLinter(
30		name,
31		"Whitespace Linter - Forces you to use empty lines!",
32		[]*analysis.Analyzer{analyzer},
33		nil,
34	).WithContextSetter(func(lintCtx *linter.Context) {
35		analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
36			var (
37				files        = []string{}
38				linterCfg    = lintCtx.Cfg.LintersSettings.WSL
39				processorCfg = wsl.Configuration{
40					StrictAppend:                     linterCfg.StrictAppend,
41					AllowAssignAndCallCuddle:         linterCfg.AllowAssignAndCallCuddle,
42					AllowMultiLineAssignCuddle:       linterCfg.AllowMultiLineAssignCuddle,
43					AllowCuddleDeclaration:           linterCfg.AllowCuddleDeclaration,
44					AllowTrailingComment:             linterCfg.AllowTrailingComment,
45					AllowSeparatedLeadingComment:     linterCfg.AllowSeparatedLeadingComment,
46					ForceCuddleErrCheckAndAssign:     linterCfg.ForceCuddleErrCheckAndAssign,
47					ForceCaseTrailingWhitespaceLimit: linterCfg.ForceCaseTrailingWhitespaceLimit,
48					AllowCuddleWithCalls:             []string{"Lock", "RLock"},
49					AllowCuddleWithRHS:               []string{"Unlock", "RUnlock"},
50					ErrorVariableNames:               []string{"err"},
51				}
52			)
53
54			for _, file := range pass.Files {
55				files = append(files, pass.Fset.PositionFor(file.Pos(), false).Filename)
56			}
57
58			wslErrors, _ := wsl.NewProcessorWithConfig(processorCfg).
59				ProcessFiles(files)
60
61			if len(wslErrors) == 0 {
62				return nil, nil
63			}
64
65			mu.Lock()
66			defer mu.Unlock()
67
68			for _, err := range wslErrors {
69				issues = append(issues, goanalysis.NewIssue(&result.Issue{
70					FromLinter: name,
71					Pos:        err.Position,
72					Text:       err.Reason,
73				}, pass))
74			}
75
76			return nil, nil
77		}
78	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
79		return issues
80	}).WithLoadMode(goanalysis.LoadModeSyntax)
81}
82