blob: abbd3afbd58c6efb864970f60b7667f4171a5534 [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;
Jordan Rosee7427632012-06-24 00:07:45 +000024using namespace diagtool;
Jordan Rose0832f822012-06-04 16:57:50 +000025
26namespace {
27 struct PrettyDiag {
28 StringRef Name;
29 StringRef Flag;
30 DiagnosticsEngine::Level Level;
31
32 PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level)
33 : Name(name), Flag(flag), Level(level) {}
34
35 bool operator<(const PrettyDiag &x) const { return Name < x.Name; }
36 };
37}
38
39static void printUsage() {
40 llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n";
41}
42
43static char getCharForLevel(DiagnosticsEngine::Level Level) {
44 switch (Level) {
45 case DiagnosticsEngine::Ignored: return ' ';
46 case DiagnosticsEngine::Note: return '-';
Stephen Hines651f13c2014-04-23 16:59:28 -070047 case DiagnosticsEngine::Remark: return 'R';
Jordan Rose0832f822012-06-04 16:57:50 +000048 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
56static IntrusiveRefCntPtr<DiagnosticsEngine>
57createDiagnostics(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(
Douglas Gregor02c23eb2012-10-23 22:26:28 +000064 new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
Jordan Rose0832f822012-06-04 16:57:50 +000065
66 // Try to build a CompilerInvocation.
Pirama Arumuga Nainar87d948e2016-03-03 15:49:35 -080067 SmallVector<const char *, 4> Args;
68 Args.push_back("diagtool");
69 Args.append(argv, argv + argc);
Stephen Hines651f13c2014-04-23 16:59:28 -070070 std::unique_ptr<CompilerInvocation> Invocation(
Pirama Arumuga Nainar87d948e2016-03-03 15:49:35 -080071 createInvocationFromCommandLine(Args, InterimDiags));
Jordan Rose0832f822012-06-04 16:57:50 +000072 if (!Invocation)
Stephen Hinesc568f1e2014-07-21 00:47:37 -070073 return nullptr;
Jordan Rose0832f822012-06-04 16:57:50 +000074
75 // Build the diagnostics parser
76 IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
Sean Silvad47afb92013-01-20 01:58:28 +000077 CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts());
Jordan Rose0832f822012-06-04 16:57:50 +000078 if (!FinalDiags)
Stephen Hinesc568f1e2014-07-21 00:47:37 -070079 return nullptr;
80
Jordan Rose0832f822012-06-04 16:57:50 +000081 // Flush any errors created when initializing everything. This could happen
82 // for invalid command lines, which will probably give non-sensical results.
83 DiagsBuffer->FlushDiagnostics(*FinalDiags);
84
85 return FinalDiags;
86}
87
88int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
89 // First check our one flag (--levels).
90 bool ShouldShowLevels = true;
91 if (argc > 0) {
92 StringRef FirstArg(*argv);
93 if (FirstArg.equals("--no-levels")) {
94 ShouldShowLevels = false;
95 --argc;
96 ++argv;
97 } else if (FirstArg.equals("--levels")) {
98 ShouldShowLevels = true;
99 --argc;
100 ++argv;
101 }
102 }
103
104 // Create the diagnostic engine.
105 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
106 if (!Diags) {
107 printUsage();
108 return EXIT_FAILURE;
109 }
110
111 // Now we have our diagnostics. Iterate through EVERY diagnostic and see
112 // which ones are turned on.
113 // FIXME: It would be very nice to print which flags are turning on which
114 // diagnostics, but this can be done with a diff.
Jordan Rosee7427632012-06-24 00:07:45 +0000115 ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
Jordan Rose0832f822012-06-04 16:57:50 +0000116 std::vector<PrettyDiag> Active;
117
Jordan Rosee7427632012-06-24 00:07:45 +0000118 for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(),
119 E = AllDiagnostics.end();
120 I != E; ++I) {
Jordan Rose0832f822012-06-04 16:57:50 +0000121 unsigned DiagID = I->DiagID;
122
123 if (DiagnosticIDs::isBuiltinNote(DiagID))
124 continue;
125
126 if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
127 continue;
128
129 DiagnosticsEngine::Level DiagLevel =
130 Diags->getDiagnosticLevel(DiagID, SourceLocation());
131 if (DiagLevel == DiagnosticsEngine::Ignored)
132 continue;
133
134 StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
135 Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
136 }
137
Jordan Rose0832f822012-06-04 16:57:50 +0000138 // Print them all out.
139 for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
140 E = Active.end(); I != E; ++I) {
141 if (ShouldShowLevels)
142 Out << getCharForLevel(I->Level) << " ";
143 Out << I->Name;
144 if (!I->Flag.empty())
145 Out << " [-W" << I->Flag << "]";
146 Out << '\n';
147 }
148
149 return EXIT_SUCCESS;
150}