1
1
package goanalysis
2
2
3
3
import (
4
- "errors"
5
4
"fmt"
6
- "go/types"
7
- "io"
8
- "reflect"
9
5
"runtime/debug"
10
- "time"
11
6
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"
17
7
"github.com/golangci/golangci-lint/internal/errorutil"
18
- "github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors"
19
8
)
20
9
21
10
type actionAllocator struct {
@@ -39,54 +28,6 @@ func (actAlloc *actionAllocator) alloc() *action {
39
28
return act
40
29
}
41
30
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
-
90
31
func (act * action ) waitUntilDependingAnalyzersWorked () {
91
32
for _ , dep := range act .deps {
92
33
if dep .pkg == act .pkg {
@@ -113,265 +54,6 @@ func (act *action) analyzeSafe() {
113
54
act .r .sw .TrackStage (act .a .Name , act .analyze )
114
55
}
115
56
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
-
375
57
func (act * action ) markDepsForAnalyzingSource () {
376
58
// Horizontal deps (analyzer.Requires) must be loaded from source and analyzed before analyzing
377
59
// this action.
0 commit comments