blob: 2bc5124e61859819320712fac1e95c1fc500910c [file] [log] [blame]
Jordan Rose0832f822012-06-04 16:57:50 +00001//===- 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
19DEF_DIAGTOOL("show-enabled",
20 "Show which warnings are enabled for a given command line",
21 ShowEnabledWarnings)
22
23using namespace clang;
24
25namespace {
26 struct PrettyDiag {
27 StringRef Name;
28 StringRef Flag;
29 DiagnosticsEngine::Level Level;
30
31 PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level)
32 : Name(name), Flag(flag), Level(level) {}
33
34 bool operator<(const PrettyDiag &x) const { return Name < x.Name; }
35 };
36}
37
38static void printUsage() {
39 llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n";
40}
41
42static char getCharForLevel(DiagnosticsEngine::Level Level) {
43 switch (Level) {
44 case DiagnosticsEngine::Ignored: return ' ';
45 case DiagnosticsEngine::Note: return '-';
46 case DiagnosticsEngine::Warning: return 'W';
47 case DiagnosticsEngine::Error: return 'E';
48 case DiagnosticsEngine::Fatal: return 'F';
49 }
50
51 llvm_unreachable("Unknown diagnostic level");
52}
53
54static IntrusiveRefCntPtr<DiagnosticsEngine>
55createDiagnostics(unsigned int argc, char **argv) {
56 IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
57
58 // Buffer diagnostics from argument parsing so that we can output them using a
59 // well formed diagnostic object.
60 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
61 IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
62 new DiagnosticsEngine(DiagIDs, DiagsBuffer));
63
64 // Try to build a CompilerInvocation.
65 OwningPtr<CompilerInvocation> Invocation(
66 createInvocationFromCommandLine(ArrayRef<const char *>(argv, argc),
67 InterimDiags));
68 if (!Invocation)
69 return NULL;
70
71 // Build the diagnostics parser
72 IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
73 CompilerInstance::createDiagnostics(Invocation->getDiagnosticOpts(),
74 argc, argv);
75 if (!FinalDiags)
76 return NULL;
77
78 // Flush any errors created when initializing everything. This could happen
79 // for invalid command lines, which will probably give non-sensical results.
80 DiagsBuffer->FlushDiagnostics(*FinalDiags);
81
82 return FinalDiags;
83}
84
85int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
86 // First check our one flag (--levels).
87 bool ShouldShowLevels = true;
88 if (argc > 0) {
89 StringRef FirstArg(*argv);
90 if (FirstArg.equals("--no-levels")) {
91 ShouldShowLevels = false;
92 --argc;
93 ++argv;
94 } else if (FirstArg.equals("--levels")) {
95 ShouldShowLevels = true;
96 --argc;
97 ++argv;
98 }
99 }
100
101 // Create the diagnostic engine.
102 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
103 if (!Diags) {
104 printUsage();
105 return EXIT_FAILURE;
106 }
107
108 // Now we have our diagnostics. Iterate through EVERY diagnostic and see
109 // which ones are turned on.
110 // FIXME: It would be very nice to print which flags are turning on which
111 // diagnostics, but this can be done with a diff.
112 std::vector<PrettyDiag> Active;
113
114 for (const diagtool::DiagnosticRecord *I = diagtool::BuiltinDiagnostics,
115 *E = I + diagtool::BuiltinDiagnosticsCount; I != E; ++I) {
116 unsigned DiagID = I->DiagID;
117
118 if (DiagnosticIDs::isBuiltinNote(DiagID))
119 continue;
120
121 if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
122 continue;
123
124 DiagnosticsEngine::Level DiagLevel =
125 Diags->getDiagnosticLevel(DiagID, SourceLocation());
126 if (DiagLevel == DiagnosticsEngine::Ignored)
127 continue;
128
129 StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
130 Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
131 }
132
133 std::sort(Active.begin(), Active.end());
134
135 // Print them all out.
136 for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
137 E = Active.end(); I != E; ++I) {
138 if (ShouldShowLevels)
139 Out << getCharForLevel(I->Level) << " ";
140 Out << I->Name;
141 if (!I->Flag.empty())
142 Out << " [-W" << I->Flag << "]";
143 Out << '\n';
144 }
145
146 return EXIT_SUCCESS;
147}