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-exception 6// 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 clang::DiagnosticsEngine Diags(new DiagnosticIDs, 35 new DiagnosticOptions); 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 for (const GroupRecord &GR : Group.subgroups()) 44 if (!unimplemented(GR)) 45 return false; 46 47 return true; 48 } 49 50 static bool enabledByDefault(const GroupRecord &Group) { 51 for (const DiagnosticRecord &DR : Group.diagnostics()) { 52 if (isIgnored(DR.DiagID)) 53 return false; 54 } 55 56 for (const GroupRecord &GR : Group.subgroups()) { 57 if (!enabledByDefault(GR)) 58 return false; 59 } 60 61 return true; 62 } 63 64 void printGroup(const GroupRecord &Group, unsigned Indent = 0) { 65 out.indent(Indent * 2); 66 67 if (unimplemented(Group)) 68 out << Colors::RED; 69 else if (enabledByDefault(Group)) 70 out << Colors::GREEN; 71 else 72 out << Colors::YELLOW; 73 74 out << "-W" << Group.getName() << "\n" << Colors::RESET; 75 76 ++Indent; 77 for (const GroupRecord &GR : Group.subgroups()) { 78 printGroup(GR, Indent); 79 } 80 81 if (Internal) { 82 for (const DiagnosticRecord &DR : Group.diagnostics()) { 83 if (!isIgnored(DR.DiagID)) 84 out << Colors::GREEN; 85 out.indent(Indent * 2); 86 out << DR.getName() << Colors::RESET << "\n"; 87 } 88 } 89 } 90 91 int showGroup(StringRef RootGroup) { 92 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 93 94 if (RootGroup.size() > UINT16_MAX) { 95 llvm::errs() << "No such diagnostic group exists\n"; 96 return 1; 97 } 98 99 const GroupRecord *Found = llvm::lower_bound(AllGroups, RootGroup); 100 if (Found == AllGroups.end() || Found->getName() != RootGroup) { 101 llvm::errs() << "No such diagnostic group exists\n"; 102 return 1; 103 } 104 105 printGroup(*Found); 106 107 return 0; 108 } 109 110 int showAll() { 111 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 112 llvm::DenseSet<unsigned> NonRootGroupIDs; 113 114 for (const GroupRecord &GR : AllGroups) { 115 for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE; 116 ++SI) { 117 NonRootGroupIDs.insert((unsigned)SI.getID()); 118 } 119 } 120 121 assert(NonRootGroupIDs.size() < AllGroups.size()); 122 123 for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) { 124 if (!NonRootGroupIDs.count(i)) 125 printGroup(AllGroups[i]); 126 } 127 128 return 0; 129 } 130 131 void showKey() { 132 out << '\n' << Colors::GREEN << "GREEN" << Colors::RESET 133 << " = enabled by default"; 134 out << '\n' << Colors::RED << "RED" << Colors::RESET 135 << " = unimplemented (accepted for GCC compatibility)\n\n"; 136 } 137}; 138 139static void printUsage() { 140 llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n"; 141} 142 143int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 144 // First check our one flag (--flags-only). 145 bool Internal = false; 146 if (argc > 0) { 147 StringRef FirstArg(*argv); 148 if (FirstArg.equals("--internal")) { 149 Internal = true; 150 --argc; 151 ++argv; 152 } 153 } 154 155 bool ShowAll = false; 156 StringRef RootGroup; 157 158 switch (argc) { 159 case 0: 160 ShowAll = true; 161 break; 162 case 1: 163 RootGroup = argv[0]; 164 if (RootGroup.startswith("-W")) 165 RootGroup = RootGroup.substr(2); 166 if (RootGroup == "everything") 167 ShowAll = true; 168 // FIXME: Handle other special warning flags, like -pedantic. 169 break; 170 default: 171 printUsage(); 172 return -1; 173 } 174 175 out.enable_colors(out.has_colors()); 176 177 TreePrinter TP(out); 178 TP.Internal = Internal; 179 TP.showKey(); 180 return ShowAll ? TP.showAll() : TP.showGroup(RootGroup); 181} 182