Skip to content

Commit

Permalink
fix: force typecheck to be the first linter
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Mar 19, 2021
1 parent 9a381ee commit ce5b910
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 8 deletions.
8 changes: 7 additions & 1 deletion pkg/golinters/typecheck.go
Expand Up @@ -8,19 +8,25 @@ import (

func NewTypecheck() *goanalysis.Linter {
const linterName = "typecheck"

analyzer := &analysis.Analyzer{
Name: linterName,
Doc: goanalysis.TheOnlyanalyzerDoc,
Run: func(pass *analysis.Pass) (interface{}, error) {
return nil, nil
},
}

// Note: typecheck doesn't require the LoadModeWholeProgram
// but it's a hack to force this linter to be the first linter in all the cases.
linter := goanalysis.NewLinter(
linterName,
"Like the front-end of a Go compiler, parses and type-checks Go code",
[]*analysis.Analyzer{analyzer},
nil,
).WithLoadMode(goanalysis.LoadModeTypesInfo)
).WithLoadMode(goanalysis.LoadModeWholeProgram)

linter.SetTypecheckMode()

return linter
}
8 changes: 8 additions & 0 deletions pkg/lint/linter/config.go
Expand Up @@ -20,6 +20,14 @@ const (
PresetUnused = "unused" // Related to the detection of unused code.
)

const (
// typecheck must be first because it checks the compiling errors.
FirstLinter = "typecheck"

// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives.
LastLinter = "nolintlint"
)

type Deprecation struct {
Since string
Message string
Expand Down
22 changes: 21 additions & 1 deletion pkg/lint/lintersdb/enabled_set.go
Expand Up @@ -111,6 +111,15 @@ func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
// Make order of execution of linters (go/analysis metalinter and unused) stable.
sort.Slice(resultLinters, func(i, j int) bool {
a, b := resultLinters[i], resultLinters[j]

if a.Name() == linter.FirstLinter || b.Name() == linter.LastLinter {
return true
}

if a.Name() == linter.LastLinter || b.Name() == linter.FirstLinter {
return false
}

if a.DoesChangeTypes != b.DoesChangeTypes {
return b.DoesChangeTypes // move type-changing linters to the end to optimize speed
}
Expand Down Expand Up @@ -149,8 +158,19 @@ func (es EnabledSet) combineGoAnalysisLinters(linters map[string]*linter.Config)

// Make order of execution of go/analysis analyzers stable.
sort.Slice(goanalysisLinters, func(i, j int) bool {
return strings.Compare(goanalysisLinters[i].Name(), goanalysisLinters[j].Name()) <= 0
a, b := goanalysisLinters[i], goanalysisLinters[j]

if a.Name() == linter.FirstLinter || b.Name() == linter.LastLinter {
return true
}

if a.Name() == linter.LastLinter || b.Name() == linter.FirstLinter {
return false
}

return strings.Compare(a.Name(), b.Name()) <= 0
})

ml := goanalysis.NewMetaLinter(goanalysisLinters)

var presets []string
Expand Down
11 changes: 6 additions & 5 deletions pkg/lint/lintersdb/manager.go
Expand Up @@ -131,6 +131,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
const megacheckName = "megacheck"

lcs := []*linter.Config{
linter.NewConfig(golinters.NewTypecheck()).
WithSince("v1.3.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL(""),

linter.NewConfig(golinters.NewGovet(govetCfg)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
Expand Down Expand Up @@ -247,11 +253,6 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSince("v1.20.0").
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/uudashr/gocognit"),
linter.NewConfig(golinters.NewTypecheck()).
WithSince("v1.3.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL(""),
linter.NewConfig(golinters.NewAsciicheck()).
WithSince("v1.26.0").
WithPresets(linter.PresetBugs, linter.PresetStyle).
Expand Down
6 changes: 5 additions & 1 deletion pkg/lint/runner.go
Expand Up @@ -200,7 +200,7 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint
sw.TrackStage(lc.Name(), func() {
linterIssues, err := r.runLinterSafe(ctx, lintCtx, lc)
if err != nil {
r.Log.Warnf("Can't run linter %s: %s", lc.Linter.Name(), err)
r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err)
if os.Getenv("GOLANGCI_COM_RUN") == "" {
// Don't stop all linters on one linter failure for golangci.com.
runErr = err
Expand All @@ -209,6 +209,10 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint
}
issues = append(issues, linterIssues...)
})

if lc.Name() == linter.FirstLinter && len(issues) > 0 {
return r.processLintResults(issues), nil
}
}

return r.processLintResults(issues), runErr
Expand Down

0 comments on commit ce5b910

Please sign in to comment.