Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / godoc / versions.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/godoc/versions.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/godoc/versions.go
new file mode 100644 (file)
index 0000000..f03c714
--- /dev/null
@@ -0,0 +1,224 @@
+// 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.
+
+// This file caches information about which standard library types, methods,
+// and functions appeared in what version of Go
+
+package godoc
+
+import (
+       "bufio"
+       "go/build"
+       "log"
+       "os"
+       "path/filepath"
+       "strings"
+       "unicode"
+)
+
+// apiVersions is a map of packages to information about those packages'
+// symbols and when they were added to Go.
+//
+// Only things added after Go1 are tracked. Version strings are of the
+// form "1.1", "1.2", etc.
+type apiVersions map[string]pkgAPIVersions // keyed by Go package ("net/http")
+
+// pkgAPIVersions contains information about which version of Go added
+// certain package symbols.
+//
+// Only things added after Go1 are tracked. Version strings are of the
+// form "1.1", "1.2", etc.
+type pkgAPIVersions struct {
+       typeSince   map[string]string            // "Server" -> "1.7"
+       methodSince map[string]map[string]string // "*Server" ->"Shutdown"->1.8
+       funcSince   map[string]string            // "NewServer" -> "1.7"
+       fieldSince  map[string]map[string]string // "ClientTrace" -> "Got1xxResponse" -> "1.11"
+}
+
+// sinceVersionFunc returns a string (such as "1.7") specifying which Go
+// version introduced a symbol, unless it was introduced in Go1, in
+// which case it returns the empty string.
+//
+// The kind is one of "type", "method", or "func".
+//
+// The receiver is only used for "methods" and specifies the receiver type,
+// such as "*Server".
+//
+// The name is the symbol name ("Server") and the pkg is the package
+// ("net/http").
+func (v apiVersions) sinceVersionFunc(kind, receiver, name, pkg string) string {
+       pv := v[pkg]
+       switch kind {
+       case "func":
+               return pv.funcSince[name]
+       case "type":
+               return pv.typeSince[name]
+       case "method":
+               return pv.methodSince[receiver][name]
+       }
+       return ""
+}
+
+// versionedRow represents an API feature, a parsed line of a
+// $GOROOT/api/go.*txt file.
+type versionedRow struct {
+       pkg        string // "net/http"
+       kind       string // "type", "func", "method", "field" TODO: "const", "var"
+       recv       string // for methods, the receiver type ("Server", "*Server")
+       name       string // name of type, (struct) field, func, method
+       structName string // for struct fields, the outer struct name
+}
+
+// versionParser parses $GOROOT/api/go*.txt files and stores them in in its rows field.
+type versionParser struct {
+       res apiVersions // initialized lazily
+}
+
+func (vp *versionParser) parseFile(name string) error {
+       base := filepath.Base(name)
+       ver := strings.TrimPrefix(strings.TrimSuffix(base, ".txt"), "go")
+       if ver == "1" {
+               return nil
+       }
+       f, err := os.Open(name)
+       if err != nil {
+               return err
+       }
+       defer f.Close()
+
+       sc := bufio.NewScanner(f)
+       for sc.Scan() {
+               row, ok := parseRow(sc.Text())
+               if !ok {
+                       continue
+               }
+               if vp.res == nil {
+                       vp.res = make(apiVersions)
+               }
+               pkgi, ok := vp.res[row.pkg]
+               if !ok {
+                       pkgi = pkgAPIVersions{
+                               typeSince:   make(map[string]string),
+                               methodSince: make(map[string]map[string]string),
+                               funcSince:   make(map[string]string),
+                               fieldSince:  make(map[string]map[string]string),
+                       }
+                       vp.res[row.pkg] = pkgi
+               }
+               switch row.kind {
+               case "func":
+                       pkgi.funcSince[row.name] = ver
+               case "type":
+                       pkgi.typeSince[row.name] = ver
+               case "method":
+                       if _, ok := pkgi.methodSince[row.recv]; !ok {
+                               pkgi.methodSince[row.recv] = make(map[string]string)
+                       }
+                       pkgi.methodSince[row.recv][row.name] = ver
+               case "field":
+                       if _, ok := pkgi.fieldSince[row.structName]; !ok {
+                               pkgi.fieldSince[row.structName] = make(map[string]string)
+                       }
+                       pkgi.fieldSince[row.structName][row.name] = ver
+               }
+       }
+       return sc.Err()
+}
+
+func parseRow(s string) (vr versionedRow, ok bool) {
+       if !strings.HasPrefix(s, "pkg ") {
+               // Skip comments, blank lines, etc.
+               return
+       }
+       rest := s[len("pkg "):]
+       endPkg := strings.IndexFunc(rest, func(r rune) bool { return !(unicode.IsLetter(r) || r == '/' || unicode.IsDigit(r)) })
+       if endPkg == -1 {
+               return
+       }
+       vr.pkg, rest = rest[:endPkg], rest[endPkg:]
+       if !strings.HasPrefix(rest, ", ") {
+               // If the part after the pkg name isn't ", ", then it's a OS/ARCH-dependent line of the form:
+               //   pkg syscall (darwin-amd64), const ImplementsGetwd = false
+               // We skip those for now.
+               return
+       }
+       rest = rest[len(", "):]
+
+       switch {
+       case strings.HasPrefix(rest, "type "):
+               rest = rest[len("type "):]
+               sp := strings.IndexByte(rest, ' ')
+               if sp == -1 {
+                       return
+               }
+               vr.name, rest = rest[:sp], rest[sp+1:]
+               if !strings.HasPrefix(rest, "struct, ") {
+                       vr.kind = "type"
+                       return vr, true
+               }
+               rest = rest[len("struct, "):]
+               if i := strings.IndexByte(rest, ' '); i != -1 {
+                       vr.kind = "field"
+                       vr.structName = vr.name
+                       vr.name = rest[:i]
+                       return vr, true
+               }
+       case strings.HasPrefix(rest, "func "):
+               vr.kind = "func"
+               rest = rest[len("func "):]
+               if i := strings.IndexByte(rest, '('); i != -1 {
+                       vr.name = rest[:i]
+                       return vr, true
+               }
+       case strings.HasPrefix(rest, "method "): // "method (*File) SetModTime(time.Time)"
+               vr.kind = "method"
+               rest = rest[len("method "):] // "(*File) SetModTime(time.Time)"
+               sp := strings.IndexByte(rest, ' ')
+               if sp == -1 {
+                       return
+               }
+               vr.recv = strings.Trim(rest[:sp], "()") // "*File"
+               rest = rest[sp+1:]                      // SetMode(os.FileMode)
+               paren := strings.IndexByte(rest, '(')
+               if paren == -1 {
+                       return
+               }
+               vr.name = rest[:paren]
+               return vr, true
+       }
+       return // TODO: handle more cases
+}
+
+// InitVersionInfo parses the $GOROOT/api/go*.txt API definition files to discover
+// which API features were added in which Go releases.
+func (c *Corpus) InitVersionInfo() {
+       var err error
+       c.pkgAPIInfo, err = parsePackageAPIInfo()
+       if err != nil {
+               // TODO: consider making this fatal, after the Go 1.11 cycle.
+               log.Printf("godoc: error parsing API version files: %v", err)
+       }
+}
+
+func parsePackageAPIInfo() (apiVersions, error) {
+       var apiGlob string
+       if os.Getenv("GOROOT") == "" {
+               apiGlob = filepath.Join(build.Default.GOROOT, "api", "go*.txt")
+       } else {
+               apiGlob = filepath.Join(os.Getenv("GOROOT"), "api", "go*.txt")
+       }
+
+       files, err := filepath.Glob(apiGlob)
+       if err != nil {
+               return nil, err
+       }
+
+       vp := new(versionParser)
+       for _, f := range files {
+               if err := vp.parseFile(f); err != nil {
+                       return nil, err
+               }
+       }
+       return vp.res, nil
+}