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 = llvm::lower_bound(AllGroups, RootGroup); 106 if (Found == AllGroups.end() || Found->getName() != RootGroup) { 107 llvm::errs() << "No such diagnostic group exists\n"; 108 return 1; 109 } 110 111 printGroup(*Found); 112 113 return 0; 114 } 115 116 int showAll() { 117 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 118 llvm::DenseSet<unsigned> NonRootGroupIDs; 119 120 for (const GroupRecord &GR : AllGroups) { 121 for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE; 122 ++SI) { 123 NonRootGroupIDs.insert((unsigned)SI.getID()); 124 } 125 } 126 127 assert(NonRootGroupIDs.size() < AllGroups.size()); 128 129 for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) { 130 if (!NonRootGroupIDs.count(i)) 131 printGroup(AllGroups[i]); 132 } 133 134 return 0; 135 } 136 137 void showKey() { 138 if (ShowColors) { 139 out << '\n'; 140 setColor(llvm::raw_ostream::GREEN); 141 out << "GREEN"; 142 resetColor(); 143 out << " = enabled by default\n\n"; 144 } 145 } 146 }; 147 148 static void printUsage() { 149 llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n"; 150 } 151 152 int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 153 // First check our one flag (--flags-only). 154 bool Internal = false; 155 if (argc > 0) { 156 StringRef FirstArg(*argv); 157 if (FirstArg.equals("--internal")) { 158 Internal = true; 159 --argc; 160 ++argv; 161 } 162 } 163 164 bool ShowAll = false; 165 StringRef RootGroup; 166 167 switch (argc) { 168 case 0: 169 ShowAll = true; 170 break; 171 case 1: 172 RootGroup = argv[0]; 173 if (RootGroup.startswith("-W")) 174 RootGroup = RootGroup.substr(2); 175 if (RootGroup == "everything") 176 ShowAll = true; 177 // FIXME: Handle other special warning flags, like -pedantic. 178 break; 179 default: 180 printUsage(); 181 return -1; 182 } 183 184 TreePrinter TP(out); 185 TP.Internal = Internal; 186 TP.showKey(); 187 return ShowAll ? TP.showAll() : TP.showGroup(RootGroup); 188 } 189