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