Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / analysis / internal / checker / checker.go
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package checker defines the implementation of the checker commands.
6 // The same code drives the multi-analysis driver, the single-analysis
7 // driver that is conventionally provided for convenience along with
8 // each analysis package, and the test driver.
9 package checker
10
11 import (
12         "bytes"
13         "encoding/gob"
14         "flag"
15         "fmt"
16         "go/format"
17         "go/parser"
18         "go/token"
19         "go/types"
20         "io/ioutil"
21         "log"
22         "os"
23         "reflect"
24         "runtime"
25         "runtime/pprof"
26         "runtime/trace"
27         "sort"
28         "strings"
29         "sync"
30         "time"
31
32         "golang.org/x/tools/go/analysis"
33         "golang.org/x/tools/go/analysis/internal/analysisflags"
34         "golang.org/x/tools/go/packages"
35         "golang.org/x/tools/internal/analysisinternal"
36         "golang.org/x/tools/internal/span"
37 )
38
39 var (
40         // Debug is a set of single-letter flags:
41         //
42         //      f       show [f]acts as they are created
43         //      p       disable [p]arallel execution of analyzers
44         //      s       do additional [s]anity checks on fact types and serialization
45         //      t       show [t]iming info (NB: use 'p' flag to avoid GC/scheduler noise)
46         //      v       show [v]erbose logging
47         //
48         Debug = ""
49
50         // Log files for optional performance tracing.
51         CPUProfile, MemProfile, Trace string
52
53         // Fix determines whether to apply all suggested fixes.
54         Fix bool
55 )
56
57 // RegisterFlags registers command-line flags used by the analysis driver.
58 func RegisterFlags() {
59         // When adding flags here, remember to update
60         // the list of suppressed flags in analysisflags.
61
62         flag.StringVar(&Debug, "debug", Debug, `debug flags, any subset of "fpstv"`)
63
64         flag.StringVar(&CPUProfile, "cpuprofile", "", "write CPU profile to this file")
65         flag.StringVar(&MemProfile, "memprofile", "", "write memory profile to this file")
66         flag.StringVar(&Trace, "trace", "", "write trace log to this file")
67
68         flag.BoolVar(&Fix, "fix", false, "apply all suggested fixes")
69 }
70
71 // Run loads the packages specified by args using go/packages,
72 // then applies the specified analyzers to them.
73 // Analysis flags must already have been set.
74 // It provides most of the logic for the main functions of both the
75 // singlechecker and the multi-analysis commands.
76 // It returns the appropriate exit code.
77 func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) {
78         if CPUProfile != "" {
79                 f, err := os.Create(CPUProfile)
80                 if err != nil {
81                         log.Fatal(err)
82                 }
83                 if err := pprof.StartCPUProfile(f); err != nil {
84                         log.Fatal(err)
85                 }
86                 // NB: profile won't be written in case of error.
87                 defer pprof.StopCPUProfile()
88         }
89
90         if Trace != "" {
91                 f, err := os.Create(Trace)
92                 if err != nil {
93                         log.Fatal(err)
94                 }
95                 if err := trace.Start(f); err != nil {
96                         log.Fatal(err)
97                 }
98                 // NB: trace log won't be written in case of error.
99                 defer func() {
100                         trace.Stop()
101                         log.Printf("To view the trace, run:\n$ go tool trace view %s", Trace)
102                 }()
103         }
104
105         if MemProfile != "" {
106                 f, err := os.Create(MemProfile)
107                 if err != nil {
108                         log.Fatal(err)
109                 }
110                 // NB: memprofile won't be written in case of error.
111                 defer func() {
112                         runtime.GC() // get up-to-date statistics
113                         if err := pprof.WriteHeapProfile(f); err != nil {
114                                 log.Fatalf("Writing memory profile: %v", err)
115                         }
116                         f.Close()
117                 }()
118         }
119
120         // Load the packages.
121         if dbg('v') {
122                 log.SetPrefix("")
123                 log.SetFlags(log.Lmicroseconds) // display timing
124                 log.Printf("load %s", args)
125         }
126
127         // Optimization: if the selected analyzers don't produce/consume
128         // facts, we need source only for the initial packages.
129         allSyntax := needFacts(analyzers)
130         initial, err := load(args, allSyntax)
131         if err != nil {
132                 log.Print(err)
133                 return 1 // load errors
134         }
135
136         // Print the results.
137         roots := analyze(initial, analyzers)
138
139         if Fix {
140                 applyFixes(roots)
141         }
142
143         return printDiagnostics(roots)
144 }
145
146 // load loads the initial packages.
147 func load(patterns []string, allSyntax bool) ([]*packages.Package, error) {
148         mode := packages.LoadSyntax
149         if allSyntax {
150                 mode = packages.LoadAllSyntax
151         }
152         conf := packages.Config{
153                 Mode:  mode,
154                 Tests: true,
155         }
156         initial, err := packages.Load(&conf, patterns...)
157         if err == nil {
158                 if n := packages.PrintErrors(initial); n > 1 {
159                         err = fmt.Errorf("%d errors during loading", n)
160                 } else if n == 1 {
161                         err = fmt.Errorf("error during loading")
162                 } else if len(initial) == 0 {
163                         err = fmt.Errorf("%s matched no packages", strings.Join(patterns, " "))
164                 }
165         }
166
167         return initial, err
168 }
169
170 // TestAnalyzer applies an analysis to a set of packages (and their
171 // dependencies if necessary) and returns the results.
172 //
173 // Facts about pkg are returned in a map keyed by object; package facts
174 // have a nil key.
175 //
176 // This entry point is used only by analysistest.
177 func TestAnalyzer(a *analysis.Analyzer, pkgs []*packages.Package) []*TestAnalyzerResult {
178         var results []*TestAnalyzerResult
179         for _, act := range analyze(pkgs, []*analysis.Analyzer{a}) {
180                 facts := make(map[types.Object][]analysis.Fact)
181                 for key, fact := range act.objectFacts {
182                         if key.obj.Pkg() == act.pass.Pkg {
183                                 facts[key.obj] = append(facts[key.obj], fact)
184                         }
185                 }
186                 for key, fact := range act.packageFacts {
187                         if key.pkg == act.pass.Pkg {
188                                 facts[nil] = append(facts[nil], fact)
189                         }
190                 }
191
192                 results = append(results, &TestAnalyzerResult{act.pass, act.diagnostics, facts, act.result, act.err})
193         }
194         return results
195 }
196
197 type TestAnalyzerResult struct {
198         Pass        *analysis.Pass
199         Diagnostics []analysis.Diagnostic
200         Facts       map[types.Object][]analysis.Fact
201         Result      interface{}
202         Err         error
203 }
204
205 func analyze(pkgs []*packages.Package, analyzers []*analysis.Analyzer) []*action {
206         // Construct the action graph.
207         if dbg('v') {
208                 log.Printf("building graph of analysis passes")
209         }
210
211         // Each graph node (action) is one unit of analysis.
212         // Edges express package-to-package (vertical) dependencies,
213         // and analysis-to-analysis (horizontal) dependencies.
214         type key struct {
215                 *analysis.Analyzer
216                 *packages.Package
217         }
218         actions := make(map[key]*action)
219
220         var mkAction func(a *analysis.Analyzer, pkg *packages.Package) *action
221         mkAction = func(a *analysis.Analyzer, pkg *packages.Package) *action {
222                 k := key{a, pkg}
223                 act, ok := actions[k]
224                 if !ok {
225                         act = &action{a: a, pkg: pkg}
226
227                         // Add a dependency on each required analyzers.
228                         for _, req := range a.Requires {
229                                 act.deps = append(act.deps, mkAction(req, pkg))
230                         }
231
232                         // An analysis that consumes/produces facts
233                         // must run on the package's dependencies too.
234                         if len(a.FactTypes) > 0 {
235                                 paths := make([]string, 0, len(pkg.Imports))
236                                 for path := range pkg.Imports {
237                                         paths = append(paths, path)
238                                 }
239                                 sort.Strings(paths) // for determinism
240                                 for _, path := range paths {
241                                         dep := mkAction(a, pkg.Imports[path])
242                                         act.deps = append(act.deps, dep)
243                                 }
244                         }
245
246                         actions[k] = act
247                 }
248                 return act
249         }
250
251         // Build nodes for initial packages.
252         var roots []*action
253         for _, a := range analyzers {
254                 for _, pkg := range pkgs {
255                         root := mkAction(a, pkg)
256                         root.isroot = true
257                         roots = append(roots, root)
258                 }
259         }
260
261         // Execute the graph in parallel.
262         execAll(roots)
263
264         return roots
265 }
266
267 func applyFixes(roots []*action) {
268         visited := make(map[*action]bool)
269         var apply func(*action) error
270         var visitAll func(actions []*action) error
271         visitAll = func(actions []*action) error {
272                 for _, act := range actions {
273                         if !visited[act] {
274                                 visited[act] = true
275                                 visitAll(act.deps)
276                                 if err := apply(act); err != nil {
277                                         return err
278                                 }
279                         }
280                 }
281                 return nil
282         }
283
284         // TODO(matloob): Is this tree business too complicated? (After all this is Go!)
285         // Just create a set (map) of edits, sort by pos and call it a day?
286         type offsetedit struct {
287                 start, end int
288                 newText    []byte
289         } // TextEdit using byteOffsets instead of pos
290         type node struct {
291                 edit        offsetedit
292                 left, right *node
293         }
294
295         var insert func(tree **node, edit offsetedit) error
296         insert = func(treeptr **node, edit offsetedit) error {
297                 if *treeptr == nil {
298                         *treeptr = &node{edit, nil, nil}
299                         return nil
300                 }
301                 tree := *treeptr
302                 if edit.end <= tree.edit.start {
303                         return insert(&tree.left, edit)
304                 } else if edit.start >= tree.edit.end {
305                         return insert(&tree.right, edit)
306                 }
307
308                 // Overlapping text edit.
309                 return fmt.Errorf("analyses applying overlapping text edits affecting pos range (%v, %v) and (%v, %v)",
310                         edit.start, edit.end, tree.edit.start, tree.edit.end)
311
312         }
313
314         editsForFile := make(map[*token.File]*node)
315
316         apply = func(act *action) error {
317                 for _, diag := range act.diagnostics {
318                         for _, sf := range diag.SuggestedFixes {
319                                 for _, edit := range sf.TextEdits {
320                                         // Validate the edit.
321                                         if edit.Pos > edit.End {
322                                                 return fmt.Errorf(
323                                                         "diagnostic for analysis %v contains Suggested Fix with malformed edit: pos (%v) > end (%v)",
324                                                         act.a.Name, edit.Pos, edit.End)
325                                         }
326                                         file, endfile := act.pkg.Fset.File(edit.Pos), act.pkg.Fset.File(edit.End)
327                                         if file == nil || endfile == nil || file != endfile {
328                                                 return (fmt.Errorf(
329                                                         "diagnostic for analysis %v contains Suggested Fix with malformed spanning files %v and %v",
330                                                         act.a.Name, file.Name(), endfile.Name()))
331                                         }
332                                         start, end := file.Offset(edit.Pos), file.Offset(edit.End)
333
334                                         // TODO(matloob): Validate that edits do not affect other packages.
335                                         root := editsForFile[file]
336                                         if err := insert(&root, offsetedit{start, end, edit.NewText}); err != nil {
337                                                 return err
338                                         }
339                                         editsForFile[file] = root // In case the root changed
340                                 }
341                         }
342                 }
343                 return nil
344         }
345
346         visitAll(roots)
347
348         fset := token.NewFileSet() // Shared by parse calls below
349         // Now we've got a set of valid edits for each file. Get the new file contents.
350         for f, tree := range editsForFile {
351                 contents, err := ioutil.ReadFile(f.Name())
352                 if err != nil {
353                         log.Fatal(err)
354                 }
355
356                 cur := 0 // current position in the file
357
358                 var out bytes.Buffer
359
360                 var recurse func(*node)
361                 recurse = func(node *node) {
362                         if node.left != nil {
363                                 recurse(node.left)
364                         }
365
366                         edit := node.edit
367                         if edit.start > cur {
368                                 out.Write(contents[cur:edit.start])
369                                 out.Write(edit.newText)
370                         }
371                         cur = edit.end
372
373                         if node.right != nil {
374                                 recurse(node.right)
375                         }
376                 }
377                 recurse(tree)
378                 // Write out the rest of the file.
379                 if cur < len(contents) {
380                         out.Write(contents[cur:])
381                 }
382
383                 // Try to format the file.
384                 ff, err := parser.ParseFile(fset, f.Name(), out.Bytes(), parser.ParseComments)
385                 if err == nil {
386                         var buf bytes.Buffer
387                         if err = format.Node(&buf, fset, ff); err == nil {
388                                 out = buf
389                         }
390                 }
391
392                 ioutil.WriteFile(f.Name(), out.Bytes(), 0644)
393         }
394 }
395
396 // printDiagnostics prints the diagnostics for the root packages in either
397 // plain text or JSON format. JSON format also includes errors for any
398 // dependencies.
399 //
400 // It returns the exitcode: in plain mode, 0 for success, 1 for analysis
401 // errors, and 3 for diagnostics. We avoid 2 since the flag package uses
402 // it. JSON mode always succeeds at printing errors and diagnostics in a
403 // structured form to stdout.
404 func printDiagnostics(roots []*action) (exitcode int) {
405         // Print the output.
406         //
407         // Print diagnostics only for root packages,
408         // but errors for all packages.
409         printed := make(map[*action]bool)
410         var print func(*action)
411         var visitAll func(actions []*action)
412         visitAll = func(actions []*action) {
413                 for _, act := range actions {
414                         if !printed[act] {
415                                 printed[act] = true
416                                 visitAll(act.deps)
417                                 print(act)
418                         }
419                 }
420         }
421
422         if analysisflags.JSON {
423                 // JSON output
424                 tree := make(analysisflags.JSONTree)
425                 print = func(act *action) {
426                         var diags []analysis.Diagnostic
427                         if act.isroot {
428                                 diags = act.diagnostics
429                         }
430                         tree.Add(act.pkg.Fset, act.pkg.ID, act.a.Name, diags, act.err)
431                 }
432                 visitAll(roots)
433                 tree.Print()
434         } else {
435                 // plain text output
436
437                 // De-duplicate diagnostics by position (not token.Pos) to
438                 // avoid double-reporting in source files that belong to
439                 // multiple packages, such as foo and foo.test.
440                 type key struct {
441                         pos token.Position
442                         end token.Position
443                         *analysis.Analyzer
444                         message string
445                 }
446                 seen := make(map[key]bool)
447
448                 print = func(act *action) {
449                         if act.err != nil {
450                                 fmt.Fprintf(os.Stderr, "%s: %v\n", act.a.Name, act.err)
451                                 exitcode = 1 // analysis failed, at least partially
452                                 return
453                         }
454                         if act.isroot {
455                                 for _, diag := range act.diagnostics {
456                                         // We don't display a.Name/f.Category
457                                         // as most users don't care.
458
459                                         posn := act.pkg.Fset.Position(diag.Pos)
460                                         end := act.pkg.Fset.Position(diag.End)
461                                         k := key{posn, end, act.a, diag.Message}
462                                         if seen[k] {
463                                                 continue // duplicate
464                                         }
465                                         seen[k] = true
466
467                                         analysisflags.PrintPlain(act.pkg.Fset, diag)
468                                 }
469                         }
470                 }
471                 visitAll(roots)
472
473                 if exitcode == 0 && len(seen) > 0 {
474                         exitcode = 3 // successfully produced diagnostics
475                 }
476         }
477
478         // Print timing info.
479         if dbg('t') {
480                 if !dbg('p') {
481                         log.Println("Warning: times are mostly GC/scheduler noise; use -debug=tp to disable parallelism")
482                 }
483                 var all []*action
484                 var total time.Duration
485                 for act := range printed {
486                         all = append(all, act)
487                         total += act.duration
488                 }
489                 sort.Slice(all, func(i, j int) bool {
490                         return all[i].duration > all[j].duration
491                 })
492
493                 // Print actions accounting for 90% of the total.
494                 var sum time.Duration
495                 for _, act := range all {
496                         fmt.Fprintf(os.Stderr, "%s\t%s\n", act.duration, act)
497                         sum += act.duration
498                         if sum >= total*9/10 {
499                                 break
500                         }
501                 }
502         }
503
504         return exitcode
505 }
506
507 // needFacts reports whether any analysis required by the specified set
508 // needs facts.  If so, we must load the entire program from source.
509 func needFacts(analyzers []*analysis.Analyzer) bool {
510         seen := make(map[*analysis.Analyzer]bool)
511         var q []*analysis.Analyzer // for BFS
512         q = append(q, analyzers...)
513         for len(q) > 0 {
514                 a := q[0]
515                 q = q[1:]
516                 if !seen[a] {
517                         seen[a] = true
518                         if len(a.FactTypes) > 0 {
519                                 return true
520                         }
521                         q = append(q, a.Requires...)
522                 }
523         }
524         return false
525 }
526
527 // An action represents one unit of analysis work: the application of
528 // one analysis to one package. Actions form a DAG, both within a
529 // package (as different analyzers are applied, either in sequence or
530 // parallel), and across packages (as dependencies are analyzed).
531 type action struct {
532         once         sync.Once
533         a            *analysis.Analyzer
534         pkg          *packages.Package
535         pass         *analysis.Pass
536         isroot       bool
537         deps         []*action
538         objectFacts  map[objectFactKey]analysis.Fact
539         packageFacts map[packageFactKey]analysis.Fact
540         inputs       map[*analysis.Analyzer]interface{}
541         result       interface{}
542         diagnostics  []analysis.Diagnostic
543         err          error
544         duration     time.Duration
545 }
546
547 type objectFactKey struct {
548         obj types.Object
549         typ reflect.Type
550 }
551
552 type packageFactKey struct {
553         pkg *types.Package
554         typ reflect.Type
555 }
556
557 func (act *action) String() string {
558         return fmt.Sprintf("%s@%s", act.a, act.pkg)
559 }
560
561 func execAll(actions []*action) {
562         sequential := dbg('p')
563         var wg sync.WaitGroup
564         for _, act := range actions {
565                 wg.Add(1)
566                 work := func(act *action) {
567                         act.exec()
568                         wg.Done()
569                 }
570                 if sequential {
571                         work(act)
572                 } else {
573                         go work(act)
574                 }
575         }
576         wg.Wait()
577 }
578
579 func (act *action) exec() { act.once.Do(act.execOnce) }
580
581 func (act *action) execOnce() {
582         // Analyze dependencies.
583         execAll(act.deps)
584
585         // TODO(adonovan): uncomment this during profiling.
586         // It won't build pre-go1.11 but conditional compilation
587         // using build tags isn't warranted.
588         //
589         // ctx, task := trace.NewTask(context.Background(), "exec")
590         // trace.Log(ctx, "pass", act.String())
591         // defer task.End()
592
593         // Record time spent in this node but not its dependencies.
594         // In parallel mode, due to GC/scheduler contention, the
595         // time is 5x higher than in sequential mode, even with a
596         // semaphore limiting the number of threads here.
597         // So use -debug=tp.
598         if dbg('t') {
599                 t0 := time.Now()
600                 defer func() { act.duration = time.Since(t0) }()
601         }
602
603         // Report an error if any dependency failed.
604         var failed []string
605         for _, dep := range act.deps {
606                 if dep.err != nil {
607                         failed = append(failed, dep.String())
608                 }
609         }
610         if failed != nil {
611                 sort.Strings(failed)
612                 act.err = fmt.Errorf("failed prerequisites: %s", strings.Join(failed, ", "))
613                 return
614         }
615
616         // Plumb the output values of the dependencies
617         // into the inputs of this action.  Also facts.
618         inputs := make(map[*analysis.Analyzer]interface{})
619         act.objectFacts = make(map[objectFactKey]analysis.Fact)
620         act.packageFacts = make(map[packageFactKey]analysis.Fact)
621         for _, dep := range act.deps {
622                 if dep.pkg == act.pkg {
623                         // Same package, different analysis (horizontal edge):
624                         // in-memory outputs of prerequisite analyzers
625                         // become inputs to this analysis pass.
626                         inputs[dep.a] = dep.result
627
628                 } else if dep.a == act.a { // (always true)
629                         // Same analysis, different package (vertical edge):
630                         // serialized facts produced by prerequisite analysis
631                         // become available to this analysis pass.
632                         inheritFacts(act, dep)
633                 }
634         }
635
636         // Run the analysis.
637         pass := &analysis.Pass{
638                 Analyzer:          act.a,
639                 Fset:              act.pkg.Fset,
640                 Files:             act.pkg.Syntax,
641                 OtherFiles:        act.pkg.OtherFiles,
642                 IgnoredFiles:      act.pkg.IgnoredFiles,
643                 Pkg:               act.pkg.Types,
644                 TypesInfo:         act.pkg.TypesInfo,
645                 TypesSizes:        act.pkg.TypesSizes,
646                 ResultOf:          inputs,
647                 Report:            func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
648                 ImportObjectFact:  act.importObjectFact,
649                 ExportObjectFact:  act.exportObjectFact,
650                 ImportPackageFact: act.importPackageFact,
651                 ExportPackageFact: act.exportPackageFact,
652                 AllObjectFacts:    act.allObjectFacts,
653                 AllPackageFacts:   act.allPackageFacts,
654         }
655         act.pass = pass
656
657         var errors []types.Error
658         // Get any type errors that are attributed to the pkg.
659         // This is necessary to test analyzers that provide
660         // suggested fixes for compiler/type errors.
661         for _, err := range act.pkg.Errors {
662                 if err.Kind != packages.TypeError {
663                         continue
664                 }
665                 // err.Pos is a string of form: "file:line:col" or "file:line" or "" or "-"
666                 spn := span.Parse(err.Pos)
667                 // Extract the token positions from the error string.
668                 line, col, offset := spn.Start().Line(), spn.Start().Column(), -1
669                 act.pkg.Fset.Iterate(func(f *token.File) bool {
670                         if f.Name() != spn.URI().Filename() {
671                                 return true
672                         }
673                         offset = int(f.LineStart(line)) + col - 1
674                         return false
675                 })
676                 if offset == -1 {
677                         continue
678                 }
679                 errors = append(errors, types.Error{
680                         Fset: act.pkg.Fset,
681                         Msg:  err.Msg,
682                         Pos:  token.Pos(offset),
683                 })
684         }
685         analysisinternal.SetTypeErrors(pass, errors)
686
687         var err error
688         if act.pkg.IllTyped && !pass.Analyzer.RunDespiteErrors {
689                 err = fmt.Errorf("analysis skipped due to errors in package")
690         } else {
691                 act.result, err = pass.Analyzer.Run(pass)
692                 if err == nil {
693                         if got, want := reflect.TypeOf(act.result), pass.Analyzer.ResultType; got != want {
694                                 err = fmt.Errorf(
695                                         "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v",
696                                         pass.Pkg.Path(), pass.Analyzer, got, want)
697                         }
698                 }
699         }
700         act.err = err
701
702         // disallow calls after Run
703         pass.ExportObjectFact = nil
704         pass.ExportPackageFact = nil
705 }
706
707 // inheritFacts populates act.facts with
708 // those it obtains from its dependency, dep.
709 func inheritFacts(act, dep *action) {
710         serialize := dbg('s')
711
712         for key, fact := range dep.objectFacts {
713                 // Filter out facts related to objects
714                 // that are irrelevant downstream
715                 // (equivalently: not in the compiler export data).
716                 if !exportedFrom(key.obj, dep.pkg.Types) {
717                         if false {
718                                 log.Printf("%v: discarding %T fact from %s for %s: %s", act, fact, dep, key.obj, fact)
719                         }
720                         continue
721                 }
722
723                 // Optionally serialize/deserialize fact
724                 // to verify that it works across address spaces.
725                 if serialize {
726                         encodedFact, err := codeFact(fact)
727                         if err != nil {
728                                 log.Panicf("internal error: encoding of %T fact failed in %v", fact, act)
729                         }
730                         fact = encodedFact
731                 }
732
733                 if false {
734                         log.Printf("%v: inherited %T fact for %s: %s", act, fact, key.obj, fact)
735                 }
736                 act.objectFacts[key] = fact
737         }
738
739         for key, fact := range dep.packageFacts {
740                 // TODO: filter out facts that belong to
741                 // packages not mentioned in the export data
742                 // to prevent side channels.
743
744                 // Optionally serialize/deserialize fact
745                 // to verify that it works across address spaces
746                 // and is deterministic.
747                 if serialize {
748                         encodedFact, err := codeFact(fact)
749                         if err != nil {
750                                 log.Panicf("internal error: encoding of %T fact failed in %v", fact, act)
751                         }
752                         fact = encodedFact
753                 }
754
755                 if false {
756                         log.Printf("%v: inherited %T fact for %s: %s", act, fact, key.pkg.Path(), fact)
757                 }
758                 act.packageFacts[key] = fact
759         }
760 }
761
762 // codeFact encodes then decodes a fact,
763 // just to exercise that logic.
764 func codeFact(fact analysis.Fact) (analysis.Fact, error) {
765         // We encode facts one at a time.
766         // A real modular driver would emit all facts
767         // into one encoder to improve gob efficiency.
768         var buf bytes.Buffer
769         if err := gob.NewEncoder(&buf).Encode(fact); err != nil {
770                 return nil, err
771         }
772
773         // Encode it twice and assert that we get the same bits.
774         // This helps detect nondeterministic Gob encoding (e.g. of maps).
775         var buf2 bytes.Buffer
776         if err := gob.NewEncoder(&buf2).Encode(fact); err != nil {
777                 return nil, err
778         }
779         if !bytes.Equal(buf.Bytes(), buf2.Bytes()) {
780                 return nil, fmt.Errorf("encoding of %T fact is nondeterministic", fact)
781         }
782
783         new := reflect.New(reflect.TypeOf(fact).Elem()).Interface().(analysis.Fact)
784         if err := gob.NewDecoder(&buf).Decode(new); err != nil {
785                 return nil, err
786         }
787         return new, nil
788 }
789
790 // exportedFrom reports whether obj may be visible to a package that imports pkg.
791 // This includes not just the exported members of pkg, but also unexported
792 // constants, types, fields, and methods, perhaps belonging to oether packages,
793 // that find there way into the API.
794 // This is an overapproximation of the more accurate approach used by
795 // gc export data, which walks the type graph, but it's much simpler.
796 //
797 // TODO(adonovan): do more accurate filtering by walking the type graph.
798 func exportedFrom(obj types.Object, pkg *types.Package) bool {
799         switch obj := obj.(type) {
800         case *types.Func:
801                 return obj.Exported() && obj.Pkg() == pkg ||
802                         obj.Type().(*types.Signature).Recv() != nil
803         case *types.Var:
804                 if obj.IsField() {
805                         return true
806                 }
807                 // we can't filter more aggressively than this because we need
808                 // to consider function parameters exported, but have no way
809                 // of telling apart function parameters from local variables.
810                 return obj.Pkg() == pkg
811         case *types.TypeName, *types.Const:
812                 return true
813         }
814         return false // Nil, Builtin, Label, or PkgName
815 }
816
817 // importObjectFact implements Pass.ImportObjectFact.
818 // Given a non-nil pointer ptr of type *T, where *T satisfies Fact,
819 // importObjectFact copies the fact value to *ptr.
820 func (act *action) importObjectFact(obj types.Object, ptr analysis.Fact) bool {
821         if obj == nil {
822                 panic("nil object")
823         }
824         key := objectFactKey{obj, factType(ptr)}
825         if v, ok := act.objectFacts[key]; ok {
826                 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
827                 return true
828         }
829         return false
830 }
831
832 // exportObjectFact implements Pass.ExportObjectFact.
833 func (act *action) exportObjectFact(obj types.Object, fact analysis.Fact) {
834         if act.pass.ExportObjectFact == nil {
835                 log.Panicf("%s: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact)
836         }
837
838         if obj.Pkg() != act.pkg.Types {
839                 log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package",
840                         act.a, act.pkg, obj, fact)
841         }
842
843         key := objectFactKey{obj, factType(fact)}
844         act.objectFacts[key] = fact // clobber any existing entry
845         if dbg('f') {
846                 objstr := types.ObjectString(obj, (*types.Package).Name)
847                 fmt.Fprintf(os.Stderr, "%s: object %s has fact %s\n",
848                         act.pkg.Fset.Position(obj.Pos()), objstr, fact)
849         }
850 }
851
852 // allObjectFacts implements Pass.AllObjectFacts.
853 func (act *action) allObjectFacts() []analysis.ObjectFact {
854         facts := make([]analysis.ObjectFact, 0, len(act.objectFacts))
855         for k := range act.objectFacts {
856                 facts = append(facts, analysis.ObjectFact{k.obj, act.objectFacts[k]})
857         }
858         return facts
859 }
860
861 // importPackageFact implements Pass.ImportPackageFact.
862 // Given a non-nil pointer ptr of type *T, where *T satisfies Fact,
863 // fact copies the fact value to *ptr.
864 func (act *action) importPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
865         if pkg == nil {
866                 panic("nil package")
867         }
868         key := packageFactKey{pkg, factType(ptr)}
869         if v, ok := act.packageFacts[key]; ok {
870                 reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
871                 return true
872         }
873         return false
874 }
875
876 // exportPackageFact implements Pass.ExportPackageFact.
877 func (act *action) exportPackageFact(fact analysis.Fact) {
878         if act.pass.ExportPackageFact == nil {
879                 log.Panicf("%s: Pass.ExportPackageFact(%T) called after Run", act, fact)
880         }
881
882         key := packageFactKey{act.pass.Pkg, factType(fact)}
883         act.packageFacts[key] = fact // clobber any existing entry
884         if dbg('f') {
885                 fmt.Fprintf(os.Stderr, "%s: package %s has fact %s\n",
886                         act.pkg.Fset.Position(act.pass.Files[0].Pos()), act.pass.Pkg.Path(), fact)
887         }
888 }
889
890 func factType(fact analysis.Fact) reflect.Type {
891         t := reflect.TypeOf(fact)
892         if t.Kind() != reflect.Ptr {
893                 log.Fatalf("invalid Fact type: got %T, want pointer", t)
894         }
895         return t
896 }
897
898 // allObjectFacts implements Pass.AllObjectFacts.
899 func (act *action) allPackageFacts() []analysis.PackageFact {
900         facts := make([]analysis.PackageFact, 0, len(act.packageFacts))
901         for k := range act.packageFacts {
902                 facts = append(facts, analysis.PackageFact{k.pkg, act.packageFacts[k]})
903         }
904         return facts
905 }
906
907 func dbg(b byte) bool { return strings.IndexByte(Debug, b) >= 0 }