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 18 DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView) 19 20 using namespace clang; 21 using namespace diagtool; 22 23 class TreePrinter { 24 using Colors = llvm::raw_ostream::Colors; 25 26 public: 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 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 else 68 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::RESET 129 << " = enabled by default"; 130 out << '\n' << Colors::RED << "RED" << Colors::RESET 131 << " = unimplemented (accepted for GCC compatibility)\n\n"; 132 } 133 }; 134 135 static void printUsage() { 136 llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n"; 137 } 138 139 int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 140 // First check our one flag (--flags-only). 141 bool Internal = false; 142 if (argc > 0) { 143 StringRef FirstArg(*argv); 144 if (FirstArg.equals("--internal")) { 145 Internal = true; 146 --argc; 147 ++argv; 148 } 149 } 150 151 bool ShowAll = false; 152 StringRef RootGroup; 153 154 switch (argc) { 155 case 0: 156 ShowAll = true; 157 break; 158 case 1: 159 RootGroup = argv[0]; 160 if (RootGroup.startswith("-W")) 161 RootGroup = RootGroup.substr(2); 162 if (RootGroup == "everything") 163 ShowAll = true; 164 // FIXME: Handle other special warning flags, like -pedantic. 165 break; 166 default: 167 printUsage(); 168 return -1; 169 } 170 171 out.enable_colors(out.has_colors()); 172 173 TreePrinter TP(out); 174 TP.Internal = Internal; 175 TP.showKey(); 176 return ShowAll ? TP.showAll() : TP.showGroup(RootGroup); 177 } 178