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