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