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