github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/pkg/golinters/whitespace.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/ultraware/whitespace"
     8  	"golang.org/x/tools/go/analysis"
     9  
    10  	"github.com/vanstinator/golangci-lint/pkg/config"
    11  	"github.com/vanstinator/golangci-lint/pkg/golinters/goanalysis"
    12  	"github.com/vanstinator/golangci-lint/pkg/lint/linter"
    13  	"github.com/vanstinator/golangci-lint/pkg/result"
    14  )
    15  
    16  const whitespaceName = "whitespace"
    17  
    18  func NewWhitespace(settings *config.WhitespaceSettings) *goanalysis.Linter {
    19  	var mu sync.Mutex
    20  	var resIssues []goanalysis.Issue
    21  
    22  	var wsSettings whitespace.Settings
    23  	if settings != nil {
    24  		wsSettings = whitespace.Settings{
    25  			Mode:      whitespace.RunningModeGolangCI,
    26  			MultiIf:   settings.MultiIf,
    27  			MultiFunc: settings.MultiFunc,
    28  		}
    29  	}
    30  
    31  	a := whitespace.NewAnalyzer(&wsSettings)
    32  
    33  	return goanalysis.NewLinter(
    34  		a.Name,
    35  		a.Doc,
    36  		[]*analysis.Analyzer{a},
    37  		nil,
    38  	).WithContextSetter(func(lintCtx *linter.Context) {
    39  		a.Run = func(pass *analysis.Pass) (any, error) {
    40  			issues, err := runWhitespace(pass, wsSettings)
    41  			if err != nil {
    42  				return nil, err
    43  			}
    44  
    45  			if len(issues) == 0 {
    46  				return nil, nil
    47  			}
    48  
    49  			mu.Lock()
    50  			resIssues = append(resIssues, issues...)
    51  			mu.Unlock()
    52  
    53  			return nil, nil
    54  		}
    55  	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    56  		return resIssues
    57  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    58  }
    59  
    60  func runWhitespace(pass *analysis.Pass, wsSettings whitespace.Settings) ([]goanalysis.Issue, error) {
    61  	lintIssues := whitespace.Run(pass, &wsSettings)
    62  
    63  	issues := make([]goanalysis.Issue, len(lintIssues))
    64  	for i, issue := range lintIssues {
    65  		report := &result.Issue{
    66  			FromLinter: whitespaceName,
    67  			Pos:        pass.Fset.PositionFor(issue.Diagnostic, false),
    68  			Text:       issue.Message,
    69  		}
    70  
    71  		switch issue.MessageType {
    72  		case whitespace.MessageTypeRemove:
    73  			if len(issue.LineNumbers) == 0 {
    74  				continue
    75  			}
    76  
    77  			report.LineRange = &result.Range{
    78  				From: issue.LineNumbers[0],
    79  				To:   issue.LineNumbers[len(issue.LineNumbers)-1],
    80  			}
    81  
    82  			report.Replacement = &result.Replacement{NeedOnlyDelete: true}
    83  
    84  		case whitespace.MessageTypeAdd:
    85  			report.Pos = pass.Fset.PositionFor(issue.FixStart, false)
    86  			report.Replacement = &result.Replacement{
    87  				Inline: &result.InlineFix{
    88  					StartCol:  0,
    89  					Length:    1,
    90  					NewString: "\n\t",
    91  				},
    92  			}
    93  
    94  		default:
    95  			return nil, fmt.Errorf("unknown message type: %v", issue.MessageType)
    96  		}
    97  
    98  		issues[i] = goanalysis.NewIssue(report, pass)
    99  	}
   100  
   101  	return issues, nil
   102  }