Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,25 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_executable(diagtool
diagtool_main.cpp
DiagTool.cpp
DiagnosticNames.cpp
FindDiagnosticID.cpp
ListWarnings.cpp
ShowEnabledWarnings.cpp
TreeView.cpp
)
target_link_libraries(diagtool
PRIVATE
clangBasic
clangFrontend
)
if(UNIX)
set(CLANGXX_LINK_OR_COPY create_symlink)
else()
set(CLANGXX_LINK_OR_COPY copy)
endif()

View File

@ -0,0 +1,67 @@
//===- DiagTool.cpp - Classes for defining diagtool tools -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the boilerplate for defining diagtool tools.
//
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
#include "llvm/ADT/StringMap.h"
#include <vector>
using namespace diagtool;
DiagTool::DiagTool(llvm::StringRef toolCmd,
llvm::StringRef toolDesc)
: cmd(toolCmd), description(toolDesc) {}
DiagTool::~DiagTool() {}
typedef llvm::StringMap<DiagTool *> ToolMap;
static inline ToolMap *getTools(void *v) { return static_cast<ToolMap*>(v); }
DiagTools::DiagTools() : tools(new ToolMap()) {}
DiagTools::~DiagTools() { delete getTools(tools); }
DiagTool *DiagTools::getTool(llvm::StringRef toolCmd) {
ToolMap::iterator it = getTools(tools)->find(toolCmd);
return (it == getTools(tools)->end()) ? nullptr : it->getValue();
}
void DiagTools::registerTool(DiagTool *tool) {
(*getTools(tools))[tool->getName()] = tool;
}
void DiagTools::printCommands(llvm::raw_ostream &out) {
std::vector<llvm::StringRef> toolNames;
unsigned maxName = 0;
for (ToolMap::iterator it = getTools(tools)->begin(),
ei = getTools(tools)->end(); it != ei; ++it) {
toolNames.push_back(it->getKey());
unsigned len = it->getKey().size();
if (len > maxName)
maxName = len;
}
std::sort(toolNames.begin(), toolNames.end());
for (std::vector<llvm::StringRef>::iterator it = toolNames.begin(),
ei = toolNames.end(); it != ei; ++it) {
out << " " << (*it);
unsigned spaces = (maxName + 3) - (it->size());
for (unsigned i = 0; i < spaces; ++i)
out << ' ';
out << getTool(*it)->getDescription() << '\n';
}
}
namespace diagtool {
llvm::ManagedStatic<DiagTools> diagTools;
}

View File

@ -0,0 +1,70 @@
//===- DiagTool.h - Classes for defining diagtool tools -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the boilerplate for defining diagtool tools.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_DIAGTOOL_DIAGTOOL_H
#define LLVM_CLANG_TOOLS_DIAGTOOL_DIAGTOOL_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
namespace diagtool {
class DiagTool {
const std::string cmd;
const std::string description;
public:
DiagTool(llvm::StringRef toolCmd, llvm::StringRef toolDesc);
virtual ~DiagTool();
llvm::StringRef getName() const { return cmd; }
llvm::StringRef getDescription() const { return description; }
virtual int run(unsigned argc, char *argv[], llvm::raw_ostream &out) = 0;
};
class DiagTools {
void *tools;
public:
DiagTools();
~DiagTools();
DiagTool *getTool(llvm::StringRef toolCmd);
void registerTool(DiagTool *tool);
void printCommands(llvm::raw_ostream &out);
};
extern llvm::ManagedStatic<DiagTools> diagTools;
template <typename DIAGTOOL>
class RegisterDiagTool {
public:
RegisterDiagTool() { diagTools->registerTool(new DIAGTOOL()); }
};
} // end diagtool namespace
#define DEF_DIAGTOOL(NAME, DESC, CLSNAME)\
namespace {\
class CLSNAME : public diagtool::DiagTool {\
public:\
CLSNAME() : DiagTool(NAME, DESC) {}\
virtual ~CLSNAME() {}\
int run(unsigned argc, char *argv[], llvm::raw_ostream &out) override;\
};\
diagtool::RegisterDiagTool<CLSNAME> Register##CLSNAME;\
}
#endif

View File

@ -0,0 +1,109 @@
//===- DiagnosticNames.cpp - Defines a table of all builtin diagnostics ----==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DiagnosticNames.h"
#include "clang/Basic/AllDiagnostics.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace diagtool;
static const DiagnosticRecord BuiltinDiagnosticsByName[] = {
#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticIndexName.inc"
#undef DIAG_NAME_INDEX
};
llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() {
return llvm::makeArrayRef(BuiltinDiagnosticsByName);
}
// FIXME: Is it worth having two tables, especially when this one can get
// out of sync easily?
static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) \
{ #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticCrossTUKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#include "clang/Basic/DiagnosticSerializationKinds.inc"
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticCommentKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
#undef DIAG
};
static bool orderByID(const DiagnosticRecord &Left,
const DiagnosticRecord &Right) {
return Left.DiagID < Right.DiagID;
}
const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) {
DiagnosticRecord Key = {nullptr, DiagID, 0};
const DiagnosticRecord *Result =
std::lower_bound(std::begin(BuiltinDiagnosticsByID),
std::end(BuiltinDiagnosticsByID),
Key, orderByID);
assert(Result && "diagnostic not found; table may be out of date");
return *Result;
}
#define GET_DIAG_ARRAYS
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_DIAG_ARRAYS
// Second the table of options, sorted by name for fast binary lookup.
static const GroupRecord OptionTable[] = {
#define GET_DIAG_TABLE
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_DIAG_TABLE
};
llvm::StringRef GroupRecord::getName() const {
return StringRef(DiagGroupNames + NameOffset + 1, DiagGroupNames[NameOffset]);
}
GroupRecord::subgroup_iterator GroupRecord::subgroup_begin() const {
return DiagSubGroups + SubGroups;
}
GroupRecord::subgroup_iterator GroupRecord::subgroup_end() const {
return nullptr;
}
llvm::iterator_range<diagtool::GroupRecord::subgroup_iterator>
GroupRecord::subgroups() const {
return llvm::make_range(subgroup_begin(), subgroup_end());
}
GroupRecord::diagnostics_iterator GroupRecord::diagnostics_begin() const {
return DiagArrays + Members;
}
GroupRecord::diagnostics_iterator GroupRecord::diagnostics_end() const {
return nullptr;
}
llvm::iterator_range<diagtool::GroupRecord::diagnostics_iterator>
GroupRecord::diagnostics() const {
return llvm::make_range(diagnostics_begin(), diagnostics_end());
}
llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() {
return llvm::makeArrayRef(OptionTable);
}

View File

@ -0,0 +1,120 @@
//===- DiagnosticNames.h - Defines a table of all builtin diagnostics ------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_DIAGTOOL_DIAGNOSTICNAMES_H
#define LLVM_CLANG_TOOLS_DIAGTOOL_DIAGNOSTICNAMES_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
namespace diagtool {
struct DiagnosticRecord {
const char *NameStr;
short DiagID;
uint8_t NameLen;
llvm::StringRef getName() const {
return llvm::StringRef(NameStr, NameLen);
}
bool operator<(const DiagnosticRecord &Other) const {
return getName() < Other.getName();
}
};
/// \brief Get every diagnostic in the system, sorted by name.
llvm::ArrayRef<DiagnosticRecord> getBuiltinDiagnosticsByName();
/// \brief Get a diagnostic by its ID.
const DiagnosticRecord &getDiagnosticForID(short DiagID);
struct GroupRecord {
uint16_t NameOffset;
uint16_t Members;
uint16_t SubGroups;
llvm::StringRef getName() const;
template<typename RecordType>
class group_iterator {
const short *CurrentID;
friend struct GroupRecord;
group_iterator(const short *Start) : CurrentID(Start) {
if (CurrentID && *CurrentID == -1)
CurrentID = nullptr;
}
public:
typedef RecordType value_type;
typedef const value_type & reference;
typedef const value_type * pointer;
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
inline reference operator*() const;
inline pointer operator->() const {
return &operator*();
}
inline short getID() const {
return *CurrentID;
}
group_iterator &operator++() {
++CurrentID;
if (*CurrentID == -1)
CurrentID = nullptr;
return *this;
}
bool operator==(group_iterator &Other) const {
return CurrentID == Other.CurrentID;
}
bool operator!=(group_iterator &Other) const {
return CurrentID != Other.CurrentID;
}
};
typedef group_iterator<GroupRecord> subgroup_iterator;
subgroup_iterator subgroup_begin() const;
subgroup_iterator subgroup_end() const;
llvm::iterator_range<subgroup_iterator> subgroups() const;
typedef group_iterator<DiagnosticRecord> diagnostics_iterator;
diagnostics_iterator diagnostics_begin() const;
diagnostics_iterator diagnostics_end() const;
llvm::iterator_range<diagnostics_iterator> diagnostics() const;
bool operator<(llvm::StringRef Other) const {
return getName() < Other;
}
};
/// \brief Get every diagnostic group in the system, sorted by name.
llvm::ArrayRef<GroupRecord> getDiagnosticGroups();
template<>
inline GroupRecord::subgroup_iterator::reference
GroupRecord::subgroup_iterator::operator*() const {
return getDiagnosticGroups()[*CurrentID];
}
template<>
inline GroupRecord::diagnostics_iterator::reference
GroupRecord::diagnostics_iterator::operator*() const {
return getDiagnosticForID(*CurrentID);
}
} // end namespace diagtool
#endif

View File

@ -0,0 +1,74 @@
//===- FindDiagnosticID.cpp - diagtool tool for finding diagnostic id -----===//
//
// 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/AllDiagnostics.h"
#include "llvm/Support/CommandLine.h"
DEF_DIAGTOOL("find-diagnostic-id", "Print the id of the given diagnostic",
FindDiagnosticID)
using namespace clang;
using namespace diagtool;
static StringRef getNameFromID(StringRef Name) {
int DiagID;
if(!Name.getAsInteger(0, DiagID)) {
const DiagnosticRecord &Diag = getDiagnosticForID(DiagID);
return Diag.getName();
}
return StringRef();
}
static Optional<DiagnosticRecord>
findDiagnostic(ArrayRef<DiagnosticRecord> Diagnostics, StringRef Name) {
for (const auto &Diag : Diagnostics) {
StringRef DiagName = Diag.getName();
if (DiagName == Name)
return Diag;
}
return None;
}
int FindDiagnosticID::run(unsigned int argc, char **argv,
llvm::raw_ostream &OS) {
static llvm::cl::OptionCategory FindDiagnosticIDOptions(
"diagtool find-diagnostic-id options");
static llvm::cl::opt<std::string> DiagnosticName(
llvm::cl::Positional, llvm::cl::desc("<diagnostic-name>"),
llvm::cl::Required, llvm::cl::cat(FindDiagnosticIDOptions));
std::vector<const char *> Args;
Args.push_back("diagtool find-diagnostic-id");
for (const char *A : llvm::makeArrayRef(argv, argc))
Args.push_back(A);
llvm::cl::HideUnrelatedOptions(FindDiagnosticIDOptions);
llvm::cl::ParseCommandLineOptions((int)Args.size(), Args.data(),
"Diagnostic ID mapping utility");
ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
Optional<DiagnosticRecord> Diag =
findDiagnostic(AllDiagnostics, DiagnosticName);
if (!Diag) {
// Name to id failed, so try id to name.
auto Name = getNameFromID(DiagnosticName);
if (!Name.empty()) {
OS << Name << '\n';
return 0;
}
llvm::errs() << "error: invalid diagnostic '" << DiagnosticName << "'\n";
return 1;
}
OS << Diag->DiagID << "\n";
return 0;
}

View File

@ -0,0 +1,102 @@
//===- ListWarnings.h - diagtool tool for printing warning flags ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides a diagtool tool that displays warning flags for
// diagnostics.
//
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
#include "DiagnosticNames.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Format.h"
DEF_DIAGTOOL("list-warnings",
"List warnings and their corresponding flags",
ListWarnings)
using namespace clang;
using namespace diagtool;
namespace {
struct Entry {
llvm::StringRef DiagName;
llvm::StringRef Flag;
Entry(llvm::StringRef diagN, llvm::StringRef flag)
: DiagName(diagN), Flag(flag) {}
bool operator<(const Entry &x) const { return DiagName < x.DiagName; }
};
}
static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
for (const Entry &E : entries) {
out << " " << E.DiagName;
if (!E.Flag.empty())
out << " [-W" << E.Flag << "]";
out << '\n';
}
}
int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
std::vector<Entry> Flagged, Unflagged;
llvm::StringMap<std::vector<unsigned> > flagHistogram;
for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
const unsigned diagID = DR.DiagID;
if (DiagnosticIDs::isBuiltinNote(diagID))
continue;
if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
continue;
Entry entry(DR.getName(), DiagnosticIDs::getWarningOptionForDiag(diagID));
if (entry.Flag.empty())
Unflagged.push_back(entry);
else {
Flagged.push_back(entry);
flagHistogram[entry.Flag].push_back(diagID);
}
}
out << "Warnings with flags (" << Flagged.size() << "):\n";
printEntries(Flagged, out);
out << "Warnings without flags (" << Unflagged.size() << "):\n";
printEntries(Unflagged, out);
out << "\nSTATISTICS:\n\n";
double percentFlagged =
((double)Flagged.size()) / (Flagged.size() + Unflagged.size()) * 100.0;
out << " Percentage of warnings with flags: "
<< llvm::format("%.4g", percentFlagged) << "%\n";
out << " Number of unique flags: "
<< flagHistogram.size() << '\n';
double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size();
out << " Average number of diagnostics per flag: "
<< llvm::format("%.4g", avgDiagsPerFlag) << '\n';
out << " Number in -Wpedantic (not covered by other -W flags): "
<< flagHistogram["pedantic"].size() << '\n';
out << '\n';
return 0;
}

View File

@ -0,0 +1,146 @@
//===- 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 "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/Support/TargetSelect.h"
DEF_DIAGTOOL("show-enabled",
"Show which warnings are enabled for a given command line",
ShowEnabledWarnings)
using namespace clang;
using namespace diagtool;
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 void printUsage() {
llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n";
}
static char getCharForLevel(DiagnosticsEngine::Level Level) {
switch (Level) {
case DiagnosticsEngine::Ignored: return ' ';
case DiagnosticsEngine::Note: return '-';
case DiagnosticsEngine::Remark: return 'R';
case DiagnosticsEngine::Warning: return 'W';
case DiagnosticsEngine::Error: return 'E';
case DiagnosticsEngine::Fatal: return 'F';
}
llvm_unreachable("Unknown diagnostic level");
}
static IntrusiveRefCntPtr<DiagnosticsEngine>
createDiagnostics(unsigned int argc, char **argv) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
// Try to build a CompilerInvocation.
SmallVector<const char *, 4> Args;
Args.push_back("diagtool");
Args.append(argv, argv + argc);
std::unique_ptr<CompilerInvocation> Invocation =
createInvocationFromCommandLine(Args, InterimDiags);
if (!Invocation)
return nullptr;
// Build the diagnostics parser
IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts());
if (!FinalDiags)
return nullptr;
// Flush any errors created when initializing everything. This could happen
// for invalid command lines, which will probably give non-sensical results.
DiagsBuffer->FlushDiagnostics(*FinalDiags);
return FinalDiags;
}
int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
// First check our one flag (--levels).
bool ShouldShowLevels = true;
if (argc > 0) {
StringRef FirstArg(*argv);
if (FirstArg.equals("--no-levels")) {
ShouldShowLevels = false;
--argc;
++argv;
} else if (FirstArg.equals("--levels")) {
ShouldShowLevels = true;
--argc;
++argv;
}
}
// Create the diagnostic engine.
IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
if (!Diags) {
printUsage();
return EXIT_FAILURE;
}
// 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 DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
unsigned DiagID = DR.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(DR.getName(), WarningOpt, DiagLevel));
}
// Print them all out.
for (const PrettyDiag &PD : Active) {
if (ShouldShowLevels)
Out << getCharForLevel(PD.Level) << " ";
Out << PD.Name;
if (!PD.Flag.empty())
Out << " [-W" << PD.Flag << "]";
Out << '\n';
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,192 @@
//===- TreeView.cpp - diagtool tool for printing warning 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/AST/ASTDiagnostic.h"
#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Process.h"
DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView)
using namespace clang;
using namespace diagtool;
static bool hasColors(const llvm::raw_ostream &out) {
if (&out != &llvm::errs() && &out != &llvm::outs())
return false;
return llvm::errs().is_displayed() && llvm::outs().is_displayed();
}
class TreePrinter {
public:
llvm::raw_ostream &out;
const bool ShowColors;
bool Internal;
TreePrinter(llvm::raw_ostream &out)
: out(out), ShowColors(hasColors(out)), Internal(false) {}
void setColor(llvm::raw_ostream::Colors Color) {
if (ShowColors)
out << llvm::sys::Process::OutputColor(Color, false, false);
}
void resetColor() {
if (ShowColors)
out << llvm::sys::Process::ResetColor();
}
static bool isIgnored(unsigned DiagID) {
// FIXME: This feels like a hack.
static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
new DiagnosticOptions);
return Diags.isIgnored(DiagID, SourceLocation());
}
static bool enabledByDefault(const GroupRecord &Group) {
for (const DiagnosticRecord &DR : Group.diagnostics()) {
if (isIgnored(DR.DiagID))
return false;
}
for (const GroupRecord &GR : Group.subgroups()) {
if (!enabledByDefault(GR))
return false;
}
return true;
}
void printGroup(const GroupRecord &Group, unsigned Indent = 0) {
out.indent(Indent * 2);
if (enabledByDefault(Group))
setColor(llvm::raw_ostream::GREEN);
else
setColor(llvm::raw_ostream::YELLOW);
out << "-W" << Group.getName() << "\n";
resetColor();
++Indent;
for (const GroupRecord &GR : Group.subgroups()) {
printGroup(GR, Indent);
}
if (Internal) {
for (const DiagnosticRecord &DR : Group.diagnostics()) {
if (ShowColors && !isIgnored(DR.DiagID))
setColor(llvm::raw_ostream::GREEN);
out.indent(Indent * 2);
out << DR.getName();
resetColor();
out << "\n";
}
}
}
int showGroup(StringRef RootGroup) {
ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
if (RootGroup.size() > UINT16_MAX) {
llvm::errs() << "No such diagnostic group exists\n";
return 1;
}
const GroupRecord *Found =
std::lower_bound(AllGroups.begin(), AllGroups.end(), RootGroup);
if (Found == AllGroups.end() || Found->getName() != RootGroup) {
llvm::errs() << "No such diagnostic group exists\n";
return 1;
}
printGroup(*Found);
return 0;
}
int showAll() {
ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
llvm::DenseSet<unsigned> NonRootGroupIDs;
for (const GroupRecord &GR : AllGroups) {
for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE;
++SI) {
NonRootGroupIDs.insert((unsigned)SI.getID());
}
}
assert(NonRootGroupIDs.size() < AllGroups.size());
for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) {
if (!NonRootGroupIDs.count(i))
printGroup(AllGroups[i]);
}
return 0;
}
void showKey() {
if (ShowColors) {
out << '\n';
setColor(llvm::raw_ostream::GREEN);
out << "GREEN";
resetColor();
out << " = enabled by default\n\n";
}
}
};
static void printUsage() {
llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";
}
int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
// First check our one flag (--flags-only).
bool Internal = false;
if (argc > 0) {
StringRef FirstArg(*argv);
if (FirstArg.equals("--internal")) {
Internal = true;
--argc;
++argv;
}
}
bool ShowAll = false;
StringRef RootGroup;
switch (argc) {
case 0:
ShowAll = true;
break;
case 1:
RootGroup = argv[0];
if (RootGroup.startswith("-W"))
RootGroup = RootGroup.substr(2);
if (RootGroup == "everything")
ShowAll = true;
// FIXME: Handle other special warning flags, like -pedantic.
break;
default:
printUsage();
return -1;
}
TreePrinter TP(out);
TP.Internal = Internal;
TP.showKey();
return ShowAll ? TP.showAll() : TP.showGroup(RootGroup);
}

View File

@ -0,0 +1,26 @@
//===- diagtool_main.h - Entry point for invoking all diagnostic tools ----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the main function for diagtool.
//
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
using namespace diagtool;
int main(int argc, char *argv[]) {
if (argc > 1)
if (DiagTool *tool = diagTools->getTool(argv[1]))
return tool->run(argc - 2, &argv[2], llvm::outs());
llvm::errs() << "usage: diagtool <command> [<args>]\n\n";
diagTools->printCommands(llvm::errs());
return 1;
}