1 | // Copyright 2018 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 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 suspicious constructs, |
21 | such as Printf calls whose arguments do not align with the format |
22 | string. It uses heuristics that do not guarantee all reports are |
23 | genuine problems, but it can find errors not caught by the compilers. |
24 | ` |
25 | |
26 | // Help implements the help subcommand for a multichecker or unitchecker |
27 | // style command. The optional args specify the analyzers to describe. |
28 | // Help calls log.Fatal if no such analyzer exists. |
29 | func Help(progname string, analyzers []*analysis.Analyzer, args []string) { |
30 | // No args: show summary of all analyzers. |
31 | if len(args) == 0 { |
32 | fmt.Println(strings.Replace(help, "PROGNAME", progname, -1)) |
33 | fmt.Println("Registered analyzers:") |
34 | fmt.Println() |
35 | sort.Slice(analyzers, func(i, j int) bool { |
36 | return analyzers[i].Name < analyzers[j].Name |
37 | }) |
38 | for _, a := range analyzers { |
39 | title := strings.Split(a.Doc, "\n\n")[0] |
40 | fmt.Printf(" %-12s %s\n", a.Name, title) |
41 | } |
42 | fmt.Println("\nBy default all analyzers are run.") |
43 | fmt.Println("To select specific analyzers, use the -NAME flag for each one,") |
44 | fmt.Println(" or -NAME=false to run all analyzers not explicitly disabled.") |
45 | |
46 | // Show only the core command-line flags. |
47 | fmt.Println("\nCore flags:") |
48 | fmt.Println() |
49 | fs := flag.NewFlagSet("", flag.ExitOnError) |
50 | flag.VisitAll(func(f *flag.Flag) { |
51 | if !strings.Contains(f.Name, ".") { |
52 | fs.Var(f.Value, f.Name, f.Usage) |
53 | } |
54 | }) |
55 | fs.SetOutput(os.Stdout) |
56 | fs.PrintDefaults() |
57 | |
58 | fmt.Printf("\nTo see details and flags of a specific analyzer, run '%s help name'.\n", progname) |
59 | |
60 | return |
61 | } |
62 | |
63 | // Show help on specific analyzer(s). |
64 | outer: |
65 | for _, arg := range args { |
66 | for _, a := range analyzers { |
67 | if a.Name == arg { |
68 | paras := strings.Split(a.Doc, "\n\n") |
69 | title := paras[0] |
70 | fmt.Printf("%s: %s\n", a.Name, title) |
71 | |
72 | // Show only the flags relating to this analysis, |
73 | // properly prefixed. |
74 | first := true |
75 | fs := flag.NewFlagSet(a.Name, flag.ExitOnError) |
76 | a.Flags.VisitAll(func(f *flag.Flag) { |
77 | if first { |
78 | first = false |
79 | fmt.Println("\nAnalyzer flags:") |
80 | fmt.Println() |
81 | } |
82 | fs.Var(f.Value, a.Name+"."+f.Name, f.Usage) |
83 | }) |
84 | fs.SetOutput(os.Stdout) |
85 | fs.PrintDefaults() |
86 | |
87 | if len(paras) > 1 { |
88 | fmt.Printf("\n%s\n", strings.Join(paras[1:], "\n\n")) |
89 | } |
90 | |
91 | continue outer |
92 | } |
93 | } |
94 | log.Fatalf("Analyzer %q not registered", arg) |
95 | } |
96 | } |
97 |
Members