www.github.com/golangci/golangci-lint.git@v1.10.1/pkg/golinters/typecheck.go (about) 1 package golinters 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "go/token" 8 "strconv" 9 "strings" 10 11 "github.com/golangci/golangci-lint/pkg/lint/linter" 12 "github.com/golangci/golangci-lint/pkg/result" 13 ) 14 15 type TypeCheck struct{} 16 17 func (TypeCheck) Name() string { 18 return "typecheck" 19 } 20 21 func (TypeCheck) Desc() string { 22 return "Like the front-end of a Go compiler, parses and type-checks Go code" 23 } 24 25 func (lint TypeCheck) parseError(srcErr error) (*result.Issue, error) { 26 // TODO: cast srcErr to types.Error and just use it 27 28 // file:line(<optional>:colon): message 29 parts := strings.Split(srcErr.Error(), ":") 30 if len(parts) < 3 { 31 return nil, errors.New("too few colons") 32 } 33 34 file := parts[0] 35 line, err := strconv.Atoi(parts[1]) 36 if err != nil { 37 return nil, fmt.Errorf("can't parse line number %q: %s", parts[1], err) 38 } 39 40 var column int 41 var message string 42 if len(parts) == 3 { // no column 43 message = parts[2] 44 } else { 45 column, err = strconv.Atoi(parts[2]) 46 if err == nil { // column was parsed 47 message = strings.Join(parts[3:], ":") 48 } else { 49 message = strings.Join(parts[2:], ":") 50 } 51 } 52 53 message = strings.TrimSpace(message) 54 if message == "" { 55 return nil, fmt.Errorf("empty message") 56 } 57 58 return &result.Issue{ 59 Pos: token.Position{ 60 Filename: file, 61 Line: line, 62 Column: column, 63 }, 64 Text: markIdentifiers(message), 65 FromLinter: lint.Name(), 66 }, nil 67 } 68 69 func (lint TypeCheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { 70 var res []result.Issue 71 for _, pkg := range lintCtx.NotCompilingPackages { 72 for _, err := range pkg.Errors { 73 i, perr := lint.parseError(err) 74 if perr != nil { 75 lintCtx.Log.Warnf("Can't parse type error %s: %s", err, perr) 76 } else { 77 res = append(res, *i) 78 } 79 } 80 } 81 82 return res, nil 83 }