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