Coverage Report

Created: 2021-09-21 08:58

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/diagtool/TreeView.cpp
Line
Count
Source (jump to first uncovered line)
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
DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView)
19
20
using namespace clang;
21
using namespace diagtool;
22
23
class TreePrinter {
24
  using Colors = llvm::raw_ostream::Colors;
25
26
public:
27
  llvm::raw_ostream &out;
28
  bool Internal;
29
30
7
  TreePrinter(llvm::raw_ostream &out) : out(out), Internal(false) {}
31
32
13.0k
  static bool isIgnored(unsigned DiagID) {
33
    // FIXME: This feels like a hack.
34
13.0k
    static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
35
13.0k
                                          new DiagnosticOptions);
36
13.0k
    return Diags.isIgnored(DiagID, SourceLocation());
37
13.0k
  }
38
39
3.72k
  static bool unimplemented(const GroupRecord &Group) {
40
3.72k
    if (!Group.diagnostics().empty())
41
3.29k
      return false;
42
43
429
    for (const GroupRecord &GR : Group.subgroups())
44
308
      if (!unimplemented(GR))
45
304
        return false;
46
47
125
    return true;
48
429
  }
49
50
3.90k
  static bool enabledByDefault(const GroupRecord &Group) {
51
5.65k
    for (const DiagnosticRecord &DR : Group.diagnostics()) {
52
5.65k
      if (isIgnored(DR.DiagID))
53
1.64k
        return false;
54
5.65k
    }
55
56
2.26k
    for (const GroupRecord &GR : Group.subgroups()) {
57
617
      if (!enabledByDefault(GR))
58
273
        return false;
59
617
    }
60
61
1.98k
    return true;
62
2.26k
  }
63
64
3.41k
  void printGroup(const GroupRecord &Group, unsigned Indent = 0) {
65
3.41k
    out.indent(Indent * 2);
66
67
3.41k
    if (unimplemented(Group))
68
121
      out << Colors::RED;
69
3.29k
    else if (enabledByDefault(Group))
70
1.64k
      out << Colors::GREEN;
71
1.64k
    else
72
1.64k
      out << Colors::YELLOW;
73
74
3.41k
    out << "-W" << Group.getName() << "\n" << Colors::RESET;
75
76
3.41k
    ++Indent;
77
3.41k
    for (const GroupRecord &GR : Group.subgroups()) {
78
1.77k
      printGroup(GR, Indent);
79
1.77k
    }
80
81
3.41k
    if (Internal) {
82
7.35k
      for (const DiagnosticRecord &DR : Group.diagnostics()) {
83
7.35k
        if (!isIgnored(DR.DiagID))
84
3.45k
          out << Colors::GREEN;
85
7.35k
        out.indent(Indent * 2);
86
7.35k
        out << DR.getName() << Colors::RESET << "\n";
87
7.35k
      }
88
3.28k
    }
89
3.41k
  }
90
91
4
  int showGroup(StringRef RootGroup) {
92
4
    ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
93
94
4
    if (RootGroup.size() > UINT16_MAX) {
95
0
      llvm::errs() << "No such diagnostic group exists\n";
96
0
      return 1;
97
0
    }
98
99
4
    const GroupRecord *Found = llvm::lower_bound(AllGroups, RootGroup);
100
4
    if (Found == AllGroups.end() || Found->getName() != RootGroup) {
101
1
      llvm::errs() << "No such diagnostic group exists\n";
102
1
      return 1;
103
1
    }
104
105
3
    printGroup(*Found);
106
107
3
    return 0;
108
4
  }
109
110
3
  int showAll() {
111
3
    ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
112
3
    llvm::DenseSet<unsigned> NonRootGroupIDs;
113
114
2.73k
    for (const GroupRecord &GR : AllGroups) {
115
4.21k
      for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE;
116
2.73k
           
++SI1.47k
) {
117
1.47k
        NonRootGroupIDs.insert((unsigned)SI.getID());
118
1.47k
      }
119
2.73k
    }
120
121
3
    assert(NonRootGroupIDs.size() < AllGroups.size());
122
123
2.73k
    for (unsigned i = 0, e = AllGroups.size(); i != e; 
++i2.73k
) {
124
2.73k
      if (!NonRootGroupIDs.count(i))
125
1.63k
        printGroup(AllGroups[i]);
126
2.73k
    }
127
128
3
    return 0;
129
3
  }
130
131
7
  void showKey() {
132
7
    out << '\n' << Colors::GREEN << "GREEN" << Colors::RESET
133
7
        << " = enabled by default";
134
7
    out << '\n' << Colors::RED << "RED" << Colors::RESET
135
7
        << " = unimplemented (accepted for GCC compatibility)\n\n";
136
7
  }
137
};
138
139
0
static void printUsage() {
140
0
  llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";
141
0
}
142
143
7
int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
144
  // First check our one flag (--flags-only).
145
7
  bool Internal = false;
146
7
  if (argc > 0) {
147
7
    StringRef FirstArg(*argv);
148
7
    if (FirstArg.equals("--internal")) {
149
4
      Internal = true;
150
4
      --argc;
151
4
      ++argv;
152
4
    }
153
7
  }
154
155
7
  bool ShowAll = false;
156
7
  StringRef RootGroup;
157
158
7
  switch (argc) {
159
1
  case 0:
160
1
    ShowAll = true;
161
1
    break;
162
6
  case 1:
163
6
    RootGroup = argv[0];
164
6
    if (RootGroup.startswith("-W"))
165
5
      RootGroup = RootGroup.substr(2);
166
6
    if (RootGroup == "everything")
167
2
      ShowAll = true;
168
    // FIXME: Handle other special warning flags, like -pedantic.
169
6
    break;
170
0
  default:
171
0
    printUsage();
172
0
    return -1;
173
7
  }
174
175
7
  out.enable_colors(out.has_colors());
176
177
7
  TreePrinter TP(out);
178
7
  TP.Internal = Internal;
179
7
  TP.showKey();
180
7
  return ShowAll ? 
TP.showAll()3
:
TP.showGroup(RootGroup)4
;
181
7
}