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