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