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