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