1 //===- ShowEnabledWarnings - diagtool tool for printing enabled flags -----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "DiagnosticNames.h"
11 #include "clang/Basic/LLVM.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Frontend/TextDiagnosticBuffer.h"
14 #include "clang/Frontend/TextDiagnosticPrinter.h"
15 #include "clang/Frontend/Utils.h"
16 #include "llvm/Support/TargetSelect.h"
17 #include "llvm/Support/VirtualFileSystem.h"
19 DEF_DIAGTOOL("show-enabled",
20 "Show which warnings are enabled for a given command line",
23 using namespace clang
;
24 using namespace diagtool
;
30 DiagnosticsEngine::Level Level
;
32 PrettyDiag(StringRef name
, StringRef flag
, DiagnosticsEngine::Level level
)
33 : Name(name
), Flag(flag
), Level(level
) {}
35 bool operator<(const PrettyDiag
&x
) const { return Name
< x
.Name
; }
39 static void printUsage() {
40 llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n";
43 static char getCharForLevel(DiagnosticsEngine::Level 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';
53 llvm_unreachable("Unknown diagnostic level");
56 static IntrusiveRefCntPtr
<DiagnosticsEngine
>
57 createDiagnostics(unsigned int argc
, char **argv
) {
58 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagIDs(new DiagnosticIDs());
60 // Buffer diagnostics from argument parsing so that we can output them using a
61 // well formed diagnostic object.
62 TextDiagnosticBuffer
*DiagsBuffer
= new TextDiagnosticBuffer
;
64 // Try to build a CompilerInvocation.
65 SmallVector
<const char *, 4> Args
;
66 Args
.push_back("diagtool");
67 Args
.append(argv
, argv
+ argc
);
68 CreateInvocationOptions CIOpts
;
70 new DiagnosticsEngine(DiagIDs
, new DiagnosticOptions(), DiagsBuffer
);
71 std::unique_ptr
<CompilerInvocation
> Invocation
=
72 createInvocation(Args
, CIOpts
);
76 // Build the diagnostics parser
77 IntrusiveRefCntPtr
<DiagnosticsEngine
> FinalDiags
=
78 CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
79 &Invocation
->getDiagnosticOpts());
83 // Flush any errors created when initializing everything. This could happen
84 // for invalid command lines, which will probably give non-sensical results.
85 DiagsBuffer
->FlushDiagnostics(*FinalDiags
);
90 int ShowEnabledWarnings::run(unsigned int argc
, char **argv
, raw_ostream
&Out
) {
91 // First check our one flag (--levels).
92 bool ShouldShowLevels
= true;
94 StringRef
FirstArg(*argv
);
95 if (FirstArg
== "--no-levels") {
96 ShouldShowLevels
= false;
99 } else if (FirstArg
== "--levels") {
100 ShouldShowLevels
= true;
106 // Create the diagnostic engine.
107 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags
= createDiagnostics(argc
, argv
);
113 // Now we have our diagnostics. Iterate through EVERY diagnostic and see
114 // which ones are turned on.
115 // FIXME: It would be very nice to print which flags are turning on which
116 // diagnostics, but this can be done with a diff.
117 std::vector
<PrettyDiag
> Active
;
119 for (const DiagnosticRecord
&DR
: getBuiltinDiagnosticsByName()) {
120 unsigned DiagID
= DR
.DiagID
;
122 if (DiagnosticIDs::isBuiltinNote(DiagID
))
125 if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID
))
128 DiagnosticsEngine::Level DiagLevel
=
129 Diags
->getDiagnosticLevel(DiagID
, SourceLocation());
130 if (DiagLevel
== DiagnosticsEngine::Ignored
)
133 StringRef WarningOpt
= DiagnosticIDs::getWarningOptionForDiag(DiagID
);
134 Active
.push_back(PrettyDiag(DR
.getName(), WarningOpt
, DiagLevel
));
137 // Print them all out.
138 for (const PrettyDiag
&PD
: Active
) {
139 if (ShouldShowLevels
)
140 Out
<< getCharForLevel(PD
.Level
) << " ";
142 if (!PD
.Flag
.empty())
143 Out
<< " [-W" << PD
.Flag
<< "]";