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 class TreePrinter { 24 using Color = llvm::raw_ostream::Color; 25 26 public: 27 llvm::raw_ostream &out; 28 bool Internal; 29 30 TreePrinter(llvm::raw_ostream &out) : out(out), Internal(false) { 31 if (&out != &llvm::errs() && &out != &llvm::outs()) 32 out.disable_colors(); 33 } 34 35 static bool isIgnored(unsigned DiagID) { 36 // FIXME: This feels like a hack. 37 static clang::DiagnosticsEngine Diags(new DiagnosticIDs, 38 new DiagnosticOptions); 39 return Diags.isIgnored(DiagID, SourceLocation()); 40 } 41 42 static bool enabledByDefault(const GroupRecord &Group) { 43 for (const DiagnosticRecord &DR : Group.diagnostics()) { 44 if (isIgnored(DR.DiagID)) 45 return false; 46 } 47 48 for (const GroupRecord &GR : Group.subgroups()) { 49 if (!enabledByDefault(GR)) 50 return false; 51 } 52 53 return true; 54 } 55 56 void printGroup(const GroupRecord &Group, unsigned Indent = 0) { 57 out.indent(Indent * 2); 58 59 if (enabledByDefault(Group)) 60 out << Color::GREEN; 61 else 62 out << Color::YELLOW; 63 64 out << "-W" << Group.getName() << "\n" << Color::RESET; 65 66 ++Indent; 67 for (const GroupRecord &GR : Group.subgroups()) { 68 printGroup(GR, Indent); 69 } 70 71 if (Internal) { 72 for (const DiagnosticRecord &DR : Group.diagnostics()) { 73 if (!isIgnored(DR.DiagID)) 74 out << Color::GREEN; 75 out.indent(Indent * 2); 76 out << DR.getName() << Color::RESET << "\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 = llvm::lower_bound(AllGroups, RootGroup); 90 if (Found == AllGroups.end() || Found->getName() != RootGroup) { 91 llvm::errs() << "No such diagnostic group exists\n"; 92 return 1; 93 } 94 95 printGroup(*Found); 96 97 return 0; 98 } 99 100 int showAll() { 101 ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); 102 llvm::DenseSet<unsigned> NonRootGroupIDs; 103 104 for (const GroupRecord &GR : AllGroups) { 105 for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE; 106 ++SI) { 107 NonRootGroupIDs.insert((unsigned)SI.getID()); 108 } 109 } 110 111 assert(NonRootGroupIDs.size() < AllGroups.size()); 112 113 for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) { 114 if (!NonRootGroupIDs.count(i)) 115 printGroup(AllGroups[i]); 116 } 117 118 return 0; 119 } 120 121 void showKey() { 122 out << '\n' 123 << Color::GREEN << "GREEN" << Color::RESET 124 << " = enabled by default\n\n"; 125 } 126 }; 127 128 static void printUsage() { 129 llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n"; 130 } 131 132 int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 133 // First check our one flag (--flags-only). 134 bool Internal = false; 135 if (argc > 0) { 136 StringRef FirstArg(*argv); 137 if (FirstArg.equals("--internal")) { 138 Internal = true; 139 --argc; 140 ++argv; 141 } 142 } 143 144 bool ShowAll = false; 145 StringRef RootGroup; 146 147 switch (argc) { 148 case 0: 149 ShowAll = true; 150 break; 151 case 1: 152 RootGroup = argv[0]; 153 if (RootGroup.startswith("-W")) 154 RootGroup = RootGroup.substr(2); 155 if (RootGroup == "everything") 156 ShowAll = true; 157 // FIXME: Handle other special warning flags, like -pedantic. 158 break; 159 default: 160 printUsage(); 161 return -1; 162 } 163 164 TreePrinter TP(out); 165 TP.Internal = Internal; 166 TP.showKey(); 167 return ShowAll ? TP.showAll() : TP.showGroup(RootGroup); 168 } 169