xref: /openbsd-src/gnu/llvm/clang/tools/diagtool/ShowEnabledWarnings.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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