1
2
3
4
5 package vet
6
7 import (
8 "bytes"
9 "encoding/json"
10 "errors"
11 "flag"
12 "fmt"
13 "log"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "strings"
18
19 "cmd/go/internal/base"
20 "cmd/go/internal/cmdflag"
21 "cmd/go/internal/work"
22 )
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 var vetTool string
39
40 func init() {
41 work.AddBuildFlags(CmdVet, work.DefaultBuildFlags)
42 CmdVet.Flag.StringVar(&vetTool, "vettool", "", "")
43 }
44
45 func parseVettoolFlag(args []string) {
46
47
48
49 for i, arg := range args {
50 if arg == "-vettool" || arg == "--vettool" {
51 if i+1 >= len(args) {
52 log.Fatalf("%s requires a filename", arg)
53 }
54 vetTool = args[i+1]
55 return
56 } else if strings.HasPrefix(arg, "-vettool=") ||
57 strings.HasPrefix(arg, "--vettool=") {
58 vetTool = arg[strings.IndexByte(arg, '=')+1:]
59 return
60 }
61 }
62 }
63
64
65
66 func vetFlags(args []string) (passToVet, packageNames []string) {
67 parseVettoolFlag(args)
68
69
70 var tool string
71 if vetTool == "" {
72 tool = base.Tool("vet")
73 } else {
74 var err error
75 tool, err = filepath.Abs(vetTool)
76 if err != nil {
77 log.Fatal(err)
78 }
79 }
80 out := new(bytes.Buffer)
81 vetcmd := exec.Command(tool, "-flags")
82 vetcmd.Stdout = out
83 if err := vetcmd.Run(); err != nil {
84 fmt.Fprintf(os.Stderr, "go: can't execute %s -flags: %v\n", tool, err)
85 base.SetExitStatus(2)
86 base.Exit()
87 }
88 var analysisFlags []struct {
89 Name string
90 Bool bool
91 Usage string
92 }
93 if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil {
94 fmt.Fprintf(os.Stderr, "go: can't unmarshal JSON from %s -flags: %v", tool, err)
95 base.SetExitStatus(2)
96 base.Exit()
97 }
98
99
100
101
102
103
104 isVetFlag := make(map[string]bool, len(analysisFlags))
105 cf := CmdVet.Flag
106 for _, f := range analysisFlags {
107 isVetFlag[f.Name] = true
108 if cf.Lookup(f.Name) == nil {
109 if f.Bool {
110 cf.Bool(f.Name, false, "")
111 } else {
112 cf.String(f.Name, "", "")
113 }
114 }
115 }
116
117
118
119 base.SetFromGOFLAGS(&CmdVet.Flag)
120 addFromGOFLAGS := map[string]bool{}
121 CmdVet.Flag.Visit(func(f *flag.Flag) {
122 if isVetFlag[f.Name] {
123 addFromGOFLAGS[f.Name] = true
124 }
125 })
126
127 explicitFlags := make([]string, 0, len(args))
128 for len(args) > 0 {
129 f, remainingArgs, err := cmdflag.ParseOne(&CmdVet.Flag, args)
130
131 if errors.Is(err, flag.ErrHelp) {
132 exitWithUsage()
133 }
134
135 if errors.Is(err, cmdflag.ErrFlagTerminator) {
136
137
138 packageNames = remainingArgs
139 break
140 }
141
142 if nf := (cmdflag.NonFlagError{}); errors.As(err, &nf) {
143
144
145 packageNames = args
146 break
147 }
148
149 if err != nil {
150 fmt.Fprintln(os.Stderr, err)
151 exitWithUsage()
152 }
153
154 if isVetFlag[f.Name] {
155
156
157 explicitFlags = append(explicitFlags, args[:len(args)-len(remainingArgs)]...)
158
159
160
161 delete(addFromGOFLAGS, f.Name)
162 }
163
164 args = remainingArgs
165 }
166
167
168 CmdVet.Flag.Visit(func(f *flag.Flag) {
169 if addFromGOFLAGS[f.Name] {
170 passToVet = append(passToVet, fmt.Sprintf("-%s=%s", f.Name, f.Value))
171 }
172 })
173 passToVet = append(passToVet, explicitFlags...)
174 return passToVet, packageNames
175 }
176
177 func exitWithUsage() {
178 fmt.Fprintf(os.Stderr, "usage: %s\n", CmdVet.UsageLine)
179 fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", CmdVet.LongName())
180
181
182 cmd := "go tool vet"
183 if vetTool != "" {
184 cmd = vetTool
185 }
186 fmt.Fprintf(os.Stderr, "Run '%s help' for a full list of flags and analyzers.\n", cmd)
187 fmt.Fprintf(os.Stderr, "Run '%s -help' for an overview.\n", cmd)
188
189 base.SetExitStatus(2)
190 base.Exit()
191 }
192
View as plain text