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

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"sync"
     7  
     8  	"github.com/OpenPeeDeeP/depguard"
     9  	"golang.org/x/tools/go/analysis"
    10  	"golang.org/x/tools/go/loader" //nolint:staticcheck // require changes in github.com/OpenPeeDeeP/depguard
    11  
    12  	"github.com/elek/golangci-lint/pkg/golinters/goanalysis"
    13  	"github.com/elek/golangci-lint/pkg/lint/linter"
    14  	"github.com/elek/golangci-lint/pkg/result"
    15  )
    16  
    17  func setDepguardListType(dg *depguard.Depguard, lintCtx *linter.Context) error {
    18  	listType := lintCtx.Settings().Depguard.ListType
    19  	var found bool
    20  	dg.ListType, found = depguard.StringToListType[strings.ToLower(listType)]
    21  	if !found {
    22  		if listType != "" {
    23  			return fmt.Errorf("unsure what list type %s is", listType)
    24  		}
    25  		dg.ListType = depguard.LTBlacklist
    26  	}
    27  
    28  	return nil
    29  }
    30  
    31  func setupDepguardPackages(dg *depguard.Depguard, lintCtx *linter.Context) {
    32  	if dg.ListType == depguard.LTBlacklist {
    33  		// if the list type was a blacklist the packages with error messages should
    34  		// be included in the blacklist package list
    35  
    36  		noMessagePackages := make(map[string]bool)
    37  		for _, pkg := range dg.Packages {
    38  			noMessagePackages[pkg] = true
    39  		}
    40  
    41  		for pkg := range lintCtx.Settings().Depguard.PackagesWithErrorMessage {
    42  			if _, ok := noMessagePackages[pkg]; !ok {
    43  				dg.Packages = append(dg.Packages, pkg)
    44  			}
    45  		}
    46  	}
    47  }
    48  
    49  func NewDepguard() *goanalysis.Linter {
    50  	const linterName = "depguard"
    51  	var mu sync.Mutex
    52  	var resIssues []goanalysis.Issue
    53  
    54  	analyzer := &analysis.Analyzer{
    55  		Name: linterName,
    56  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    57  	}
    58  	return goanalysis.NewLinter(
    59  		linterName,
    60  		"Go linter that checks if package imports are in a list of acceptable packages",
    61  		[]*analysis.Analyzer{analyzer},
    62  		nil,
    63  	).WithContextSetter(func(lintCtx *linter.Context) {
    64  		dgSettings := &lintCtx.Settings().Depguard
    65  		analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
    66  			prog := goanalysis.MakeFakeLoaderProgram(pass)
    67  			dg := &depguard.Depguard{
    68  				Packages:      dgSettings.Packages,
    69  				IncludeGoRoot: dgSettings.IncludeGoRoot,
    70  			}
    71  			if err := setDepguardListType(dg, lintCtx); err != nil {
    72  				return nil, err
    73  			}
    74  			setupDepguardPackages(dg, lintCtx)
    75  
    76  			loadConfig := &loader.Config{
    77  				Cwd:   "",  // fallbacked to os.Getcwd
    78  				Build: nil, // fallbacked to build.Default
    79  			}
    80  			issues, err := dg.Run(loadConfig, prog)
    81  			if err != nil {
    82  				return nil, err
    83  			}
    84  			if len(issues) == 0 {
    85  				return nil, nil
    86  			}
    87  			msgSuffix := "is in the blacklist"
    88  			if dg.ListType == depguard.LTWhitelist {
    89  				msgSuffix = "is not in the whitelist"
    90  			}
    91  			res := make([]goanalysis.Issue, 0, len(issues))
    92  			for _, i := range issues {
    93  				userSuppliedMsgSuffix := dgSettings.PackagesWithErrorMessage[i.PackageName]
    94  				if userSuppliedMsgSuffix != "" {
    95  					userSuppliedMsgSuffix = ": " + userSuppliedMsgSuffix
    96  				}
    97  				res = append(res, goanalysis.NewIssue(&result.Issue{
    98  					Pos:        i.Position,
    99  					Text:       fmt.Sprintf("%s %s%s", formatCode(i.PackageName, lintCtx.Cfg), msgSuffix, userSuppliedMsgSuffix),
   100  					FromLinter: linterName,
   101  				}, pass))
   102  			}
   103  			mu.Lock()
   104  			resIssues = append(resIssues, res...)
   105  			mu.Unlock()
   106  
   107  			return nil, nil
   108  		}
   109  	}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
   110  		return resIssues
   111  	}).WithLoadMode(goanalysis.LoadModeTypesInfo)
   112  }