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