improve typecheck errors parsing
This commit is contained in:
parent
55a18ae18a
commit
dba3907ff3
@ -88,7 +88,7 @@ func (m Megacheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.I
|
|||||||
var errors []packages.Error
|
var errors []packages.Error
|
||||||
for _, p := range lintCtx.NotCompilingPackages {
|
for _, p := range lintCtx.NotCompilingPackages {
|
||||||
errPkgs = append(errPkgs, p.String())
|
errPkgs = append(errPkgs, p.String())
|
||||||
errors = append(errors, libpackages.ExtractErrors(p)...)
|
errors = append(errors, libpackages.ExtractErrors(p, lintCtx.ASTCache)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
warnText := fmt.Sprintf("Can't run megacheck because of compilation errors in packages %s",
|
warnText := fmt.Sprintf("Can't run megacheck because of compilation errors in packages %s",
|
||||||
|
@ -2,12 +2,7 @@ package golinters
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"go/token"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
@ -26,44 +21,31 @@ func (TypeCheck) Desc() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lint TypeCheck) parseError(srcErr packages.Error) (*result.Issue, error) {
|
func (lint TypeCheck) parseError(srcErr packages.Error) (*result.Issue, error) {
|
||||||
// file:line(<optional>:colon)
|
pos, err := libpackages.ParseErrorPosition(srcErr.Pos)
|
||||||
parts := strings.Split(srcErr.Pos, ":")
|
|
||||||
if len(parts) == 1 {
|
|
||||||
return nil, errors.New("no colons")
|
|
||||||
}
|
|
||||||
|
|
||||||
file := parts[0]
|
|
||||||
line, err := strconv.Atoi(parts[1])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't parse line number %q: %s", parts[1], err)
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
var column int
|
|
||||||
if len(parts) == 3 { // no column
|
|
||||||
column, err = strconv.Atoi(parts[2])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to parse column from %q", parts[2])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &result.Issue{
|
return &result.Issue{
|
||||||
Pos: token.Position{
|
Pos: *pos,
|
||||||
Filename: file,
|
|
||||||
Line: line,
|
|
||||||
Column: column,
|
|
||||||
},
|
|
||||||
Text: srcErr.Msg,
|
Text: srcErr.Msg,
|
||||||
FromLinter: lint.Name(),
|
FromLinter: lint.Name(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lint TypeCheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
func (lint TypeCheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||||
|
uniqReportedIssues := map[string]bool{}
|
||||||
|
|
||||||
var res []result.Issue
|
var res []result.Issue
|
||||||
for _, pkg := range lintCtx.NotCompilingPackages {
|
for _, pkg := range lintCtx.NotCompilingPackages {
|
||||||
errors := libpackages.ExtractErrors(pkg)
|
errors := libpackages.ExtractErrors(pkg, lintCtx.ASTCache)
|
||||||
for _, err := range errors {
|
for _, err := range errors {
|
||||||
i, perr := lint.parseError(err)
|
i, perr := lint.parseError(err)
|
||||||
if perr != nil { // failed to parse
|
if perr != nil { // failed to parse
|
||||||
|
if uniqReportedIssues[err.Msg] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
uniqReportedIssues[err.Msg] = true
|
||||||
lintCtx.Log.Errorf("typechecking error: %s", err.Msg)
|
lintCtx.Log.Errorf("typechecking error: %s", err.Msg)
|
||||||
} else {
|
} else {
|
||||||
res = append(res, *i)
|
res = append(res, *i)
|
||||||
|
@ -334,7 +334,7 @@ func (cl ContextLoader) Load(ctx context.Context, linters []linter.Config) (*lin
|
|||||||
} else {
|
} else {
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
if pkg.IllTyped {
|
if pkg.IllTyped {
|
||||||
cl.log.Infof("Pkg %s errors: %v", pkg.ID, libpackages.ExtractErrors(pkg))
|
cl.log.Infof("Pkg %s errors: %v", pkg.ID, libpackages.ExtractErrors(pkg, astCache))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
pkg/packages/errors.go
Normal file
38
pkg/packages/errors.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package packages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseErrorPosition(pos string) (*token.Position, error) {
|
||||||
|
// file:line(<optional>:colon)
|
||||||
|
parts := strings.Split(pos, ":")
|
||||||
|
if len(parts) == 1 {
|
||||||
|
return nil, errors.New("no colons")
|
||||||
|
}
|
||||||
|
|
||||||
|
file := parts[0]
|
||||||
|
line, err := strconv.Atoi(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("can't parse line number %q: %s", parts[1], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var column int
|
||||||
|
if len(parts) == 3 { // no column
|
||||||
|
column, err = strconv.Atoi(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to parse column from %q", parts[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token.Position{
|
||||||
|
Filename: file,
|
||||||
|
Line: line,
|
||||||
|
Column: column,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -3,10 +3,13 @@ package packages
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/lint/astcache"
|
||||||
|
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExtractErrors(pkg *packages.Package) []packages.Error {
|
//nolint:gocyclo
|
||||||
|
func ExtractErrors(pkg *packages.Package, astCache *astcache.Cache) []packages.Error {
|
||||||
errors := extractErrorsImpl(pkg)
|
errors := extractErrorsImpl(pkg)
|
||||||
if len(errors) == 0 {
|
if len(errors) == 0 {
|
||||||
return errors
|
return errors
|
||||||
@ -22,17 +25,18 @@ func ExtractErrors(pkg *packages.Package) []packages.Error {
|
|||||||
uniqErrors = append(uniqErrors, err)
|
uniqErrors = append(uniqErrors, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pkg.Errors) == 0 && len(pkg.GoFiles) != 0 {
|
|
||||||
// erorrs were extracted from deps and have at leat one file in package
|
|
||||||
for i := range uniqErrors {
|
|
||||||
// change pos to local file to properly process it by processors (properly read line etc)
|
|
||||||
uniqErrors[i].Msg = fmt.Sprintf("%s: %s", uniqErrors[i].Pos, uniqErrors[i].Msg)
|
|
||||||
uniqErrors[i].Pos = fmt.Sprintf("%s:1", pkg.GoFiles[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// some errors like "code in directory expects import" don't have Pos, set it here
|
|
||||||
if len(pkg.GoFiles) != 0 {
|
if len(pkg.GoFiles) != 0 {
|
||||||
|
// errors were extracted from deps and have at leat one file in package
|
||||||
|
for i := range uniqErrors {
|
||||||
|
errPos, parseErr := ParseErrorPosition(uniqErrors[i].Pos)
|
||||||
|
if parseErr != nil || astCache.Get(errPos.Filename) == nil {
|
||||||
|
// change pos to local file to properly process it by processors (properly read line etc)
|
||||||
|
uniqErrors[i].Msg = fmt.Sprintf("%s: %s", uniqErrors[i].Pos, uniqErrors[i].Msg)
|
||||||
|
uniqErrors[i].Pos = fmt.Sprintf("%s:1", pkg.GoFiles[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// some errors like "code in directory expects import" don't have Pos, set it here
|
||||||
for i := range uniqErrors {
|
for i := range uniqErrors {
|
||||||
err := &uniqErrors[i]
|
err := &uniqErrors[i]
|
||||||
if err.Pos == "" {
|
if err.Pos == "" {
|
||||||
|
@ -42,6 +42,11 @@ func (p *AutogeneratedExclude) Process(issues []result.Issue) ([]result.Issue, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *AutogeneratedExclude) shouldPassIssue(i *result.Issue) (bool, error) {
|
func (p *AutogeneratedExclude) shouldPassIssue(i *result.Issue) (bool, error) {
|
||||||
|
if i.FromLinter == "typecheck" {
|
||||||
|
// don't hide typechecking errors in generated files: users expect to see why the project isn't compiling
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
fs, err := p.getOrCreateFileSummary(i)
|
fs, err := p.getOrCreateFileSummary(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -24,7 +24,8 @@ func TestEmptyDirRun(t *testing.T) {
|
|||||||
|
|
||||||
func TestNotExistingDirRun(t *testing.T) {
|
func TestNotExistingDirRun(t *testing.T) {
|
||||||
testshared.NewLintRunner(t).Run(getTestDataDir("no_such_dir")).
|
testshared.NewLintRunner(t).Run(getTestDataDir("no_such_dir")).
|
||||||
ExpectHasIssue(`cannot find package \"./testdata/no_such_dir\"`)
|
ExpectExitCode(exitcodes.WarningInTest).
|
||||||
|
ExpectOutputContains(`cannot find package \"./testdata/no_such_dir\"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSymlinkLoop(t *testing.T) {
|
func TestSymlinkLoop(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user