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