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 / facts / facts.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/go/analysis/internal/facts/facts.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/go/analysis/internal/facts/facts.go
new file mode 100644 (file)
index 0000000..1fb69c6
--- /dev/null
@@ -0,0 +1,323 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package facts defines a serializable set of analysis.Fact.
+//
+// It provides a partial implementation of the Fact-related parts of the
+// analysis.Pass interface for use in analysis drivers such as "go vet"
+// and other build systems.
+//
+// The serial format is unspecified and may change, so the same version
+// of this package must be used for reading and writing serialized facts.
+//
+// The handling of facts in the analysis system parallels the handling
+// of type information in the compiler: during compilation of package P,
+// the compiler emits an export data file that describes the type of
+// every object (named thing) defined in package P, plus every object
+// indirectly reachable from one of those objects. Thus the downstream
+// compiler of package Q need only load one export data file per direct
+// import of Q, and it will learn everything about the API of package P
+// and everything it needs to know about the API of P's dependencies.
+//
+// Similarly, analysis of package P emits a fact set containing facts
+// about all objects exported from P, plus additional facts about only
+// those objects of P's dependencies that are reachable from the API of
+// package P; the downstream analysis of Q need only load one fact set
+// per direct import of Q.
+//
+// The notion of "exportedness" that matters here is that of the
+// compiler. According to the language spec, a method pkg.T.f is
+// unexported simply because its name starts with lowercase. But the
+// compiler must nonetheless export f so that downstream compilations can
+// accurately ascertain whether pkg.T implements an interface pkg.I
+// defined as interface{f()}. Exported thus means "described in export
+// data".
+//
+package facts
+
+import (
+       "bytes"
+       "encoding/gob"
+       "fmt"
+       "go/types"
+       "io/ioutil"
+       "log"
+       "reflect"
+       "sort"
+       "sync"
+
+       "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/go/types/objectpath"
+)
+
+const debug = false
+
+// A Set is a set of analysis.Facts.
+//
+// Decode creates a Set of facts by reading from the imports of a given
+// package, and Encode writes out the set. Between these operation,
+// the Import and Export methods will query and update the set.
+//
+// All of Set's methods except String are safe to call concurrently.
+type Set struct {
+       pkg *types.Package
+       mu  sync.Mutex
+       m   map[key]analysis.Fact
+}
+
+type key struct {
+       pkg *types.Package
+       obj types.Object // (object facts only)
+       t   reflect.Type
+}
+
+// ImportObjectFact implements analysis.Pass.ImportObjectFact.
+func (s *Set) ImportObjectFact(obj types.Object, ptr analysis.Fact) bool {
+       if obj == nil {
+               panic("nil object")
+       }
+       key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(ptr)}
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       if v, ok := s.m[key]; ok {
+               reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
+               return true
+       }
+       return false
+}
+
+// ExportObjectFact implements analysis.Pass.ExportObjectFact.
+func (s *Set) ExportObjectFact(obj types.Object, fact analysis.Fact) {
+       if obj.Pkg() != s.pkg {
+               log.Panicf("in package %s: ExportObjectFact(%s, %T): can't set fact on object belonging another package",
+                       s.pkg, obj, fact)
+       }
+       key := key{pkg: obj.Pkg(), obj: obj, t: reflect.TypeOf(fact)}
+       s.mu.Lock()
+       s.m[key] = fact // clobber any existing entry
+       s.mu.Unlock()
+}
+
+func (s *Set) AllObjectFacts(filter map[reflect.Type]bool) []analysis.ObjectFact {
+       var facts []analysis.ObjectFact
+       s.mu.Lock()
+       for k, v := range s.m {
+               if k.obj != nil && filter[k.t] {
+                       facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: v})
+               }
+       }
+       s.mu.Unlock()
+       return facts
+}
+
+// ImportPackageFact implements analysis.Pass.ImportPackageFact.
+func (s *Set) ImportPackageFact(pkg *types.Package, ptr analysis.Fact) bool {
+       if pkg == nil {
+               panic("nil package")
+       }
+       key := key{pkg: pkg, t: reflect.TypeOf(ptr)}
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       if v, ok := s.m[key]; ok {
+               reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem())
+               return true
+       }
+       return false
+}
+
+// ExportPackageFact implements analysis.Pass.ExportPackageFact.
+func (s *Set) ExportPackageFact(fact analysis.Fact) {
+       key := key{pkg: s.pkg, t: reflect.TypeOf(fact)}
+       s.mu.Lock()
+       s.m[key] = fact // clobber any existing entry
+       s.mu.Unlock()
+}
+
+func (s *Set) AllPackageFacts(filter map[reflect.Type]bool) []analysis.PackageFact {
+       var facts []analysis.PackageFact
+       s.mu.Lock()
+       for k, v := range s.m {
+               if k.obj == nil && filter[k.t] {
+                       facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: v})
+               }
+       }
+       s.mu.Unlock()
+       return facts
+}
+
+// gobFact is the Gob declaration of a serialized fact.
+type gobFact struct {
+       PkgPath string          // path of package
+       Object  objectpath.Path // optional path of object relative to package itself
+       Fact    analysis.Fact   // type and value of user-defined Fact
+}
+
+// Decode decodes all the facts relevant to the analysis of package pkg.
+// The read function reads serialized fact data from an external source
+// for one of of pkg's direct imports. The empty file is a valid
+// encoding of an empty fact set.
+//
+// It is the caller's responsibility to call gob.Register on all
+// necessary fact types.
+func Decode(pkg *types.Package, read func(packagePath string) ([]byte, error)) (*Set, error) {
+       // Compute the import map for this package.
+       // See the package doc comment.
+       packages := importMap(pkg.Imports())
+
+       // Read facts from imported packages.
+       // Facts may describe indirectly imported packages, or their objects.
+       m := make(map[key]analysis.Fact) // one big bucket
+       for _, imp := range pkg.Imports() {
+               logf := func(format string, args ...interface{}) {
+                       if debug {
+                               prefix := fmt.Sprintf("in %s, importing %s: ",
+                                       pkg.Path(), imp.Path())
+                               log.Print(prefix, fmt.Sprintf(format, args...))
+                       }
+               }
+
+               // Read the gob-encoded facts.
+               data, err := read(imp.Path())
+               if err != nil {
+                       return nil, fmt.Errorf("in %s, can't import facts for package %q: %v",
+                               pkg.Path(), imp.Path(), err)
+               }
+               if len(data) == 0 {
+                       continue // no facts
+               }
+               var gobFacts []gobFact
+               if err := gob.NewDecoder(bytes.NewReader(data)).Decode(&gobFacts); err != nil {
+                       return nil, fmt.Errorf("decoding facts for %q: %v", imp.Path(), err)
+               }
+               if debug {
+                       logf("decoded %d facts: %v", len(gobFacts), gobFacts)
+               }
+
+               // Parse each one into a key and a Fact.
+               for _, f := range gobFacts {
+                       factPkg := packages[f.PkgPath]
+                       if factPkg == nil {
+                               // Fact relates to a dependency that was
+                               // unused in this translation unit. Skip.
+                               logf("no package %q; discarding %v", f.PkgPath, f.Fact)
+                               continue
+                       }
+                       key := key{pkg: factPkg, t: reflect.TypeOf(f.Fact)}
+                       if f.Object != "" {
+                               // object fact
+                               obj, err := objectpath.Object(factPkg, f.Object)
+                               if err != nil {
+                                       // (most likely due to unexported object)
+                                       // TODO(adonovan): audit for other possibilities.
+                                       logf("no object for path: %v; discarding %s", err, f.Fact)
+                                       continue
+                               }
+                               key.obj = obj
+                               logf("read %T fact %s for %v", f.Fact, f.Fact, key.obj)
+                       } else {
+                               // package fact
+                               logf("read %T fact %s for %v", f.Fact, f.Fact, factPkg)
+                       }
+                       m[key] = f.Fact
+               }
+       }
+
+       return &Set{pkg: pkg, m: m}, nil
+}
+
+// Encode encodes a set of facts to a memory buffer.
+//
+// It may fail if one of the Facts could not be gob-encoded, but this is
+// a sign of a bug in an Analyzer.
+func (s *Set) Encode() []byte {
+
+       // TODO(adonovan): opt: use a more efficient encoding
+       // that avoids repeating PkgPath for each fact.
+
+       // Gather all facts, including those from imported packages.
+       var gobFacts []gobFact
+
+       s.mu.Lock()
+       for k, fact := range s.m {
+               if debug {
+                       log.Printf("%v => %s\n", k, fact)
+               }
+               var object objectpath.Path
+               if k.obj != nil {
+                       path, err := objectpath.For(k.obj)
+                       if err != nil {
+                               if debug {
+                                       log.Printf("discarding fact %s about %s\n", fact, k.obj)
+                               }
+                               continue // object not accessible from package API; discard fact
+                       }
+                       object = path
+               }
+               gobFacts = append(gobFacts, gobFact{
+                       PkgPath: k.pkg.Path(),
+                       Object:  object,
+                       Fact:    fact,
+               })
+       }
+       s.mu.Unlock()
+
+       // Sort facts by (package, object, type) for determinism.
+       sort.Slice(gobFacts, func(i, j int) bool {
+               x, y := gobFacts[i], gobFacts[j]
+               if x.PkgPath != y.PkgPath {
+                       return x.PkgPath < y.PkgPath
+               }
+               if x.Object != y.Object {
+                       return x.Object < y.Object
+               }
+               tx := reflect.TypeOf(x.Fact)
+               ty := reflect.TypeOf(y.Fact)
+               if tx != ty {
+                       return tx.String() < ty.String()
+               }
+               return false // equal
+       })
+
+       var buf bytes.Buffer
+       if len(gobFacts) > 0 {
+               if err := gob.NewEncoder(&buf).Encode(gobFacts); err != nil {
+                       // Fact encoding should never fail. Identify the culprit.
+                       for _, gf := range gobFacts {
+                               if err := gob.NewEncoder(ioutil.Discard).Encode(gf); err != nil {
+                                       fact := gf.Fact
+                                       pkgpath := reflect.TypeOf(fact).Elem().PkgPath()
+                                       log.Panicf("internal error: gob encoding of analysis fact %s failed: %v; please report a bug against fact %T in package %q",
+                                               fact, err, fact, pkgpath)
+                               }
+                       }
+               }
+       }
+
+       if debug {
+               log.Printf("package %q: encode %d facts, %d bytes\n",
+                       s.pkg.Path(), len(gobFacts), buf.Len())
+       }
+
+       return buf.Bytes()
+}
+
+// String is provided only for debugging, and must not be called
+// concurrent with any Import/Export method.
+func (s *Set) String() string {
+       var buf bytes.Buffer
+       buf.WriteString("{")
+       for k, f := range s.m {
+               if buf.Len() > 1 {
+                       buf.WriteString(", ")
+               }
+               if k.obj != nil {
+                       buf.WriteString(k.obj.String())
+               } else {
+                       buf.WriteString(k.pkg.Path())
+               }
+               fmt.Fprintf(&buf, ": %v", f)
+       }
+       buf.WriteString("}")
+       return buf.String()
+}