Skip to content

Commit 39f46be

Browse files
committed
Fix staticcheck panic on packages that do not compile
The bug was introduced in golangci-lint when migrating staticcheck to go/packages. Also, thanks to pkg.IllTyped we can analyze as max as we can by staticcheck. Relates: #418, #369, #429, #489
1 parent 09677d5 commit 39f46be

File tree

4 files changed

+17
-79
lines changed

4 files changed

+17
-79
lines changed

pkg/exitcodes/exitcodes.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ var (
2424
Message: "no go files to analyze",
2525
Code: NoGoFiles,
2626
}
27+
ErrFailure = &ExitError{
28+
Message: "failed to analyze",
29+
Code: Failure,
30+
}
2731
)

pkg/golinters/megacheck.go

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ import (
1818
"github.com/golangci/go-tools/unused"
1919
"golang.org/x/tools/go/packages"
2020

21-
"github.com/golangci/golangci-lint/pkg/fsutils"
22-
libpackages "github.com/golangci/golangci-lint/pkg/packages"
23-
2421
"github.com/golangci/golangci-lint/pkg/lint/linter"
2522
"github.com/golangci/golangci-lint/pkg/result"
2623
)
@@ -179,67 +176,7 @@ func (m MegacheckMetalinter) isValidChild(name string) bool {
179176
return false
180177
}
181178

182-
func prettifyCompilationError(err packages.Error) error {
183-
i, _ := TypeCheck{}.parseError(err)
184-
if i == nil {
185-
return err
186-
}
187-
188-
shortFilename, pathErr := fsutils.ShortestRelPath(i.Pos.Filename, "")
189-
if pathErr != nil {
190-
return err
191-
}
192-
193-
errText := shortFilename
194-
if i.Line() != 0 {
195-
errText += fmt.Sprintf(":%d", i.Line())
196-
}
197-
errText += fmt.Sprintf(": %s", i.Text)
198-
return errors.New(errText)
199-
}
200-
201-
func (m megacheck) canAnalyze(lintCtx *linter.Context) bool {
202-
if len(lintCtx.NotCompilingPackages) == 0 {
203-
return true
204-
}
205-
206-
var errPkgs []string
207-
var errs []packages.Error
208-
for _, p := range lintCtx.NotCompilingPackages {
209-
if p.Name == "main" {
210-
// megacheck crashes on not compiling packages but main packages
211-
// aren't reachable by megacheck: other packages can't depend on them.
212-
continue
213-
}
214-
215-
errPkgs = append(errPkgs, p.String())
216-
errs = append(errs, libpackages.ExtractErrors(p, lintCtx.ASTCache)...)
217-
}
218-
219-
if len(errPkgs) == 0 { // only main packages do not compile
220-
return true
221-
}
222-
223-
// TODO: print real linter names in this message
224-
warnText := fmt.Sprintf("Can't run megacheck because of compilation errors in packages %s", errPkgs)
225-
if len(errs) != 0 {
226-
warnText += fmt.Sprintf(": %s", prettifyCompilationError(errs[0]))
227-
if len(errs) > 1 {
228-
const runCmd = "golangci-lint run --no-config --disable-all -E typecheck"
229-
warnText += fmt.Sprintf(" and %d more errors: run `%s` to see all errors", len(errs)-1, runCmd)
230-
}
231-
}
232-
lintCtx.Log.Warnf("%s", warnText)
233-
234-
// megacheck crashes if there are not compiling packages
235-
return false
236-
}
237-
238179
func (m megacheck) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
239-
if !m.canAnalyze(lintCtx) {
240-
return nil, nil
241-
}
242-
243180
issues, err := m.runMegacheck(lintCtx.Packages, lintCtx.Settings().Unused.CheckExported)
244181
if err != nil {
245182
return nil, errors.Wrap(err, "failed to run megacheck")

pkg/lint/load.go

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"github.com/golangci/golangci-lint/pkg/lint/astcache"
2424
"github.com/golangci/golangci-lint/pkg/lint/linter"
2525
"github.com/golangci/golangci-lint/pkg/logutils"
26-
libpackages "github.com/golangci/golangci-lint/pkg/packages"
2726
)
2827

2928
type ContextLoader struct {
@@ -265,6 +264,10 @@ func (cl ContextLoader) loadPackages(ctx context.Context, loadMode packages.Load
265264
if strings.Contains(err.Msg, "no Go files") {
266265
return nil, errors.Wrapf(exitcodes.ErrNoGoFiles, "package %s", pkg.PkgPath)
267266
}
267+
if strings.Contains(err.Msg, "cannot find package") {
268+
// when analyzing not existing directory
269+
return nil, errors.Wrap(exitcodes.ErrFailure, err.Msg)
270+
}
268271
}
269272
}
270273

@@ -358,29 +361,23 @@ func (cl ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*li
358361
Log: cl.log,
359362
}
360363

361-
if prog != nil {
362-
saveNotCompilingPackages(ret)
363-
} else {
364-
for _, pkg := range pkgs {
365-
if pkg.IllTyped {
366-
cl.log.Infof("Pkg %s errors: %v", pkg.ID, libpackages.ExtractErrors(pkg, astCache))
367-
}
368-
}
369-
}
370-
364+
separateNotCompilingPackages(ret)
371365
return ret, nil
372366
}
373367

374-
// saveNotCompilingPackages saves not compiling packages into separate slice:
375-
// a lot of linters crash on such packages. Leave them only for those linters
376-
// which can work with them.
377-
func saveNotCompilingPackages(lintCtx *linter.Context) {
368+
// separateNotCompilingPackages moves not compiling packages into separate slice:
369+
// a lot of linters crash on such packages
370+
func separateNotCompilingPackages(lintCtx *linter.Context) {
371+
goodPkgs := make([]*packages.Package, 0, len(lintCtx.Packages))
378372
for _, pkg := range lintCtx.Packages {
379373
if pkg.IllTyped {
380374
lintCtx.NotCompilingPackages = append(lintCtx.NotCompilingPackages, pkg)
375+
} else {
376+
goodPkgs = append(goodPkgs, pkg)
381377
}
382378
}
383379

380+
lintCtx.Packages = goodPkgs
384381
if len(lintCtx.NotCompilingPackages) != 0 {
385382
lintCtx.Log.Infof("Packages that do not compile: %+v", lintCtx.NotCompilingPackages)
386383
}

test/run_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestEmptyDirRun(t *testing.T) {
3232

3333
func TestNotExistingDirRun(t *testing.T) {
3434
testshared.NewLintRunner(t).Run(getTestDataDir("no_such_dir")).
35-
ExpectExitCode(exitcodes.WarningInTest).
35+
ExpectExitCode(exitcodes.Failure).
3636
ExpectOutputContains(`cannot find package \"./testdata/no_such_dir\"`)
3737
}
3838

0 commit comments

Comments
 (0)