github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/go/internal/vet/vetflag.go (about) 1 // Copyright 2017 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 vet 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "log" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "strings" 17 18 "cmd/go/internal/base" 19 "cmd/go/internal/cmdflag" 20 "cmd/go/internal/str" 21 "cmd/go/internal/work" 22 ) 23 24 // go vet flag processing 25 // 26 // We query the flags of the tool specified by GOVETTOOL (default: 27 // cmd/vet) and accept any of those flags plus any flag valid for 'go 28 // build'. The tool must support -flags, which prints a description of 29 // its flags in JSON to stdout. 30 31 // GOVETTOOL specifies the vet command to run. 32 // This must be an environment variable because 33 // we need it before flag processing, as we execute 34 // $GOVETTOOL to discover the set of flags it supports. 35 // 36 // Using an environment variable also makes it easy for users to opt in 37 // to (and later, opt out of) the new cmd/vet analysis driver during the 38 // transition. It is also used by tests. 39 var vetTool = os.Getenv("GOVETTOOL") 40 41 // vetFlags processes the command line, splitting it at the first non-flag 42 // into the list of flags and list of packages. 43 func vetFlags(args []string) (passToVet, packageNames []string) { 44 // Query the vet command for its flags. 45 tool := vetTool 46 if tool != "" { 47 var err error 48 tool, err = filepath.Abs(tool) 49 if err != nil { 50 log.Fatal(err) 51 } 52 } else { 53 tool = base.Tool("vet") 54 } 55 out := new(bytes.Buffer) 56 vetcmd := exec.Command(tool, "-flags") 57 vetcmd.Stdout = out 58 if err := vetcmd.Run(); err != nil { 59 fmt.Fprintf(os.Stderr, "go vet: can't execute %s -flags: %v\n", tool, err) 60 os.Exit(2) 61 } 62 var analysisFlags []struct { 63 Name string 64 Bool bool 65 Usage string 66 } 67 if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil { 68 fmt.Fprintf(os.Stderr, "go vet: can't unmarshal JSON from %s -flags: %v", tool, err) 69 os.Exit(2) 70 } 71 72 // Add vet's flags to vetflagDefn. 73 // 74 // Some flags, in particular -tags and -v, are known to vet but 75 // also defined as build flags. This works fine, so we don't 76 // define them here but use AddBuildFlags to init them. 77 // However some, like -x, are known to the build but not to vet. 78 var vetFlagDefn []*cmdflag.Defn 79 for _, f := range analysisFlags { 80 switch f.Name { 81 case "tags", "v": 82 continue 83 } 84 defn := &cmdflag.Defn{ 85 Name: f.Name, 86 PassToTest: true, 87 } 88 if f.Bool { 89 defn.BoolVar = new(bool) 90 } 91 vetFlagDefn = append(vetFlagDefn, defn) 92 } 93 94 // Add build flags to vetFlagDefn. 95 var cmd base.Command 96 work.AddBuildFlags(&cmd) 97 cmd.Flag.VisitAll(func(f *flag.Flag) { 98 vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{ 99 Name: f.Name, 100 Value: f.Value, 101 }) 102 }) 103 104 // Process args. 105 args = str.StringList(cmdflag.FindGOFLAGS(vetFlagDefn), args) 106 for i := 0; i < len(args); i++ { 107 if !strings.HasPrefix(args[i], "-") { 108 return args[:i], args[i:] 109 } 110 111 f, value, extraWord := cmdflag.Parse("vet", vetFlagDefn, args, i) 112 if f == nil { 113 fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i]) 114 fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n") 115 os.Exit(2) 116 } 117 if f.Value != nil { 118 if err := f.Value.Set(value); err != nil { 119 base.Fatalf("invalid flag argument for -%s: %v", f.Name, err) 120 } 121 keep := f.PassToTest 122 if !keep { 123 // A build flag, probably one we don't want to pass to vet. 124 // Can whitelist. 125 switch f.Name { 126 case "tags", "v": 127 keep = true 128 } 129 } 130 if !keep { 131 // Flags known to the build but not to vet, so must be dropped. 132 if extraWord { 133 args = append(args[:i], args[i+2:]...) 134 extraWord = false 135 } else { 136 args = append(args[:i], args[i+1:]...) 137 } 138 i-- 139 } 140 } 141 if extraWord { 142 i++ 143 } 144 } 145 return args, nil 146 }