Clang Project

clang_source_code/tools/diagtool/TreeView.cpp
1//===- TreeView.cpp - diagtool tool for printing warning flags ------------===//
2//
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
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
20using namespace clang;
21using namespace diagtool;
22
23static 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
29class TreePrinter {
30public:
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, falsefalse);
41  }
42
43  void resetColor() {
44    if (ShowColors)
45      out << llvm::sys::Process::ResetColor();
46  }
47
48  static bool isIgnored(unsigned DiagID) {
49    // FIXME: This feels like a hack.
50    static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
51                                          new DiagnosticOptions);
52    return Diags.isIgnored(DiagIDSourceLocation());
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 &Groupunsigned 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<GroupRecordAllGroups = 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<GroupRecordAllGroups = 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 = 0e = 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
150static void printUsage() {
151  llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";
152}
153
154int TreeView::run(unsigned int argcchar **argvllvm::raw_ostream &out) {
155  // First check our one flag (--flags-only).
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    // FIXME: Handle other special warning flags, like -pedantic.
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