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 }