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