1
2
3
4
5 package analysisflags
6
7 import (
8 "flag"
9 "fmt"
10 "log"
11 "os"
12 "sort"
13 "strings"
14
15 "golang.org/x/tools/go/analysis"
16 )
17
18 const help = `PROGNAME is a tool for static analysis of Go programs.
19
20 PROGNAME examines Go source code and reports diagnostics for
21 suspicious constructs or opportunities for improvement.
22 Diagnostics may include suggested fixes.
23
24 An example of a suspicious construct is a Printf call whose arguments
25 do not align with the format string. Analyzers may use heuristics that
26 do not guarantee all reports are genuine problems, but can find
27 mistakes not caught by the compiler.
28
29 An example of an opportunity for improvement is a loop over
30 strings.Split(doc, "\n"), which may be replaced by a loop over the
31 strings.SplitSeq iterator, avoiding an array allocation.
32 Diagnostics in such cases may report non-problems,
33 but should carry fixes that may be safely applied.
34
35 For analyzers of the first kind, use "go vet -vettool=PROGRAM"
36 to run the tool and report diagnostics.
37
38 For analyzers of the second kind, use "go fix -fixtool=PROGRAM"
39 to run the tool and apply the fixes it suggests.
40 `
41
42
43
44
45 func Help(progname string, analyzers []*analysis.Analyzer, args []string) {
46
47 if len(args) == 0 {
48 fmt.Println(strings.ReplaceAll(help, "PROGNAME", progname))
49 fmt.Println("Registered analyzers:")
50 fmt.Println()
51 sort.Slice(analyzers, func(i, j int) bool {
52 return analyzers[i].Name < analyzers[j].Name
53 })
54 for _, a := range analyzers {
55 title := strings.Split(a.Doc, "\n\n")[0]
56 fmt.Printf(" %-12s %s\n", a.Name, title)
57 }
58 fmt.Println("\nBy default all analyzers are run.")
59 fmt.Println("To select specific analyzers, use the -NAME flag for each one,")
60 fmt.Println(" or -NAME=false to run all analyzers not explicitly disabled.")
61
62
63 fmt.Println("\nCore flags:")
64 fmt.Println()
65 fs := flag.NewFlagSet("", flag.ExitOnError)
66 flag.VisitAll(func(f *flag.Flag) {
67 if !strings.Contains(f.Name, ".") {
68 fs.Var(f.Value, f.Name, f.Usage)
69 }
70 })
71 fs.SetOutput(os.Stdout)
72 fs.PrintDefaults()
73
74 fmt.Printf("\nTo see details and flags of a specific analyzer, run '%s help name'.\n", progname)
75
76 return
77 }
78
79
80 outer:
81 for _, arg := range args {
82 for _, a := range analyzers {
83 if a.Name == arg {
84 paras := strings.Split(a.Doc, "\n\n")
85 title := paras[0]
86 fmt.Printf("%s: %s\n", a.Name, title)
87
88
89
90 first := true
91 fs := flag.NewFlagSet(a.Name, flag.ExitOnError)
92 a.Flags.VisitAll(func(f *flag.Flag) {
93 if first {
94 first = false
95 fmt.Println("\nAnalyzer flags:")
96 fmt.Println()
97 }
98 fs.Var(f.Value, a.Name+"."+f.Name, f.Usage)
99 })
100 fs.SetOutput(os.Stdout)
101 fs.PrintDefaults()
102
103 if len(paras) > 1 {
104 fmt.Printf("\n%s\n", strings.Join(paras[1:], "\n\n"))
105 }
106
107 continue outer
108 }
109 }
110 log.Fatalf("Analyzer %q not registered", arg)
111 }
112 }
113
View as plain text