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