github.com/chenfeining/golangci-lint@v1.0.2-0.20230730162517-14c6c67868df/pkg/golinters/forbidigo.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/ashanbrown/forbidigo/forbidigo"
     8  	"golang.org/x/tools/go/analysis"
     9  
    10  	"github.com/chenfeining/golangci-lint/pkg/config"
    11  	"github.com/chenfeining/golangci-lint/pkg/golinters/goanalysis"
    12  	"github.com/chenfeining/golangci-lint/pkg/lint/linter"
    13  	"github.com/chenfeining/golangci-lint/pkg/logutils"
    14  	"github.com/chenfeining/golangci-lint/pkg/result"
    15  )
    16  
    17  const forbidigoName = "forbidigo"
    18  
    19  //nolint:dupl
    20  func NewForbidigo(settings *config.ForbidigoSettings) *goanalysis.Linter {
    21  	var mu sync.Mutex
    22  	var resIssues []goanalysis.Issue
    23  
    24  	analyzer := &analysis.Analyzer{
    25  		Name: forbidigoName,
    26  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    27  		Run: func(pass *analysis.Pass) (any, error) {
    28  			issues, err := runForbidigo(pass, settings)
    29  			if err != nil {
    30  				return nil, err
    31  			}
    32  
    33  			if len(issues) == 0 {
    34  				return nil, nil
    35  			}
    36  
    37  			mu.Lock()
    38  			resIssues = append(resIssues, issues...)
    39  			mu.Unlock()
    40  			return nil, nil
    41  		},
    42  	}
    43  
    44  	// Without AnalyzeTypes, LoadModeSyntax is enough.
    45  	// But we cannot make this depend on the settings and have to mirror the mode chosen in GetAllSupportedLinterConfigs,
    46  	// therefore we have to use LoadModeTypesInfo in all cases.
    47  	return goanalysis.NewLinter(
    48  		forbidigoName,
    49  		"Forbids identifiers",
    50  		[]*analysis.Analyzer{analyzer},
    51  		nil,
    52  	).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    53  		return resIssues
    54  	}).WithLoadMode(goanalysis.LoadModeTypesInfo)
    55  }
    56  
    57  func runForbidigo(pass *analysis.Pass, settings *config.ForbidigoSettings) ([]goanalysis.Issue, error) {
    58  	options := []forbidigo.Option{
    59  		forbidigo.OptionExcludeGodocExamples(settings.ExcludeGodocExamples),
    60  		// disable "//permit" directives so only "//nolint" directives matters within golangci-lint
    61  		forbidigo.OptionIgnorePermitDirectives(true),
    62  		forbidigo.OptionAnalyzeTypes(settings.AnalyzeTypes),
    63  	}
    64  
    65  	// Convert patterns back to strings because that is what NewLinter accepts.
    66  	var patterns []string
    67  	for _, pattern := range settings.Forbid {
    68  		buffer, err := pattern.MarshalString()
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  		patterns = append(patterns, string(buffer))
    73  	}
    74  
    75  	forbid, err := forbidigo.NewLinter(patterns, options...)
    76  	if err != nil {
    77  		return nil, fmt.Errorf("failed to create linter %q: %w", forbidigoName, err)
    78  	}
    79  
    80  	var issues []goanalysis.Issue
    81  	for _, file := range pass.Files {
    82  		runConfig := forbidigo.RunConfig{
    83  			Fset:     pass.Fset,
    84  			DebugLog: logutils.Debug(logutils.DebugKeyForbidigo),
    85  		}
    86  		if settings != nil && settings.AnalyzeTypes {
    87  			runConfig.TypesInfo = pass.TypesInfo
    88  		}
    89  		hints, err := forbid.RunWithConfig(runConfig, file)
    90  		if err != nil {
    91  			return nil, fmt.Errorf("forbidigo linter failed on file %q: %w", file.Name.String(), err)
    92  		}
    93  
    94  		for _, hint := range hints {
    95  			issues = append(issues, goanalysis.NewIssue(&result.Issue{
    96  				Pos:        hint.Position(),
    97  				Text:       hint.Details(),
    98  				FromLinter: forbidigoName,
    99  			}, pass))
   100  		}
   101  	}
   102  
   103  	return issues, nil
   104  }