1 //===- TreeView.cpp - diagtool tool for printing warning flags ------------===//
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
7 //===----------------------------------------------------------------------===//
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"
18 DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView
)
20 using namespace clang
;
21 using namespace diagtool
;
24 using Colors
= llvm::raw_ostream::Colors
;
27 llvm::raw_ostream
&out
;
30 TreePrinter(llvm::raw_ostream
&out
) : out(out
), Internal(false) {}
32 static bool isIgnored(unsigned DiagID
) {
33 // FIXME: This feels like a hack.
34 static clang::DiagnosticsEngine
Diags(new DiagnosticIDs
,
35 new DiagnosticOptions
);
36 return Diags
.isIgnored(DiagID
, SourceLocation());
39 static bool unimplemented(const GroupRecord
&Group
) {
40 if (!Group
.diagnostics().empty())
43 return llvm::all_of(Group
.subgroups(), unimplemented
);
46 static bool enabledByDefault(const GroupRecord
&Group
) {
47 for (const DiagnosticRecord
&DR
: Group
.diagnostics()) {
48 if (isIgnored(DR
.DiagID
))
52 for (const GroupRecord
&GR
: Group
.subgroups()) {
53 if (!enabledByDefault(GR
))
60 void printGroup(const GroupRecord
&Group
, unsigned Indent
= 0) {
61 out
.indent(Indent
* 2);
63 if (unimplemented(Group
))
65 else if (enabledByDefault(Group
))
68 out
<< Colors::YELLOW
;
70 out
<< "-W" << Group
.getName() << "\n" << Colors::RESET
;
73 for (const GroupRecord
&GR
: Group
.subgroups()) {
74 printGroup(GR
, Indent
);
78 for (const DiagnosticRecord
&DR
: Group
.diagnostics()) {
79 if (!isIgnored(DR
.DiagID
))
81 out
.indent(Indent
* 2);
82 out
<< DR
.getName() << Colors::RESET
<< "\n";
87 int showGroup(StringRef RootGroup
) {
88 ArrayRef
<GroupRecord
> AllGroups
= getDiagnosticGroups();
90 if (RootGroup
.size() > UINT16_MAX
) {
91 llvm::errs() << "No such diagnostic group exists\n";
95 const GroupRecord
*Found
= llvm::lower_bound(AllGroups
, RootGroup
);
96 if (Found
== AllGroups
.end() || Found
->getName() != RootGroup
) {
97 llvm::errs() << "No such diagnostic group exists\n";
107 ArrayRef
<GroupRecord
> AllGroups
= getDiagnosticGroups();
108 llvm::DenseSet
<unsigned> NonRootGroupIDs
;
110 for (const GroupRecord
&GR
: AllGroups
) {
111 for (auto SI
= GR
.subgroup_begin(), SE
= GR
.subgroup_end(); SI
!= SE
;
113 NonRootGroupIDs
.insert((unsigned)SI
.getID());
117 assert(NonRootGroupIDs
.size() < AllGroups
.size());
119 for (unsigned i
= 0, e
= AllGroups
.size(); i
!= e
; ++i
) {
120 if (!NonRootGroupIDs
.count(i
))
121 printGroup(AllGroups
[i
]);
128 out
<< '\n' << Colors::GREEN
<< "GREEN" << Colors::RESET
129 << " = enabled by default";
131 << Colors::YELLOW
<< "YELLOW" << Colors::RESET
132 << " = disabled by default";
133 out
<< '\n' << Colors::RED
<< "RED" << Colors::RESET
134 << " = unimplemented (accepted for GCC compatibility)\n\n";
138 static void printUsage() {
139 llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";
142 int TreeView::run(unsigned int argc
, char **argv
, llvm::raw_ostream
&out
) {
143 // First check our one flag (--flags-only).
144 bool Internal
= false;
146 StringRef
FirstArg(*argv
);
147 if (FirstArg
.equals("--internal")) {
154 bool ShowAll
= false;
163 if (RootGroup
.startswith("-W"))
164 RootGroup
= RootGroup
.substr(2);
165 if (RootGroup
== "everything")
167 // FIXME: Handle other special warning flags, like -pedantic.
174 out
.enable_colors(out
.has_colors());
177 TP
.Internal
= Internal
;
179 return ShowAll
? TP
.showAll() : TP
.showGroup(RootGroup
);