github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/whitespace.go (about) 1 package golinters 2 3 import ( 4 "go/token" 5 "sync" 6 7 "github.com/pkg/errors" 8 "github.com/ultraware/whitespace" 9 "golang.org/x/tools/go/analysis" 10 11 "github.com/elek/golangci-lint/pkg/golinters/goanalysis" 12 "github.com/elek/golangci-lint/pkg/lint/linter" 13 "github.com/elek/golangci-lint/pkg/result" 14 ) 15 16 func NewWhitespace() *goanalysis.Linter { 17 const linterName = "whitespace" 18 var mu sync.Mutex 19 var resIssues []goanalysis.Issue 20 21 analyzer := &analysis.Analyzer{ 22 Name: linterName, 23 Doc: goanalysis.TheOnlyanalyzerDoc, 24 } 25 return goanalysis.NewLinter( 26 linterName, 27 "Tool for detection of leading and trailing whitespace", 28 []*analysis.Analyzer{analyzer}, 29 nil, 30 ).WithContextSetter(func(lintCtx *linter.Context) { 31 cfg := lintCtx.Cfg.LintersSettings.Whitespace 32 settings := whitespace.Settings{MultiIf: cfg.MultiIf, MultiFunc: cfg.MultiFunc} 33 34 analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { 35 var issues []whitespace.Message 36 for _, file := range pass.Files { 37 issues = append(issues, whitespace.Run(file, pass.Fset, settings)...) 38 } 39 40 if len(issues) == 0 { 41 return nil, nil 42 } 43 44 res := make([]goanalysis.Issue, len(issues)) 45 for k, i := range issues { 46 issue := result.Issue{ 47 Pos: token.Position{ 48 Filename: i.Pos.Filename, 49 Line: i.Pos.Line, 50 }, 51 LineRange: &result.Range{From: i.Pos.Line, To: i.Pos.Line}, 52 Text: i.Message, 53 FromLinter: linterName, 54 Replacement: &result.Replacement{}, 55 } 56 57 bracketLine, err := lintCtx.LineCache.GetLine(issue.Pos.Filename, issue.Pos.Line) 58 if err != nil { 59 return nil, errors.Wrapf(err, "failed to get line %s:%d", issue.Pos.Filename, issue.Pos.Line) 60 } 61 62 switch i.Type { 63 case whitespace.MessageTypeLeading: 64 issue.LineRange.To++ // cover two lines by the issue: opening bracket "{" (issue.Pos.Line) and following empty line 65 case whitespace.MessageTypeTrailing: 66 issue.LineRange.From-- // cover two lines by the issue: closing bracket "}" (issue.Pos.Line) and preceding empty line 67 issue.Pos.Line-- // set in sync with LineRange.From to not break fixer and other code features 68 case whitespace.MessageTypeAddAfter: 69 bracketLine += "\n" 70 } 71 issue.Replacement.NewLines = []string{bracketLine} 72 73 res[k] = goanalysis.NewIssue(&issue, pass) 74 } 75 76 mu.Lock() 77 resIssues = append(resIssues, res...) 78 mu.Unlock() 79 80 return nil, nil 81 } 82 }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { 83 return resIssues 84 }).WithLoadMode(goanalysis.LoadModeSyntax) 85 }