Skip to content

Commit ce5b910

Browse files
committed
fix: force typecheck to be the first linter
1 parent 9a381ee commit ce5b910

File tree

5 files changed

+47
-8
lines changed

5 files changed

+47
-8
lines changed

pkg/golinters/typecheck.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,25 @@ import (
88

99
func NewTypecheck() *goanalysis.Linter {
1010
const linterName = "typecheck"
11+
1112
analyzer := &analysis.Analyzer{
1213
Name: linterName,
1314
Doc: goanalysis.TheOnlyanalyzerDoc,
1415
Run: func(pass *analysis.Pass) (interface{}, error) {
1516
return nil, nil
1617
},
1718
}
19+
20+
// Note: typecheck doesn't require the LoadModeWholeProgram
21+
// but it's a hack to force this linter to be the first linter in all the cases.
1822
linter := goanalysis.NewLinter(
1923
linterName,
2024
"Like the front-end of a Go compiler, parses and type-checks Go code",
2125
[]*analysis.Analyzer{analyzer},
2226
nil,
23-
).WithLoadMode(goanalysis.LoadModeTypesInfo)
27+
).WithLoadMode(goanalysis.LoadModeWholeProgram)
28+
2429
linter.SetTypecheckMode()
30+
2531
return linter
2632
}

pkg/lint/linter/config.go

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ const (
2020
PresetUnused = "unused" // Related to the detection of unused code.
2121
)
2222

23+
const (
24+
// typecheck must be first because it checks the compiling errors.
25+
FirstLinter = "typecheck"
26+
27+
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives.
28+
LastLinter = "nolintlint"
29+
)
30+
2331
type Deprecation struct {
2432
Since string
2533
Message string

pkg/lint/lintersdb/enabled_set.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
111111
// Make order of execution of linters (go/analysis metalinter and unused) stable.
112112
sort.Slice(resultLinters, func(i, j int) bool {
113113
a, b := resultLinters[i], resultLinters[j]
114+
115+
if a.Name() == linter.FirstLinter || b.Name() == linter.LastLinter {
116+
return true
117+
}
118+
119+
if a.Name() == linter.LastLinter || b.Name() == linter.FirstLinter {
120+
return false
121+
}
122+
114123
if a.DoesChangeTypes != b.DoesChangeTypes {
115124
return b.DoesChangeTypes // move type-changing linters to the end to optimize speed
116125
}
@@ -149,8 +158,19 @@ func (es EnabledSet) combineGoAnalysisLinters(linters map[string]*linter.Config)
149158

150159
// Make order of execution of go/analysis analyzers stable.
151160
sort.Slice(goanalysisLinters, func(i, j int) bool {
152-
return strings.Compare(goanalysisLinters[i].Name(), goanalysisLinters[j].Name()) <= 0
161+
a, b := goanalysisLinters[i], goanalysisLinters[j]
162+
163+
if a.Name() == linter.FirstLinter || b.Name() == linter.LastLinter {
164+
return true
165+
}
166+
167+
if a.Name() == linter.LastLinter || b.Name() == linter.FirstLinter {
168+
return false
169+
}
170+
171+
return strings.Compare(a.Name(), b.Name()) <= 0
153172
})
173+
154174
ml := goanalysis.NewMetaLinter(goanalysisLinters)
155175

156176
var presets []string

pkg/lint/lintersdb/manager.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
131131
const megacheckName = "megacheck"
132132

133133
lcs := []*linter.Config{
134+
linter.NewConfig(golinters.NewTypecheck()).
135+
WithSince("v1.3.0").
136+
WithLoadForGoAnalysis().
137+
WithPresets(linter.PresetBugs).
138+
WithURL(""),
139+
134140
linter.NewConfig(golinters.NewGovet(govetCfg)).
135141
WithSince("v1.0.0").
136142
WithLoadForGoAnalysis().
@@ -247,11 +253,6 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
247253
WithSince("v1.20.0").
248254
WithPresets(linter.PresetComplexity).
249255
WithURL("https://github.com/uudashr/gocognit"),
250-
linter.NewConfig(golinters.NewTypecheck()).
251-
WithSince("v1.3.0").
252-
WithLoadForGoAnalysis().
253-
WithPresets(linter.PresetBugs).
254-
WithURL(""),
255256
linter.NewConfig(golinters.NewAsciicheck()).
256257
WithSince("v1.26.0").
257258
WithPresets(linter.PresetBugs, linter.PresetStyle).

pkg/lint/runner.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint
200200
sw.TrackStage(lc.Name(), func() {
201201
linterIssues, err := r.runLinterSafe(ctx, lintCtx, lc)
202202
if err != nil {
203-
r.Log.Warnf("Can't run linter %s: %s", lc.Linter.Name(), err)
203+
r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err)
204204
if os.Getenv("GOLANGCI_COM_RUN") == "" {
205205
// Don't stop all linters on one linter failure for golangci.com.
206206
runErr = err
@@ -209,6 +209,10 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint
209209
}
210210
issues = append(issues, linterIssues...)
211211
})
212+
213+
if lc.Name() == linter.FirstLinter && len(issues) > 0 {
214+
return r.processLintResults(issues), nil
215+
}
212216
}
213217

214218
return r.processLintResults(issues), runErr

0 commit comments

Comments
 (0)