17330f729Sjoerg //===- TreeView.cpp - diagtool tool for printing warning flags ------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "DiagTool.h"
107330f729Sjoerg #include "DiagnosticNames.h"
117330f729Sjoerg #include "clang/Basic/AllDiagnostics.h"
127330f729Sjoerg #include "clang/Basic/Diagnostic.h"
137330f729Sjoerg #include "clang/Basic/DiagnosticOptions.h"
147330f729Sjoerg #include "llvm/ADT/DenseSet.h"
157330f729Sjoerg #include "llvm/Support/Format.h"
167330f729Sjoerg #include "llvm/Support/Process.h"
177330f729Sjoerg
187330f729Sjoerg DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView)
197330f729Sjoerg
207330f729Sjoerg using namespace clang;
217330f729Sjoerg using namespace diagtool;
227330f729Sjoerg
237330f729Sjoerg class TreePrinter {
247330f729Sjoerg using Colors = llvm::raw_ostream::Colors;
257330f729Sjoerg
267330f729Sjoerg public:
277330f729Sjoerg llvm::raw_ostream &out;
287330f729Sjoerg bool Internal;
297330f729Sjoerg
TreePrinter(llvm::raw_ostream & out)307330f729Sjoerg TreePrinter(llvm::raw_ostream &out) : out(out), Internal(false) {}
317330f729Sjoerg
isIgnored(unsigned DiagID)327330f729Sjoerg static bool isIgnored(unsigned DiagID) {
337330f729Sjoerg // FIXME: This feels like a hack.
347330f729Sjoerg static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
357330f729Sjoerg new DiagnosticOptions);
367330f729Sjoerg return Diags.isIgnored(DiagID, SourceLocation());
377330f729Sjoerg }
387330f729Sjoerg
unimplemented(const GroupRecord & Group)39*e038c9c4Sjoerg static bool unimplemented(const GroupRecord &Group) {
40*e038c9c4Sjoerg if (!Group.diagnostics().empty())
41*e038c9c4Sjoerg return false;
42*e038c9c4Sjoerg
43*e038c9c4Sjoerg for (const GroupRecord &GR : Group.subgroups())
44*e038c9c4Sjoerg if (!unimplemented(GR))
45*e038c9c4Sjoerg return false;
46*e038c9c4Sjoerg
47*e038c9c4Sjoerg return true;
48*e038c9c4Sjoerg }
49*e038c9c4Sjoerg
enabledByDefault(const GroupRecord & Group)507330f729Sjoerg static bool enabledByDefault(const GroupRecord &Group) {
517330f729Sjoerg for (const DiagnosticRecord &DR : Group.diagnostics()) {
527330f729Sjoerg if (isIgnored(DR.DiagID))
537330f729Sjoerg return false;
547330f729Sjoerg }
557330f729Sjoerg
567330f729Sjoerg for (const GroupRecord &GR : Group.subgroups()) {
577330f729Sjoerg if (!enabledByDefault(GR))
587330f729Sjoerg return false;
597330f729Sjoerg }
607330f729Sjoerg
617330f729Sjoerg return true;
627330f729Sjoerg }
637330f729Sjoerg
printGroup(const GroupRecord & Group,unsigned Indent=0)647330f729Sjoerg void printGroup(const GroupRecord &Group, unsigned Indent = 0) {
657330f729Sjoerg out.indent(Indent * 2);
667330f729Sjoerg
67*e038c9c4Sjoerg if (unimplemented(Group))
68*e038c9c4Sjoerg out << Colors::RED;
69*e038c9c4Sjoerg else if (enabledByDefault(Group))
707330f729Sjoerg out << Colors::GREEN;
717330f729Sjoerg else
727330f729Sjoerg out << Colors::YELLOW;
737330f729Sjoerg
747330f729Sjoerg out << "-W" << Group.getName() << "\n" << Colors::RESET;
757330f729Sjoerg
767330f729Sjoerg ++Indent;
777330f729Sjoerg for (const GroupRecord &GR : Group.subgroups()) {
787330f729Sjoerg printGroup(GR, Indent);
797330f729Sjoerg }
807330f729Sjoerg
817330f729Sjoerg if (Internal) {
827330f729Sjoerg for (const DiagnosticRecord &DR : Group.diagnostics()) {
837330f729Sjoerg if (!isIgnored(DR.DiagID))
847330f729Sjoerg out << Colors::GREEN;
857330f729Sjoerg out.indent(Indent * 2);
867330f729Sjoerg out << DR.getName() << Colors::RESET << "\n";
877330f729Sjoerg }
887330f729Sjoerg }
897330f729Sjoerg }
907330f729Sjoerg
showGroup(StringRef RootGroup)917330f729Sjoerg int showGroup(StringRef RootGroup) {
927330f729Sjoerg ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
937330f729Sjoerg
947330f729Sjoerg if (RootGroup.size() > UINT16_MAX) {
957330f729Sjoerg llvm::errs() << "No such diagnostic group exists\n";
967330f729Sjoerg return 1;
977330f729Sjoerg }
987330f729Sjoerg
997330f729Sjoerg const GroupRecord *Found = llvm::lower_bound(AllGroups, RootGroup);
1007330f729Sjoerg if (Found == AllGroups.end() || Found->getName() != RootGroup) {
1017330f729Sjoerg llvm::errs() << "No such diagnostic group exists\n";
1027330f729Sjoerg return 1;
1037330f729Sjoerg }
1047330f729Sjoerg
1057330f729Sjoerg printGroup(*Found);
1067330f729Sjoerg
1077330f729Sjoerg return 0;
1087330f729Sjoerg }
1097330f729Sjoerg
showAll()1107330f729Sjoerg int showAll() {
1117330f729Sjoerg ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
1127330f729Sjoerg llvm::DenseSet<unsigned> NonRootGroupIDs;
1137330f729Sjoerg
1147330f729Sjoerg for (const GroupRecord &GR : AllGroups) {
1157330f729Sjoerg for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE;
1167330f729Sjoerg ++SI) {
1177330f729Sjoerg NonRootGroupIDs.insert((unsigned)SI.getID());
1187330f729Sjoerg }
1197330f729Sjoerg }
1207330f729Sjoerg
1217330f729Sjoerg assert(NonRootGroupIDs.size() < AllGroups.size());
1227330f729Sjoerg
1237330f729Sjoerg for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) {
1247330f729Sjoerg if (!NonRootGroupIDs.count(i))
1257330f729Sjoerg printGroup(AllGroups[i]);
1267330f729Sjoerg }
1277330f729Sjoerg
1287330f729Sjoerg return 0;
1297330f729Sjoerg }
1307330f729Sjoerg
showKey()1317330f729Sjoerg void showKey() {
1327330f729Sjoerg out << '\n' << Colors::GREEN << "GREEN" << Colors::RESET
133*e038c9c4Sjoerg << " = enabled by default";
134*e038c9c4Sjoerg out << '\n' << Colors::RED << "RED" << Colors::RESET
135*e038c9c4Sjoerg << " = unimplemented (accepted for GCC compatibility)\n\n";
1367330f729Sjoerg }
1377330f729Sjoerg };
1387330f729Sjoerg
printUsage()1397330f729Sjoerg static void printUsage() {
1407330f729Sjoerg llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";
1417330f729Sjoerg }
1427330f729Sjoerg
run(unsigned int argc,char ** argv,llvm::raw_ostream & out)1437330f729Sjoerg int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
1447330f729Sjoerg // First check our one flag (--flags-only).
1457330f729Sjoerg bool Internal = false;
1467330f729Sjoerg if (argc > 0) {
1477330f729Sjoerg StringRef FirstArg(*argv);
1487330f729Sjoerg if (FirstArg.equals("--internal")) {
1497330f729Sjoerg Internal = true;
1507330f729Sjoerg --argc;
1517330f729Sjoerg ++argv;
1527330f729Sjoerg }
1537330f729Sjoerg }
1547330f729Sjoerg
1557330f729Sjoerg bool ShowAll = false;
1567330f729Sjoerg StringRef RootGroup;
1577330f729Sjoerg
1587330f729Sjoerg switch (argc) {
1597330f729Sjoerg case 0:
1607330f729Sjoerg ShowAll = true;
1617330f729Sjoerg break;
1627330f729Sjoerg case 1:
1637330f729Sjoerg RootGroup = argv[0];
1647330f729Sjoerg if (RootGroup.startswith("-W"))
1657330f729Sjoerg RootGroup = RootGroup.substr(2);
1667330f729Sjoerg if (RootGroup == "everything")
1677330f729Sjoerg ShowAll = true;
1687330f729Sjoerg // FIXME: Handle other special warning flags, like -pedantic.
1697330f729Sjoerg break;
1707330f729Sjoerg default:
1717330f729Sjoerg printUsage();
1727330f729Sjoerg return -1;
1737330f729Sjoerg }
1747330f729Sjoerg
1757330f729Sjoerg out.enable_colors(out.has_colors());
1767330f729Sjoerg
1777330f729Sjoerg TreePrinter TP(out);
1787330f729Sjoerg TP.Internal = Internal;
1797330f729Sjoerg TP.showKey();
1807330f729Sjoerg return ShowAll ? TP.showAll() : TP.showGroup(RootGroup);
1817330f729Sjoerg }
182