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