blob: b220003e932ae667eed165e1ad51ffd400f05a14 [file] [log] [blame]
//===- ShowEnabledWarnings - diagtool tool for printing enabled flags -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
#include "DiagnosticNames.h"
#include "clang/Basic/LLVM.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "llvm/Support/TargetSelect.h"
DEF_DIAGTOOL("show-enabled",
"Show which warnings are enabled for a given command line",
ShowEnabledWarnings)
using namespace clang;
namespace {
struct PrettyDiag {
StringRef Name;
StringRef Flag;
DiagnosticsEngine::Level Level;
PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level)
: Name(name), Flag(flag), Level(level) {}
bool operator<(const PrettyDiag &x) const { return Name < x.Name; }
};
}
static char getFlagForLevel(DiagnosticsEngine::Level Level) {
switch (Level) {
case DiagnosticsEngine::Ignored: return ' ';
case DiagnosticsEngine::Note: return '-';
case DiagnosticsEngine::Warning: return 'W';
case DiagnosticsEngine::Error: return 'E';
case DiagnosticsEngine::Fatal: return 'F';
}
}
static CompilerInstance *createCompiler(unsigned int argc, char **argv) {
// First, build a compiler instance!
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
// Initialize targets first. This may be necessary if any warnings are
// selectively enabled.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagIDs, DiagsBuffer);
bool Success;
Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
argv, argv+argc, Diags);
// We are skipping cc1's usual search for a resource directory.
// This is not likely to affect warning output.
// Create the actual diagnostics engine.
Clang->createDiagnostics(argc, argv);
if (!Clang->hasDiagnostics())
return NULL;
// Flush any errors created when initializing everything. This could happen
// for invalid command lines, which will probably give non-sensical results.
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
if (!Success)
return NULL;
return Clang.take();
}
int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
// First check our one flag (--flags).
bool ShouldShowFlags = true;
if (argc > 0) {
StringRef FirstArg(*argv);
if (FirstArg.equals("--no-flags")) {
ShouldShowFlags = false;
--argc;
++argv;
} else if (FirstArg.equals("--flags")) {
ShouldShowFlags = true;
--argc;
++argv;
}
}
// Create the compiler instance.
OwningPtr<CompilerInstance> Clang(createCompiler(argc, argv));
if (!Clang)
return EXIT_FAILURE;
DiagnosticsEngine &Diags = Clang->getDiagnostics();
// Now we have our diagnostics. Iterate through EVERY diagnostic and see
// which ones are turned on.
// FIXME: It would be very nice to print which flags are turning on which
// diagnostics, but this can be done with a diff.
std::vector<PrettyDiag> Active;
for (const diagtool::DiagnosticRecord *I = diagtool::BuiltinDiagnostics,
*E = I + diagtool::BuiltinDiagnosticsCount; I != E; ++I) {
unsigned DiagID = I->DiagID;
if (DiagnosticIDs::isBuiltinNote(DiagID))
continue;
if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
continue;
DiagnosticsEngine::Level DiagLevel =
Diags.getDiagnosticLevel(DiagID, SourceLocation());
if (DiagLevel == DiagnosticsEngine::Ignored)
continue;
StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
}
std::sort(Active.begin(), Active.end());
// Print them all out.
for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
E = Active.end(); I != E; ++I) {
if (ShouldShowFlags)
Out << getFlagForLevel(I->Level) << " ";
Out << I->Name;
if (!I->Flag.empty())
Out << " [-W" << I->Flag << "]";
Out << '\n';
}
return EXIT_SUCCESS;
}