github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/nolintlint.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"sync"
     7  
     8  	"golang.org/x/tools/go/analysis"
     9  
    10  	"github.com/elek/golangci-lint/pkg/golinters/goanalysis"
    11  	"github.com/elek/golangci-lint/pkg/golinters/nolintlint"
    12  	"github.com/elek/golangci-lint/pkg/lint/linter"
    13  	"github.com/elek/golangci-lint/pkg/result"
    14  )
    15  
    16  const NolintlintName = "nolintlint"
    17  
    18  func NewNoLintLint() *goanalysis.Linter {
    19  	var mu sync.Mutex
    20  	var resIssues []goanalysis.Issue
    21  
    22  	analyzer := &analysis.Analyzer{
    23  		Name: NolintlintName,
    24  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    25  	}
    26  	return goanalysis.NewLinter(
    27  		NolintlintName,
    28  		"Reports ill-formed or insufficient nolint directives",
    29  		[]*analysis.Analyzer{analyzer},
    30  		nil,
    31  	).WithContextSetter(func(lintCtx *linter.Context) {
    32  		analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
    33  			var needs nolintlint.Needs
    34  			settings := lintCtx.Settings().NoLintLint
    35  			if settings.RequireExplanation {
    36  				needs |= nolintlint.NeedsExplanation
    37  			}
    38  			if !settings.AllowLeadingSpace {
    39  				needs |= nolintlint.NeedsMachineOnly
    40  			}
    41  			if settings.RequireSpecific {
    42  				needs |= nolintlint.NeedsSpecific
    43  			}
    44  			if !settings.AllowUnused {
    45  				needs |= nolintlint.NeedsUnused
    46  			}
    47  
    48  			lnt, err := nolintlint.NewLinter(needs, settings.AllowNoExplanation)
    49  			if err != nil {
    50  				return nil, err
    51  			}
    52  
    53  			nodes := make([]ast.Node, 0, len(pass.Files))
    54  			for _, n := range pass.Files {
    55  				nodes = append(nodes, n)
    56  			}
    57  			issues, err := lnt.Run(pass.Fset, nodes...)
    58  			if err != nil {
    59  				return nil, fmt.Errorf("linter failed to run: %s", err)
    60  			}
    61  			var res []goanalysis.Issue
    62  			for _, i := range issues {
    63  				expectNoLint := false
    64  				var expectedNolintLinter string
    65  				if ii, ok := i.(nolintlint.UnusedCandidate); ok {
    66  					expectedNolintLinter = ii.ExpectedLinter
    67  					expectNoLint = true
    68  				}
    69  				issue := &result.Issue{
    70  					FromLinter:           NolintlintName,
    71  					Text:                 i.Details(),
    72  					Pos:                  i.Position(),
    73  					ExpectNoLint:         expectNoLint,
    74  					ExpectedNoLintLinter: expectedNolintLinter,
    75  					Replacement:          i.Replacement(),
    76  				}
    77  				res = append(res, goanalysis.NewIssue(issue, pass))
    78  			}
    79  
    80  			if len(res) == 0 {
    81  				return nil, nil
    82  			}
    83  
    84  			mu.Lock()
    85  			resIssues = append(resIssues, res...)
    86  			mu.Unlock()
    87  
    88  			return nil, nil
    89  		}
    90  	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    91  		return resIssues
    92  	}).WithLoadMode(goanalysis.LoadModeSyntax)
    93  }