180 lines · cpp
1//===- TreeView.cpp - diagtool tool for printing warning flags ------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DiagTool.h"10#include "DiagnosticNames.h"11#include "clang/Basic/AllDiagnostics.h"12#include "clang/Basic/Diagnostic.h"13#include "clang/Basic/DiagnosticOptions.h"14#include "llvm/ADT/DenseSet.h"15#include "llvm/Support/Format.h"16#include "llvm/Support/Process.h"17 18DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView)19 20using namespace clang;21using namespace diagtool;22 23class TreePrinter {24 using Colors = llvm::raw_ostream::Colors;25 26public:27 llvm::raw_ostream &out;28 bool Internal;29 30 TreePrinter(llvm::raw_ostream &out) : out(out), Internal(false) {}31 32 static bool isIgnored(unsigned DiagID) {33 // FIXME: This feels like a hack.34 static DiagnosticOptions DiagOpts;35 static clang::DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts);36 return Diags.isIgnored(DiagID, SourceLocation());37 }38 39 static bool unimplemented(const GroupRecord &Group) {40 if (!Group.diagnostics().empty())41 return false;42 43 return llvm::all_of(Group.subgroups(), unimplemented);44 }45 46 static bool enabledByDefault(const GroupRecord &Group) {47 for (const DiagnosticRecord &DR : Group.diagnostics()) {48 if (isIgnored(DR.DiagID))49 return false;50 }51 52 for (const GroupRecord &GR : Group.subgroups()) {53 if (!enabledByDefault(GR))54 return false;55 }56 57 return true;58 }59 60 void printGroup(const GroupRecord &Group, unsigned Indent = 0) {61 out.indent(Indent * 2);62 63 if (unimplemented(Group))64 out << Colors::RED;65 else if (enabledByDefault(Group))66 out << Colors::GREEN;67 else68 out << Colors::YELLOW;69 70 out << "-W" << Group.getName() << "\n" << Colors::RESET;71 72 ++Indent;73 for (const GroupRecord &GR : Group.subgroups()) {74 printGroup(GR, Indent);75 }76 77 if (Internal) {78 for (const DiagnosticRecord &DR : Group.diagnostics()) {79 if (!isIgnored(DR.DiagID))80 out << Colors::GREEN;81 out.indent(Indent * 2);82 out << DR.getName() << Colors::RESET << "\n";83 }84 }85 }86 87 int showGroup(StringRef RootGroup) {88 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();89 90 if (RootGroup.size() > UINT16_MAX) {91 llvm::errs() << "No such diagnostic group exists\n";92 return 1;93 }94 95 const GroupRecord *Found = llvm::lower_bound(AllGroups, RootGroup);96 if (Found == AllGroups.end() || Found->getName() != RootGroup) {97 llvm::errs() << "No such diagnostic group exists\n";98 return 1;99 }100 101 printGroup(*Found);102 103 return 0;104 }105 106 int showAll() {107 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();108 llvm::DenseSet<unsigned> NonRootGroupIDs;109 110 for (const GroupRecord &GR : AllGroups) {111 for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE;112 ++SI) {113 NonRootGroupIDs.insert((unsigned)SI.getID());114 }115 }116 117 assert(NonRootGroupIDs.size() < AllGroups.size());118 119 for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) {120 if (!NonRootGroupIDs.count(i))121 printGroup(AllGroups[i]);122 }123 124 return 0;125 }126 127 void showKey() {128 out << '\n' << Colors::GREEN << "GREEN" << Colors::RESET129 << " = enabled by default";130 out << '\n'131 << Colors::YELLOW << "YELLOW" << Colors::RESET132 << " = disabled by default";133 out << '\n' << Colors::RED << "RED" << Colors::RESET134 << " = unimplemented (accepted for GCC compatibility)\n\n";135 }136};137 138static void printUsage() {139 llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";140}141 142int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {143 // First check our one flag (--flags-only).144 bool Internal = false;145 if (argc > 0) {146 StringRef FirstArg(*argv);147 if (FirstArg == "--internal") {148 Internal = true;149 --argc;150 ++argv;151 }152 }153 154 bool ShowAll = false;155 StringRef RootGroup;156 157 switch (argc) {158 case 0:159 ShowAll = true;160 break;161 case 1:162 RootGroup = argv[0];163 RootGroup.consume_front("-W");164 if (RootGroup == "everything")165 ShowAll = true;166 // FIXME: Handle other special warning flags, like -pedantic.167 break;168 default:169 printUsage();170 return -1;171 }172 173 out.enable_colors(out.has_colors());174 175 TreePrinter TP(out);176 TP.Internal = Internal;177 TP.showKey();178 return ShowAll ? TP.showAll() : TP.showGroup(RootGroup);179}180