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