Skip to content

Commit 8c0c515

Browse files
authored
fix: Go version propagation (#5109)
1 parent 874a8ba commit 8c0c515

10 files changed

+681
-627
lines changed

pkg/config/loader.go

-11
Original file line numberDiff line numberDiff line change
@@ -302,17 +302,6 @@ func (l *Loader) handleGoVersion() {
302302

303303
l.cfg.LintersSettings.Gocritic.Go = trimmedGoVersion
304304

305-
// staticcheck related linters.
306-
if l.cfg.LintersSettings.Staticcheck.GoVersion == "" {
307-
l.cfg.LintersSettings.Staticcheck.GoVersion = trimmedGoVersion
308-
}
309-
if l.cfg.LintersSettings.Gosimple.GoVersion == "" {
310-
l.cfg.LintersSettings.Gosimple.GoVersion = trimmedGoVersion
311-
}
312-
if l.cfg.LintersSettings.Stylecheck.GoVersion == "" {
313-
l.cfg.LintersSettings.Stylecheck.GoVersion = trimmedGoVersion
314-
}
315-
316305
os.Setenv("GOSECGOVERSION", l.cfg.Run.Go)
317306
}
318307

pkg/goanalysis/runner.go

-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
// checker is a partial copy of https://github.com/golang/tools/blob/master/go/analysis/internal/checker
2-
// Copyright 2018 The Go Authors. All rights reserved.
3-
// Use of this source code is governed by a BSD-style
4-
// license that can be found in the LICENSE file.
5-
61
// Package goanalysis defines the implementation of the checker commands.
72
// The same code drives the multi-analysis driver, the single-analysis
83
// driver that is conventionally provided for convenience along with

pkg/goanalysis/runner_action.go

-318
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
11
package goanalysis
22

33
import (
4-
"errors"
54
"fmt"
6-
"go/types"
7-
"io"
8-
"reflect"
95
"runtime/debug"
10-
"time"
116

12-
"golang.org/x/tools/go/analysis"
13-
"golang.org/x/tools/go/packages"
14-
"golang.org/x/tools/go/types/objectpath"
15-
16-
"github.com/golangci/golangci-lint/internal/cache"
177
"github.com/golangci/golangci-lint/internal/errorutil"
18-
"github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors"
198
)
209

2110
type actionAllocator struct {
@@ -39,54 +28,6 @@ func (actAlloc *actionAllocator) alloc() *action {
3928
return act
4029
}
4130

42-
// An action represents one unit of analysis work: the application of
43-
// one analysis to one package. Actions form a DAG, both within a
44-
// package (as different analyzers are applied, either in sequence or
45-
// parallel), and across packages (as dependencies are analyzed).
46-
type action struct {
47-
a *analysis.Analyzer
48-
pkg *packages.Package
49-
pass *analysis.Pass
50-
deps []*action
51-
objectFacts map[objectFactKey]analysis.Fact
52-
packageFacts map[packageFactKey]analysis.Fact
53-
result any
54-
diagnostics []analysis.Diagnostic
55-
err error
56-
r *runner
57-
analysisDoneCh chan struct{}
58-
loadCachedFactsDone bool
59-
loadCachedFactsOk bool
60-
isroot bool
61-
isInitialPkg bool
62-
needAnalyzeSource bool
63-
}
64-
65-
func (act *action) String() string {
66-
return fmt.Sprintf("%s@%s", act.a, act.pkg)
67-
}
68-
69-
func (act *action) loadCachedFacts() bool {
70-
if act.loadCachedFactsDone { // can't be set in parallel
71-
return act.loadCachedFactsOk
72-
}
73-
74-
res := func() bool {
75-
if act.isInitialPkg {
76-
return true // load cached facts only for non-initial packages
77-
}
78-
79-
if len(act.a.FactTypes) == 0 {
80-
return true // no need to load facts
81-
}
82-
83-
return act.loadPersistedFacts()
84-
}()
85-
act.loadCachedFactsDone = true
86-
act.loadCachedFactsOk = res
87-
return res
88-
}
89-
9031
func (act *action) waitUntilDependingAnalyzersWorked() {
9132
for _, dep := range act.deps {
9233
if dep.pkg == act.pkg {
@@ -113,265 +54,6 @@ func (act *action) analyzeSafe() {
11354
act.r.sw.TrackStage(act.a.Name, act.analyze)
11455
}
11556

116-
func (act *action) analyze() {
117-
defer close(act.analysisDoneCh) // unblock actions depending on this action
118-
119-
if !act.needAnalyzeSource {
120-
return
121-
}
122-
123-
defer func(now time.Time) {
124-
analyzeDebugf("go/analysis: %s: %s: analyzed package %q in %s", act.r.prefix, act.a.Name, act.pkg.Name, time.Since(now))
125-
}(time.Now())
126-
127-
// Report an error if any dependency failures.
128-
var depErrors error
129-
for _, dep := range act.deps {
130-
if dep.err == nil {
131-
continue
132-
}
133-
134-
depErrors = errors.Join(depErrors, errors.Unwrap(dep.err))
135-
}
136-
if depErrors != nil {
137-
act.err = fmt.Errorf("failed prerequisites: %w", depErrors)
138-
return
139-
}
140-
141-
// Plumb the output values of the dependencies
142-
// into the inputs of this action. Also facts.
143-
inputs := make(map[*analysis.Analyzer]any)
144-
startedAt := time.Now()
145-
for _, dep := range act.deps {
146-
if dep.pkg == act.pkg {
147-
// Same package, different analysis (horizontal edge):
148-
// in-memory outputs of prerequisite analyzers
149-
// become inputs to this analysis pass.
150-
inputs[dep.a] = dep.result
151-
} else if dep.a == act.a { // (always true)
152-
// Same analysis, different package (vertical edge):
153-
// serialized facts produced by prerequisite analysis
154-
// become available to this analysis pass.
155-
inheritFacts(act, dep)
156-
}
157-
}
158-
factsDebugf("%s: Inherited facts in %s", act, time.Since(startedAt))
159-
160-
// Run the analysis.
161-
pass := &analysis.Pass{
162-
Analyzer: act.a,
163-
Fset: act.pkg.Fset,
164-
Files: act.pkg.Syntax,
165-
OtherFiles: act.pkg.OtherFiles,
166-
Pkg: act.pkg.Types,
167-
TypesInfo: act.pkg.TypesInfo,
168-
TypesSizes: act.pkg.TypesSizes,
169-
ResultOf: inputs,
170-
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
171-
ImportObjectFact: act.importObjectFact,
172-
ExportObjectFact: act.exportObjectFact,
173-
ImportPackageFact: act.importPackageFact,
174-
ExportPackageFact: act.exportPackageFact,
175-
AllObjectFacts: act.allObjectFacts,
176-
AllPackageFacts: act.allPackageFacts,
177-
}
178-
act.pass = pass
179-
act.r.passToPkgGuard.Lock()
180-
act.r.passToPkg[pass] = act.pkg
181-
act.r.passToPkgGuard.Unlock()
182-
183-
if act.pkg.IllTyped {
184-
// It looks like there should be !pass.Analyzer.RunDespiteErrors
185-
// but govet's cgocall crashes on it. Govet itself contains !pass.Analyzer.RunDespiteErrors condition here,
186-
// but it exits before it if packages.Load have failed.
187-
act.err = fmt.Errorf("analysis skipped: %w", &pkgerrors.IllTypedError{Pkg: act.pkg})
188-
} else {
189-
startedAt = time.Now()
190-
act.result, act.err = pass.Analyzer.Run(pass)
191-
analyzedIn := time.Since(startedAt)
192-
if analyzedIn > time.Millisecond*10 {
193-
debugf("%s: run analyzer in %s", act, analyzedIn)
194-
}
195-
}
196-
197-
// disallow calls after Run
198-
pass.ExportObjectFact = nil
199-
pass.ExportPackageFact = nil
200-
201-
if err := act.persistFactsToCache(); err != nil {
202-
act.r.log.Warnf("Failed to persist facts to cache: %s", err)
203-
}
204-
}
205-
206-
// importObjectFact implements Pass.ImportObjectFact.
207-
// Given a non-nil pointer ptr of type *T, where *T satisfies Fact,
208-
// importObjectFact copies the fact value to *ptr.
209-
func (act *action) importObjectFact(obj types.Object, ptr analysis.Fact) bool {
210-
if obj == nil {
211-
panic("nil object")
212-
}
213-
key := objectFactKey{obj, act.factType(ptr)}
214-
if v, ok := act.objectFacts[key]; ok {
215-
reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
216-
return true
217-
}
218-
return false
219-
}
220-
221-
// exportObjectFact implements Pass.ExportObjectFact.
222-
func (act *action) exportObjectFact(obj types.Object, fact analysis.Fact) {
223-
if obj.Pkg() != act.pkg.Types {
224-
act.r.log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package",
225-
act.a, act.pkg, obj, fact)
226-
}
227-
228-
key := objectFactKey{obj, act.factType(fact)}
229-
act.objectFacts[key] = fact // clobber any existing entry
230-
if isFactsExportDebug {
231-
objstr := types.ObjectString(obj, (*types.Package).Name)
232-
factsExportDebugf("%s: object %s has fact %s\n",
233-
act.pkg.Fset.Position(obj.Pos()), objstr, fact)
234-
}
235-
}
236-
237-
func (act *action) allObjectFacts() []analysis.ObjectFact {
238-
out := make([]analysis.ObjectFact, 0, len(act.objectFacts))
239-
for key, fact := range act.objectFacts {
240-
out = append(out, analysis.ObjectFact{
241-
Object: key.obj,
242-
Fact: fact,
243-
})
244-
}
245-
return out
246-
}
247-
248-
// importPackageFact implements Pass.ImportPackageFact.
249-
// Given a non-nil pointer ptr of type *T, where *T satisfies Fact,
250-
// fact copies the fact value to *ptr.
251-
func (act *action) importPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
252-
if pkg == nil {
253-
panic("nil package")
254-
}
255-
key := packageFactKey{pkg, act.factType(ptr)}
256-
if v, ok := act.packageFacts[key]; ok {
257-
reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
258-
return true
259-
}
260-
return false
261-
}
262-
263-
// exportPackageFact implements Pass.ExportPackageFact.
264-
func (act *action) exportPackageFact(fact analysis.Fact) {
265-
key := packageFactKey{act.pass.Pkg, act.factType(fact)}
266-
act.packageFacts[key] = fact // clobber any existing entry
267-
factsDebugf("%s: package %s has fact %s\n",
268-
act.pkg.Fset.Position(act.pass.Files[0].Pos()), act.pass.Pkg.Path(), fact)
269-
}
270-
271-
func (act *action) allPackageFacts() []analysis.PackageFact {
272-
out := make([]analysis.PackageFact, 0, len(act.packageFacts))
273-
for key, fact := range act.packageFacts {
274-
out = append(out, analysis.PackageFact{
275-
Package: key.pkg,
276-
Fact: fact,
277-
})
278-
}
279-
return out
280-
}
281-
282-
func (act *action) factType(fact analysis.Fact) reflect.Type {
283-
t := reflect.TypeOf(fact)
284-
if t.Kind() != reflect.Ptr {
285-
act.r.log.Fatalf("invalid Fact type: got %T, want pointer", t)
286-
}
287-
return t
288-
}
289-
290-
func (act *action) persistFactsToCache() error {
291-
analyzer := act.a
292-
if len(analyzer.FactTypes) == 0 {
293-
return nil
294-
}
295-
296-
// Merge new facts into the package and persist them.
297-
var facts []Fact
298-
for key, fact := range act.packageFacts {
299-
if key.pkg != act.pkg.Types {
300-
// The fact is from inherited facts from another package
301-
continue
302-
}
303-
facts = append(facts, Fact{
304-
Path: "",
305-
Fact: fact,
306-
})
307-
}
308-
for key, fact := range act.objectFacts {
309-
obj := key.obj
310-
if obj.Pkg() != act.pkg.Types {
311-
// The fact is from inherited facts from another package
312-
continue
313-
}
314-
315-
path, err := objectpath.For(obj)
316-
if err != nil {
317-
// The object is not globally addressable
318-
continue
319-
}
320-
321-
facts = append(facts, Fact{
322-
Path: string(path),
323-
Fact: fact,
324-
})
325-
}
326-
327-
factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name)
328-
329-
key := fmt.Sprintf("%s/facts", analyzer.Name)
330-
return act.r.pkgCache.Put(act.pkg, cache.HashModeNeedAllDeps, key, facts)
331-
}
332-
333-
func (act *action) loadPersistedFacts() bool {
334-
var facts []Fact
335-
key := fmt.Sprintf("%s/facts", act.a.Name)
336-
if err := act.r.pkgCache.Get(act.pkg, cache.HashModeNeedAllDeps, key, &facts); err != nil {
337-
if !errors.Is(err, cache.ErrMissing) && !errors.Is(err, io.EOF) {
338-
act.r.log.Warnf("Failed to get persisted facts: %s", err)
339-
}
340-
341-
factsCacheDebugf("No cached facts for package %q and analyzer %s", act.pkg.Name, act.a.Name)
342-
return false
343-
}
344-
345-
factsCacheDebugf("Loaded %d cached facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name)
346-
347-
for _, f := range facts {
348-
if f.Path == "" { // this is a package fact
349-
key := packageFactKey{act.pkg.Types, act.factType(f.Fact)}
350-
act.packageFacts[key] = f.Fact
351-
continue
352-
}
353-
obj, err := objectpath.Object(act.pkg.Types, objectpath.Path(f.Path))
354-
if err != nil {
355-
// Be lenient about these errors. For example, when
356-
// analyzing io/ioutil from source, we may get a fact
357-
// for methods on the devNull type, and objectpath
358-
// will happily create a path for them. However, when
359-
// we later load io/ioutil from export data, the path
360-
// no longer resolves.
361-
//
362-
// If an exported type embeds the unexported type,
363-
// then (part of) the unexported type will become part
364-
// of the type information and our path will resolve
365-
// again.
366-
continue
367-
}
368-
factKey := objectFactKey{obj, act.factType(f.Fact)}
369-
act.objectFacts[factKey] = f.Fact
370-
}
371-
372-
return true
373-
}
374-
37557
func (act *action) markDepsForAnalyzingSource() {
37658
// Horizontal deps (analyzer.Requires) must be loaded from source and analyzed before analyzing
37759
// this action.

0 commit comments

Comments
 (0)