Richard Smith de876adab0 [diagtree] Use a different color for unimplemented GCC diagnostic flags
instead of the "enabled by default" color.

It may be technically correct to list unimplemented diagnostics as
"enabled by default" but it's quite misleading.
2020-01-31 13:40:32 -08:00

182 lines
4.6 KiB
C++

//===- TreeView.cpp - diagtool tool for printing warning flags ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
#include "DiagnosticNames.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;
class TreePrinter {
using Colors = llvm::raw_ostream::Colors;
public:
llvm::raw_ostream &out;
bool Internal;
TreePrinter(llvm::raw_ostream &out) : out(out), Internal(false) {}
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 unimplemented(const GroupRecord &Group) {
if (!Group.diagnostics().empty())
return false;
for (const GroupRecord &GR : Group.subgroups())
if (!unimplemented(GR))
return false;
return true;
}
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 (unimplemented(Group))
out << Colors::RED;
else if (enabledByDefault(Group))
out << Colors::GREEN;
else
out << Colors::YELLOW;
out << "-W" << Group.getName() << "\n" << Colors::RESET;
++Indent;
for (const GroupRecord &GR : Group.subgroups()) {
printGroup(GR, Indent);
}
if (Internal) {
for (const DiagnosticRecord &DR : Group.diagnostics()) {
if (!isIgnored(DR.DiagID))
out << Colors::GREEN;
out.indent(Indent * 2);
out << DR.getName() << Colors::RESET << "\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 = llvm::lower_bound(AllGroups, 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() {
out << '\n' << Colors::GREEN << "GREEN" << Colors::RESET
<< " = enabled by default";
out << '\n' << Colors::RED << "RED" << Colors::RESET
<< " = unimplemented (accepted for GCC compatibility)\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;
}
out.enable_colors(out.has_colors());
TreePrinter TP(out);
TP.Internal = Internal;
TP.showKey();
return ShowAll ? TP.showAll() : TP.showGroup(RootGroup);
}