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