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