github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/golinters/goanalysis/linter.go (about) 1 package goanalysis 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "strings" 8 9 "github.com/pkg/errors" 10 "golang.org/x/tools/go/analysis" 11 12 "github.com/golangci/golangci-lint/pkg/lint/linter" 13 "github.com/golangci/golangci-lint/pkg/result" 14 ) 15 16 const ( 17 TheOnlyAnalyzerName = "the_only_name" 18 TheOnlyanalyzerDoc = "the_only_doc" 19 ) 20 21 type LoadMode int 22 23 func (loadMode LoadMode) String() string { 24 switch loadMode { 25 case LoadModeNone: 26 return "none" 27 case LoadModeSyntax: 28 return "syntax" 29 case LoadModeTypesInfo: 30 return "types info" 31 case LoadModeWholeProgram: 32 return "whole program" 33 } 34 panic(fmt.Sprintf("unknown load mode %d", loadMode)) 35 } 36 37 const ( 38 LoadModeNone LoadMode = iota 39 LoadModeSyntax 40 LoadModeTypesInfo 41 LoadModeWholeProgram 42 ) 43 44 type Linter struct { 45 name, desc string 46 analyzers []*analysis.Analyzer 47 cfg map[string]map[string]interface{} 48 issuesReporter func(*linter.Context) []Issue 49 contextSetter func(*linter.Context) 50 loadMode LoadMode 51 needUseOriginalPackages bool 52 } 53 54 func NewLinter(name, desc string, analyzers []*analysis.Analyzer, cfg map[string]map[string]interface{}) *Linter { 55 return &Linter{name: name, desc: desc, analyzers: analyzers, cfg: cfg} 56 } 57 58 func (lnt *Linter) Run(_ context.Context, lintCtx *linter.Context) ([]result.Issue, error) { 59 if err := lnt.preRun(lintCtx); err != nil { 60 return nil, err 61 } 62 63 return runAnalyzers(lnt, lintCtx) 64 } 65 66 func (lnt *Linter) UseOriginalPackages() { 67 lnt.needUseOriginalPackages = true 68 } 69 70 func (lnt *Linter) LoadMode() LoadMode { 71 return lnt.loadMode 72 } 73 74 func (lnt *Linter) WithLoadMode(loadMode LoadMode) *Linter { 75 lnt.loadMode = loadMode 76 return lnt 77 } 78 79 func (lnt *Linter) WithIssuesReporter(r func(*linter.Context) []Issue) *Linter { 80 lnt.issuesReporter = r 81 return lnt 82 } 83 84 func (lnt *Linter) WithContextSetter(cs func(*linter.Context)) *Linter { 85 lnt.contextSetter = cs 86 return lnt 87 } 88 89 func (lnt *Linter) Name() string { 90 return lnt.name 91 } 92 93 func (lnt *Linter) Desc() string { 94 return lnt.desc 95 } 96 97 func (lnt *Linter) allAnalyzerNames() []string { 98 var ret []string 99 for _, a := range lnt.analyzers { 100 ret = append(ret, a.Name) 101 } 102 return ret 103 } 104 105 func (lnt *Linter) configureAnalyzer(a *analysis.Analyzer, cfg map[string]interface{}) error { 106 for k, v := range cfg { 107 f := a.Flags.Lookup(k) 108 if f == nil { 109 validFlagNames := allFlagNames(&a.Flags) 110 if len(validFlagNames) == 0 { 111 return errors.New("analyzer doesn't have settings") 112 } 113 114 return fmt.Errorf("analyzer doesn't have setting %q, valid settings: %v", 115 k, validFlagNames) 116 } 117 118 if err := f.Value.Set(valueToString(v)); err != nil { 119 return errors.Wrapf(err, "failed to set analyzer setting %q with value %v", k, v) 120 } 121 } 122 123 return nil 124 } 125 126 func (lnt *Linter) configure() error { 127 analyzersMap := map[string]*analysis.Analyzer{} 128 for _, a := range lnt.analyzers { 129 analyzersMap[a.Name] = a 130 } 131 132 for analyzerName, analyzerSettings := range lnt.cfg { 133 a := analyzersMap[analyzerName] 134 if a == nil { 135 return fmt.Errorf("settings key %q must be valid analyzer name, valid analyzers: %v", 136 analyzerName, lnt.allAnalyzerNames()) 137 } 138 139 if err := lnt.configureAnalyzer(a, analyzerSettings); err != nil { 140 return errors.Wrapf(err, "failed to configure analyzer %s", analyzerName) 141 } 142 } 143 144 return nil 145 } 146 147 func (lnt *Linter) preRun(lintCtx *linter.Context) error { 148 if err := analysis.Validate(lnt.analyzers); err != nil { 149 return errors.Wrap(err, "failed to validate analyzers") 150 } 151 152 if err := lnt.configure(); err != nil { 153 return errors.Wrap(err, "failed to configure analyzers") 154 } 155 156 if lnt.contextSetter != nil { 157 lnt.contextSetter(lintCtx) 158 } 159 160 return nil 161 } 162 163 func (lnt *Linter) getName() string { 164 return lnt.name 165 } 166 167 func (lnt *Linter) getLinterNameForDiagnostic(*Diagnostic) string { 168 return lnt.name 169 } 170 171 func (lnt *Linter) getAnalyzers() []*analysis.Analyzer { 172 return lnt.analyzers 173 } 174 175 func (lnt *Linter) useOriginalPackages() bool { 176 return lnt.needUseOriginalPackages 177 } 178 179 func (lnt *Linter) reportIssues(lintCtx *linter.Context) []Issue { 180 if lnt.issuesReporter != nil { 181 return lnt.issuesReporter(lintCtx) 182 } 183 return nil 184 } 185 186 func (lnt *Linter) getLoadMode() LoadMode { 187 return lnt.loadMode 188 } 189 190 func allFlagNames(fs *flag.FlagSet) []string { 191 var ret []string 192 fs.VisitAll(func(f *flag.Flag) { 193 ret = append(ret, f.Name) 194 }) 195 return ret 196 } 197 198 func valueToString(v interface{}) string { 199 if ss, ok := v.([]string); ok { 200 return strings.Join(ss, ",") 201 } 202 203 if is, ok := v.([]interface{}); ok { 204 var ss []string 205 for _, i := range is { 206 ss = append(ss, fmt.Sprint(i)) 207 } 208 209 return valueToString(ss) 210 } 211 212 return fmt.Sprint(v) 213 } 214 215 func DummyRun(_ *analysis.Pass) (interface{}, error) { 216 return nil, nil 217 }