github.com/shulhan/golangci-lint@v1.10.1/pkg/golinters/megacheck.go (about) 1 package golinters 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strings" 8 9 "golang.org/x/tools/go/loader" 10 "golang.org/x/tools/go/ssa" 11 "honnef.co/go/tools/lint" 12 "honnef.co/go/tools/lint/lintutil" 13 "honnef.co/go/tools/simple" 14 "honnef.co/go/tools/staticcheck" 15 "honnef.co/go/tools/unused" 16 17 "github.com/golangci/golangci-lint/pkg/fsutils" 18 "github.com/golangci/golangci-lint/pkg/lint/linter" 19 "github.com/golangci/golangci-lint/pkg/result" 20 ) 21 22 type Megacheck struct { 23 UnusedEnabled bool 24 GosimpleEnabled bool 25 StaticcheckEnabled bool 26 } 27 28 func (m Megacheck) Name() string { 29 names := []string{} 30 if m.UnusedEnabled { 31 names = append(names, "unused") 32 } 33 if m.GosimpleEnabled { 34 names = append(names, "gosimple") 35 } 36 if m.StaticcheckEnabled { 37 names = append(names, "staticcheck") 38 } 39 40 if len(names) == 1 { 41 return names[0] // only one sublinter is enabled 42 } 43 44 if len(names) == 3 { 45 return "megacheck" // all enabled 46 } 47 48 return fmt.Sprintf("megacheck.{%s}", strings.Join(names, ",")) 49 } 50 51 func (m Megacheck) Desc() string { 52 descs := map[string]string{ 53 "unused": "Checks Go code for unused constants, variables, functions and types", 54 "gosimple": "Linter for Go source code that specializes in simplifying a code", 55 "staticcheck": "Staticcheck is a go vet on steroids, applying a ton of static analysis checks", 56 "megacheck": "3 sub-linters in one: unused, gosimple and staticcheck", 57 } 58 59 return descs[m.Name()] 60 } 61 62 func prettifyCompilationError(err error) error { 63 i, _ := TypeCheck{}.parseError(err) 64 if i == nil { 65 return err 66 } 67 68 shortFilename, pathErr := fsutils.ShortestRelPath(i.Pos.Filename, "") 69 if pathErr != nil { 70 return err 71 } 72 73 errText := shortFilename 74 if i.Line() != 0 { 75 errText += fmt.Sprintf(":%d", i.Line()) 76 } 77 errText += fmt.Sprintf(": %s", i.Text) 78 return errors.New(errText) 79 } 80 81 func (m Megacheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { 82 if len(lintCtx.NotCompilingPackages) != 0 { 83 var packages []string 84 var errors []error 85 for _, p := range lintCtx.NotCompilingPackages { 86 packages = append(packages, p.String()) 87 errors = append(errors, p.Errors...) 88 } 89 90 warnText := fmt.Sprintf("Can't run megacheck because of compilation errors in packages %s", 91 packages) 92 if len(errors) != 0 { 93 warnText += fmt.Sprintf(": %s", prettifyCompilationError(errors[0])) 94 if len(errors) > 1 { 95 const runCmd = "golangci-lint run --no-config --disable-all -E typecheck" 96 warnText += fmt.Sprintf(" and %d more errors: run `%s` to see all errors", len(errors)-1, runCmd) 97 } 98 } 99 lintCtx.Log.Warnf("%s", warnText) 100 101 // megacheck crashes if there are not compiling packages 102 return nil, nil 103 } 104 105 issues := runMegacheck(lintCtx.Program, lintCtx.SSAProgram, lintCtx.LoaderConfig, 106 m.StaticcheckEnabled, m.GosimpleEnabled, m.UnusedEnabled, lintCtx.Settings().Unused.CheckExported) 107 if len(issues) == 0 { 108 return nil, nil 109 } 110 111 res := make([]result.Issue, 0, len(issues)) 112 for _, i := range issues { 113 res = append(res, result.Issue{ 114 Pos: i.Position, 115 Text: markIdentifiers(i.Text), 116 FromLinter: m.Name(), 117 }) 118 } 119 return res, nil 120 } 121 122 func runMegacheck(program *loader.Program, ssaProg *ssa.Program, conf *loader.Config, 123 enableStaticcheck, enableGosimple, enableUnused, checkExportedUnused bool) []lint.Problem { 124 125 var checkers []lintutil.CheckerConfig 126 127 if enableStaticcheck { 128 sac := staticcheck.NewChecker() 129 checkers = append(checkers, lintutil.CheckerConfig{ 130 Checker: sac, 131 }) 132 } 133 134 if enableGosimple { 135 sc := simple.NewChecker() 136 checkers = append(checkers, lintutil.CheckerConfig{ 137 Checker: sc, 138 }) 139 } 140 141 if enableUnused { 142 uc := unused.NewChecker(unused.CheckAll) 143 uc.WholeProgram = checkExportedUnused 144 uc.ConsiderReflection = true 145 checkers = append(checkers, lintutil.CheckerConfig{ 146 Checker: unused.NewLintChecker(uc), 147 }) 148 } 149 150 fs := lintutil.FlagSet("megacheck") 151 return lintutil.ProcessFlagSet(checkers, fs, program, ssaProg, conf) 152 }