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