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 GroupRecord Key = { RootGroup.size(), RootGroup.data(), 0, 0 }; 98 const GroupRecord *Found = 99 std::lower_bound(AllGroups.begin(), AllGroups.end(), Key); 100 101 if (Found == AllGroups.end() || Found->getName() != RootGroup) { 102 llvm::errs() << "No such diagnostic group exists\n"; 103 return 1; 104 } 105 106 printGroup(out, *Found, FlagsOnly); 107 108 return 0; 109 } 110 111 static int showAll(llvm::raw_ostream &out, bool FlagsOnly) { 112 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 113 llvm::DenseSet<unsigned> NonRootGroupIDs; 114 115 for (ArrayRef<GroupRecord>::iterator I = AllGroups.begin(), 116 E = AllGroups.end(); 117 I != E; ++I) { 118 for (GroupRecord::subgroup_iterator SI = I->subgroup_begin(), 119 SE = I->subgroup_end(); 120 SI != SE; ++SI) { 121 NonRootGroupIDs.insert((unsigned)SI.getID()); 122 } 123 } 124 125 assert(NonRootGroupIDs.size() < AllGroups.size()); 126 127 for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) { 128 if (!NonRootGroupIDs.count(i)) 129 printGroup(out, AllGroups[i], FlagsOnly); 130 } 131 132 return 0; 133 } 134 135 int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 136 // First check our one flag (--flags-only). 137 bool FlagsOnly = false; 138 if (argc > 0) { 139 StringRef FirstArg(*argv); 140 if (FirstArg.equals("--flags-only")) { 141 FlagsOnly = true; 142 --argc; 143 ++argv; 144 } 145 } 146 147 bool ShowAll = false; 148 StringRef RootGroup; 149 150 switch (argc) { 151 case 0: 152 ShowAll = true; 153 break; 154 case 1: 155 RootGroup = argv[0]; 156 if (RootGroup.startswith("-W")) 157 RootGroup = RootGroup.substr(2); 158 if (RootGroup == "everything") 159 ShowAll = true; 160 // FIXME: Handle other special warning flags, like -pedantic. 161 break; 162 default: 163 printUsage(); 164 return -1; 165 } 166 167 if (showColors(out)) { 168 out << '\n'; 169 setColor(true, out, llvm::raw_ostream::GREEN); 170 out << "GREEN"; 171 resetColor(true, out); 172 out << " = enabled by default\n\n"; 173 } 174 175 if (ShowAll) 176 return showAll(out, FlagsOnly); 177 178 return showGroup(out, RootGroup, FlagsOnly); 179 } 180 181