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 (const GroupRecord &GR : Group.subgroups()) { 66 printGroup(GR, Indent); 67 } 68 69 if (!FlagsOnly) { 70 for (const DiagnosticRecord &DR : Group.diagnostics()) { 71 if (ShowColors && !isIgnored(DR.DiagID)) 72 setColor(llvm::raw_ostream::GREEN); 73 out.indent(Indent * 2); 74 out << DR.getName(); 75 resetColor(); 76 out << "\n"; 77 } 78 } 79 } 80 81 int showGroup(StringRef RootGroup) { 82 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 83 84 if (RootGroup.size() > UINT16_MAX) { 85 llvm::errs() << "No such diagnostic group exists\n"; 86 return 1; 87 } 88 89 const GroupRecord *Found = 90 std::lower_bound(AllGroups.begin(), AllGroups.end(), RootGroup); 91 92 if (Found == AllGroups.end() || Found->getName() != RootGroup) { 93 llvm::errs() << "No such diagnostic group exists\n"; 94 return 1; 95 } 96 97 printGroup(*Found); 98 99 return 0; 100 } 101 102 int showAll() { 103 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 104 llvm::DenseSet<unsigned> NonRootGroupIDs; 105 106 for (const GroupRecord &GR : AllGroups) { 107 for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE; 108 ++SI) { 109 NonRootGroupIDs.insert((unsigned)SI.getID()); 110 } 111 } 112 113 assert(NonRootGroupIDs.size() < AllGroups.size()); 114 115 for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) { 116 if (!NonRootGroupIDs.count(i)) 117 printGroup(AllGroups[i]); 118 } 119 120 return 0; 121 } 122 123 void showKey() { 124 if (ShowColors) { 125 out << '\n'; 126 setColor(llvm::raw_ostream::GREEN); 127 out << "GREEN"; 128 resetColor(); 129 out << " = enabled by default\n\n"; 130 } 131 } 132 }; 133 134 static void printUsage() { 135 llvm::errs() << "Usage: diagtool tree [--flags-only] [<diagnostic-group>]\n"; 136 } 137 138 int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 139 // First check our one flag (--flags-only). 140 bool FlagsOnly = false; 141 if (argc > 0) { 142 StringRef FirstArg(*argv); 143 if (FirstArg.equals("--flags-only")) { 144 FlagsOnly = true; 145 --argc; 146 ++argv; 147 } 148 } 149 150 bool ShowAll = false; 151 StringRef RootGroup; 152 153 switch (argc) { 154 case 0: 155 ShowAll = true; 156 break; 157 case 1: 158 RootGroup = argv[0]; 159 if (RootGroup.startswith("-W")) 160 RootGroup = RootGroup.substr(2); 161 if (RootGroup == "everything") 162 ShowAll = true; 163 // FIXME: Handle other special warning flags, like -pedantic. 164 break; 165 default: 166 printUsage(); 167 return -1; 168 } 169 170 TreePrinter TP(out); 171 TP.FlagsOnly = FlagsOnly; 172 TP.showKey(); 173 return ShowAll ? TP.showAll() : TP.showGroup(RootGroup); 174 } 175