/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/diagtool/ShowEnabledWarnings.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- ShowEnabledWarnings - diagtool tool for printing enabled flags -----===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "DiagTool.h" |
10 | | #include "DiagnosticNames.h" |
11 | | #include "clang/Basic/LLVM.h" |
12 | | #include "clang/Frontend/CompilerInstance.h" |
13 | | #include "clang/Frontend/TextDiagnosticBuffer.h" |
14 | | #include "clang/Frontend/TextDiagnosticPrinter.h" |
15 | | #include "clang/Frontend/Utils.h" |
16 | | #include "llvm/Support/TargetSelect.h" |
17 | | |
18 | | DEF_DIAGTOOL("show-enabled", |
19 | | "Show which warnings are enabled for a given command line", |
20 | | ShowEnabledWarnings) |
21 | | |
22 | | using namespace clang; |
23 | | using namespace diagtool; |
24 | | |
25 | | namespace { |
26 | | struct PrettyDiag { |
27 | | StringRef Name; |
28 | | StringRef Flag; |
29 | | DiagnosticsEngine::Level Level; |
30 | | |
31 | | PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level) |
32 | 8.25k | : Name(name), Flag(flag), Level(level) {} |
33 | | |
34 | 0 | bool operator<(const PrettyDiag &x) const { return Name < x.Name; } |
35 | | }; |
36 | | } |
37 | | |
38 | 0 | static void printUsage() { |
39 | 0 | llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n"; |
40 | 0 | } |
41 | | |
42 | 1.18k | static char getCharForLevel(DiagnosticsEngine::Level Level) { |
43 | 1.18k | switch (Level) { |
44 | 0 | case DiagnosticsEngine::Ignored: return ' '; |
45 | 0 | case DiagnosticsEngine::Note: return '-'; |
46 | 0 | case DiagnosticsEngine::Remark: return 'R'; |
47 | 1.14k | case DiagnosticsEngine::Warning: return 'W'; |
48 | 48 | case DiagnosticsEngine::Error: return 'E'; |
49 | 1 | case DiagnosticsEngine::Fatal: return 'F'; |
50 | 1.18k | } |
51 | | |
52 | 0 | llvm_unreachable("Unknown diagnostic level"); |
53 | 0 | } |
54 | | |
55 | | static IntrusiveRefCntPtr<DiagnosticsEngine> |
56 | 12 | createDiagnostics(unsigned int argc, char **argv) { |
57 | 12 | IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs()); |
58 | | |
59 | | // Buffer diagnostics from argument parsing so that we can output them using a |
60 | | // well formed diagnostic object. |
61 | 12 | TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; |
62 | | |
63 | | // Try to build a CompilerInvocation. |
64 | 12 | SmallVector<const char *, 4> Args; |
65 | 12 | Args.push_back("diagtool"); |
66 | 12 | Args.append(argv, argv + argc); |
67 | 12 | CreateInvocationOptions CIOpts; |
68 | 12 | CIOpts.Diags = |
69 | 12 | new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer); |
70 | 12 | std::unique_ptr<CompilerInvocation> Invocation = |
71 | 12 | createInvocation(Args, CIOpts); |
72 | 12 | if (!Invocation) |
73 | 0 | return nullptr; |
74 | | |
75 | | // Build the diagnostics parser |
76 | 12 | IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags = |
77 | 12 | CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts()); |
78 | 12 | if (!FinalDiags) |
79 | 0 | return nullptr; |
80 | | |
81 | | // Flush any errors created when initializing everything. This could happen |
82 | | // for invalid command lines, which will probably give non-sensical results. |
83 | 12 | DiagsBuffer->FlushDiagnostics(*FinalDiags); |
84 | | |
85 | 12 | return FinalDiags; |
86 | 12 | } |
87 | | |
88 | 12 | int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) { |
89 | | // First check our one flag (--levels). |
90 | 12 | bool ShouldShowLevels = true; |
91 | 12 | if (argc > 0) { |
92 | 12 | StringRef FirstArg(*argv); |
93 | 12 | if (FirstArg.equals("--no-levels")) { |
94 | 7 | ShouldShowLevels = false; |
95 | 7 | --argc; |
96 | 7 | ++argv; |
97 | 7 | } else if (5 FirstArg.equals("--levels")5 ) { |
98 | 0 | ShouldShowLevels = true; |
99 | 0 | --argc; |
100 | 0 | ++argv; |
101 | 0 | } |
102 | 12 | } |
103 | | |
104 | | // Create the diagnostic engine. |
105 | 12 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv); |
106 | 12 | if (!Diags) { |
107 | 0 | printUsage(); |
108 | 0 | return EXIT_FAILURE; |
109 | 0 | } |
110 | | |
111 | | // Now we have our diagnostics. Iterate through EVERY diagnostic and see |
112 | | // which ones are turned on. |
113 | | // FIXME: It would be very nice to print which flags are turning on which |
114 | | // diagnostics, but this can be done with a diff. |
115 | 12 | std::vector<PrettyDiag> Active; |
116 | | |
117 | 71.4k | for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) { |
118 | 71.4k | unsigned DiagID = DR.DiagID; |
119 | | |
120 | 71.4k | if (DiagnosticIDs::isBuiltinNote(DiagID)) |
121 | 11.1k | continue; |
122 | | |
123 | 60.3k | if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID)) |
124 | 38.5k | continue; |
125 | | |
126 | 21.8k | DiagnosticsEngine::Level DiagLevel = |
127 | 21.8k | Diags->getDiagnosticLevel(DiagID, SourceLocation()); |
128 | 21.8k | if (DiagLevel == DiagnosticsEngine::Ignored) |
129 | 13.5k | continue; |
130 | | |
131 | 8.25k | StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID); |
132 | 8.25k | Active.push_back(PrettyDiag(DR.getName(), WarningOpt, DiagLevel)); |
133 | 8.25k | } |
134 | | |
135 | | // Print them all out. |
136 | 8.25k | for (const PrettyDiag &PD : Active) { |
137 | 8.25k | if (ShouldShowLevels) |
138 | 1.18k | Out << getCharForLevel(PD.Level) << " "; |
139 | 8.25k | Out << PD.Name; |
140 | 8.25k | if (!PD.Flag.empty()) |
141 | 7.79k | Out << " [-W" << PD.Flag << "]"; |
142 | 8.25k | Out << '\n'; |
143 | 8.25k | } |
144 | | |
145 | 12 | return EXIT_SUCCESS; |
146 | 12 | } |