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 / go / analysis / internal / analysisflags / flags.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/go/analysis/internal/analysisflags/flags.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/go/analysis/internal/analysisflags/flags.go
new file mode 100644 (file)
index 0000000..4b7be2d
--- /dev/null
@@ -0,0 +1,388 @@
+// 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 analysisflags defines helpers for processing flags of
+// analysis driver tools.
+package analysisflags
+
+import (
+       "crypto/sha256"
+       "encoding/gob"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "go/token"
+       "io"
+       "io/ioutil"
+       "log"
+       "os"
+       "strconv"
+       "strings"
+
+       "golang.org/x/tools/go/analysis"
+)
+
+// flags common to all {single,multi,unit}checkers.
+var (
+       JSON    = false // -json
+       Context = -1    // -c=N: if N>0, display offending line plus N lines of context
+)
+
+// Parse creates a flag for each of the analyzer's flags,
+// including (in multi mode) a flag named after the analyzer,
+// parses the flags, then filters and returns the list of
+// analyzers enabled by flags.
+//
+// The result is intended to be passed to unitchecker.Run or checker.Run.
+// Use in unitchecker.Run will gob.Register all fact types for the returned
+// graph of analyzers but of course not the ones only reachable from
+// dropped analyzers. To avoid inconsistency about which gob types are
+// registered from run to run, Parse itself gob.Registers all the facts
+// only reachable from dropped analyzers.
+// This is not a particularly elegant API, but this is an internal package.
+func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
+       // Connect each analysis flag to the command line as -analysis.flag.
+       enabled := make(map[*analysis.Analyzer]*triState)
+       for _, a := range analyzers {
+               var prefix string
+
+               // Add -NAME flag to enable it.
+               if multi {
+                       prefix = a.Name + "."
+
+                       enable := new(triState)
+                       enableUsage := "enable " + a.Name + " analysis"
+                       flag.Var(enable, a.Name, enableUsage)
+                       enabled[a] = enable
+               }
+
+               a.Flags.VisitAll(func(f *flag.Flag) {
+                       if !multi && flag.Lookup(f.Name) != nil {
+                               log.Printf("%s flag -%s would conflict with driver; skipping", a.Name, f.Name)
+                               return
+                       }
+
+                       name := prefix + f.Name
+                       flag.Var(f.Value, name, f.Usage)
+               })
+       }
+
+       // standard flags: -flags, -V.
+       printflags := flag.Bool("flags", false, "print analyzer flags in JSON")
+       addVersionFlag()
+
+       // flags common to all checkers
+       flag.BoolVar(&JSON, "json", JSON, "emit JSON output")
+       flag.IntVar(&Context, "c", Context, `display offending line with this many lines of context`)
+
+       // Add shims for legacy vet flags to enable existing
+       // scripts that run vet to continue to work.
+       _ = flag.Bool("source", false, "no effect (deprecated)")
+       _ = flag.Bool("v", false, "no effect (deprecated)")
+       _ = flag.Bool("all", false, "no effect (deprecated)")
+       _ = flag.String("tags", "", "no effect (deprecated)")
+       for old, new := range vetLegacyFlags {
+               newFlag := flag.Lookup(new)
+               if newFlag != nil && flag.Lookup(old) == nil {
+                       flag.Var(newFlag.Value, old, "deprecated alias for -"+new)
+               }
+       }
+
+       flag.Parse() // (ExitOnError)
+
+       // -flags: print flags so that go vet knows which ones are legitimate.
+       if *printflags {
+               printFlags()
+               os.Exit(0)
+       }
+
+       everything := expand(analyzers)
+
+       // If any -NAME flag is true,  run only those analyzers. Otherwise,
+       // if any -NAME flag is false, run all but those analyzers.
+       if multi {
+               var hasTrue, hasFalse bool
+               for _, ts := range enabled {
+                       switch *ts {
+                       case setTrue:
+                               hasTrue = true
+                       case setFalse:
+                               hasFalse = true
+                       }
+               }
+
+               var keep []*analysis.Analyzer
+               if hasTrue {
+                       for _, a := range analyzers {
+                               if *enabled[a] == setTrue {
+                                       keep = append(keep, a)
+                               }
+                       }
+                       analyzers = keep
+               } else if hasFalse {
+                       for _, a := range analyzers {
+                               if *enabled[a] != setFalse {
+                                       keep = append(keep, a)
+                               }
+                       }
+                       analyzers = keep
+               }
+       }
+
+       // Register fact types of skipped analyzers
+       // in case we encounter them in imported files.
+       kept := expand(analyzers)
+       for a := range everything {
+               if !kept[a] {
+                       for _, f := range a.FactTypes {
+                               gob.Register(f)
+                       }
+               }
+       }
+
+       return analyzers
+}
+
+func expand(analyzers []*analysis.Analyzer) map[*analysis.Analyzer]bool {
+       seen := make(map[*analysis.Analyzer]bool)
+       var visitAll func([]*analysis.Analyzer)
+       visitAll = func(analyzers []*analysis.Analyzer) {
+               for _, a := range analyzers {
+                       if !seen[a] {
+                               seen[a] = true
+                               visitAll(a.Requires)
+                       }
+               }
+       }
+       visitAll(analyzers)
+       return seen
+}
+
+func printFlags() {
+       type jsonFlag struct {
+               Name  string
+               Bool  bool
+               Usage string
+       }
+       var flags []jsonFlag = nil
+       flag.VisitAll(func(f *flag.Flag) {
+               // Don't report {single,multi}checker debugging
+               // flags or fix as these have no effect on unitchecker
+               // (as invoked by 'go vet').
+               switch f.Name {
+               case "debug", "cpuprofile", "memprofile", "trace", "fix":
+                       return
+               }
+
+               b, ok := f.Value.(interface{ IsBoolFlag() bool })
+               isBool := ok && b.IsBoolFlag()
+               flags = append(flags, jsonFlag{f.Name, isBool, f.Usage})
+       })
+       data, err := json.MarshalIndent(flags, "", "\t")
+       if err != nil {
+               log.Fatal(err)
+       }
+       os.Stdout.Write(data)
+}
+
+// addVersionFlag registers a -V flag that, if set,
+// prints the executable version and exits 0.
+//
+// If the -V flag already exists — for example, because it was already
+// registered by a call to cmd/internal/objabi.AddVersionFlag — then
+// addVersionFlag does nothing.
+func addVersionFlag() {
+       if flag.Lookup("V") == nil {
+               flag.Var(versionFlag{}, "V", "print version and exit")
+       }
+}
+
+// versionFlag minimally complies with the -V protocol required by "go vet".
+type versionFlag struct{}
+
+func (versionFlag) IsBoolFlag() bool { return true }
+func (versionFlag) Get() interface{} { return nil }
+func (versionFlag) String() string   { return "" }
+func (versionFlag) Set(s string) error {
+       if s != "full" {
+               log.Fatalf("unsupported flag value: -V=%s", s)
+       }
+
+       // This replicates the minimal subset of
+       // cmd/internal/objabi.AddVersionFlag, which is private to the
+       // go tool yet forms part of our command-line interface.
+       // TODO(adonovan): clarify the contract.
+
+       // Print the tool version so the build system can track changes.
+       // Formats:
+       //   $progname version devel ... buildID=...
+       //   $progname version go1.9.1
+       progname := os.Args[0]
+       f, err := os.Open(progname)
+       if err != nil {
+               log.Fatal(err)
+       }
+       h := sha256.New()
+       if _, err := io.Copy(h, f); err != nil {
+               log.Fatal(err)
+       }
+       f.Close()
+       fmt.Printf("%s version devel comments-go-here buildID=%02x\n",
+               progname, string(h.Sum(nil)))
+       os.Exit(0)
+       return nil
+}
+
+// A triState is a boolean that knows whether
+// it has been set to either true or false.
+// It is used to identify whether a flag appears;
+// the standard boolean flag cannot
+// distinguish missing from unset.
+// It also satisfies flag.Value.
+type triState int
+
+const (
+       unset triState = iota
+       setTrue
+       setFalse
+)
+
+func triStateFlag(name string, value triState, usage string) *triState {
+       flag.Var(&value, name, usage)
+       return &value
+}
+
+// triState implements flag.Value, flag.Getter, and flag.boolFlag.
+// They work like boolean flags: we can say vet -printf as well as vet -printf=true
+func (ts *triState) Get() interface{} {
+       return *ts == setTrue
+}
+
+func (ts triState) isTrue() bool {
+       return ts == setTrue
+}
+
+func (ts *triState) Set(value string) error {
+       b, err := strconv.ParseBool(value)
+       if err != nil {
+               // This error message looks poor but package "flag" adds
+               // "invalid boolean value %q for -NAME: %s"
+               return fmt.Errorf("want true or false")
+       }
+       if b {
+               *ts = setTrue
+       } else {
+               *ts = setFalse
+       }
+       return nil
+}
+
+func (ts *triState) String() string {
+       switch *ts {
+       case unset:
+               return "true"
+       case setTrue:
+               return "true"
+       case setFalse:
+               return "false"
+       }
+       panic("not reached")
+}
+
+func (ts triState) IsBoolFlag() bool {
+       return true
+}
+
+// Legacy flag support
+
+// vetLegacyFlags maps flags used by legacy vet to their corresponding
+// new names. The old names will continue to work.
+var vetLegacyFlags = map[string]string{
+       // Analyzer name changes
+       "bool":       "bools",
+       "buildtags":  "buildtag",
+       "methods":    "stdmethods",
+       "rangeloops": "loopclosure",
+
+       // Analyzer flags
+       "compositewhitelist":  "composites.whitelist",
+       "printfuncs":          "printf.funcs",
+       "shadowstrict":        "shadow.strict",
+       "unusedfuncs":         "unusedresult.funcs",
+       "unusedstringmethods": "unusedresult.stringmethods",
+}
+
+// ---- output helpers common to all drivers ----
+
+// PrintPlain prints a diagnostic in plain text form,
+// with context specified by the -c flag.
+func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) {
+       posn := fset.Position(diag.Pos)
+       fmt.Fprintf(os.Stderr, "%s: %s\n", posn, diag.Message)
+
+       // -c=N: show offending line plus N lines of context.
+       if Context >= 0 {
+               posn := fset.Position(diag.Pos)
+               end := fset.Position(diag.End)
+               if !end.IsValid() {
+                       end = posn
+               }
+               data, _ := ioutil.ReadFile(posn.Filename)
+               lines := strings.Split(string(data), "\n")
+               for i := posn.Line - Context; i <= end.Line+Context; i++ {
+                       if 1 <= i && i <= len(lines) {
+                               fmt.Fprintf(os.Stderr, "%d\t%s\n", i, lines[i-1])
+                       }
+               }
+       }
+}
+
+// A JSONTree is a mapping from package ID to analysis name to result.
+// Each result is either a jsonError or a list of jsonDiagnostic.
+type JSONTree map[string]map[string]interface{}
+
+// Add adds the result of analysis 'name' on package 'id'.
+// The result is either a list of diagnostics or an error.
+func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
+       var v interface{}
+       if err != nil {
+               type jsonError struct {
+                       Err string `json:"error"`
+               }
+               v = jsonError{err.Error()}
+       } else if len(diags) > 0 {
+               type jsonDiagnostic struct {
+                       Category string `json:"category,omitempty"`
+                       Posn     string `json:"posn"`
+                       Message  string `json:"message"`
+               }
+               var diagnostics []jsonDiagnostic
+               // TODO(matloob): Should the JSON diagnostics contain ranges?
+               // If so, how should they be formatted?
+               for _, f := range diags {
+                       diagnostics = append(diagnostics, jsonDiagnostic{
+                               Category: f.Category,
+                               Posn:     fset.Position(f.Pos).String(),
+                               Message:  f.Message,
+                       })
+               }
+               v = diagnostics
+       }
+       if v != nil {
+               m, ok := tree[id]
+               if !ok {
+                       m = make(map[string]interface{})
+                       tree[id] = m
+               }
+               m[name] = v
+       }
+}
+
+func (tree JSONTree) Print() {
+       data, err := json.MarshalIndent(tree, "", "\t")
+       if err != nil {
+               log.Panicf("internal error: JSON marshaling failed: %v", err)
+       }
+       fmt.Printf("%s\n", data)
+}