Coverage Report

Created: 2022-05-14 11:35

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
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
// This tablegen backend emits Clang Static Analyzer checkers tables.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "TableGenBackends.h"
14
#include "llvm/ADT/StringMap.h"
15
#include "llvm/TableGen/Error.h"
16
#include "llvm/TableGen/Record.h"
17
#include "llvm/TableGen/TableGenBackend.h"
18
#include <map>
19
#include <string>
20
21
using namespace llvm;
22
23
//===----------------------------------------------------------------------===//
24
// Static Analyzer Checkers Tables generation
25
//===----------------------------------------------------------------------===//
26
27
static std::string getPackageFullName(const Record *R, StringRef Sep = ".");
28
29
static std::string getParentPackageFullName(const Record *R,
30
0
                                            StringRef Sep = ".") {
31
0
  std::string name;
32
0
  if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
33
0
    name = getPackageFullName(DI->getDef(), Sep);
34
0
  return name;
35
0
}
36
37
0
static std::string getPackageFullName(const Record *R, StringRef Sep) {
38
0
  std::string name = getParentPackageFullName(R, Sep);
39
0
  if (!name.empty())
40
0
    name += Sep;
41
0
  assert(!R->getValueAsString("PackageName").empty());
42
0
  name += R->getValueAsString("PackageName");
43
0
  return name;
44
0
}
45
46
0
static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") {
47
0
  std::string name = getParentPackageFullName(R, Sep);
48
0
  if (!name.empty())
49
0
    name += Sep;
50
0
  assert(!R->getValueAsString("CheckerName").empty());
51
0
  name += R->getValueAsString("CheckerName");
52
0
  return name;
53
0
}
54
55
0
static std::string getStringValue(const Record &R, StringRef field) {
56
0
  if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
57
0
    return std::string(SI->getValue());
58
0
  return std::string();
59
0
}
60
61
// Calculates the integer value representing the BitsInit object
62
0
static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) {
63
0
  assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
64
65
0
  uint64_t Value = 0;
66
0
  for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
67
0
    const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
68
0
    if (Bit)
69
0
      Value |= uint64_t(Bit->getValue()) << i;
70
0
    else
71
0
      PrintFatalError(R.getLoc(),
72
0
                      "missing Documentation for " + getCheckerFullName(&R));
73
0
  }
74
0
  return Value;
75
0
}
76
77
0
static std::string getCheckerDocs(const Record &R) {
78
0
  const BitsInit *BI = R.getValueAsBitsInit("Documentation");
79
0
  if (!BI)
80
0
    PrintFatalError(R.getLoc(), "missing Documentation<...> member for " +
81
0
                                    getCheckerFullName(&R));
82
83
  // Ignore 'Documentation<NotDocumented>' checkers.
84
0
  if (getValueFromBitsInit(BI, R) == 0)
85
0
    return "";
86
87
0
  std::string CheckerFullName = StringRef(getCheckerFullName(&R, "-")).lower();
88
0
  return (llvm::Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") +
89
0
          CheckerFullName)
90
0
      .str();
91
0
}
92
93
/// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that
94
/// the class itself has to be modified for adding a new option type in
95
/// CheckerBase.td.
96
0
static std::string getCheckerOptionType(const Record &R) {
97
0
  if (BitsInit *BI = R.getValueAsBitsInit("Type")) {
98
0
    switch(getValueFromBitsInit(BI, R)) {
99
0
    case 0:
100
0
      return "int";
101
0
    case 1:
102
0
      return "string";
103
0
    case 2:
104
0
      return "bool";
105
0
    }
106
0
  }
107
0
  PrintFatalError(R.getLoc(),
108
0
                  "unable to parse command line option type for "
109
0
                  + getCheckerFullName(&R));
110
0
  return "";
111
0
}
112
113
0
static std::string getDevelopmentStage(const Record &R) {
114
0
  if (BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
115
0
    switch(getValueFromBitsInit(BI, R)) {
116
0
    case 0:
117
0
      return "alpha";
118
0
    case 1:
119
0
      return "released";
120
0
    }
121
0
  }
122
123
0
  PrintFatalError(R.getLoc(),
124
0
                  "unable to parse command line option type for "
125
0
                  + getCheckerFullName(&R));
126
0
  return "";
127
0
}
128
129
0
static bool isHidden(const Record *R) {
130
0
  if (R->getValueAsBit("Hidden"))
131
0
    return true;
132
133
  // Not declared as hidden, check the parent package if it is hidden.
134
0
  if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
135
0
    return isHidden(DI->getDef());
136
137
0
  return false;
138
0
}
139
140
0
static void printChecker(llvm::raw_ostream &OS, const Record &R) {
141
0
  OS << "CHECKER(" << "\"";
142
0
  OS.write_escaped(getCheckerFullName(&R)) << "\", ";
143
0
  OS << R.getName() << ", ";
144
0
  OS << "\"";
145
0
  OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
146
0
  OS << "\"";
147
0
  OS.write_escaped(getCheckerDocs(R));
148
0
  OS << "\", ";
149
150
0
  if (!isHidden(&R))
151
0
    OS << "false";
152
0
  else
153
0
    OS << "true";
154
155
0
  OS << ")\n";
156
0
}
157
158
static void printOption(llvm::raw_ostream &OS, StringRef FullName,
159
0
                        const Record &R) {
160
0
  OS << "\"";
161
0
  OS.write_escaped(getCheckerOptionType(R)) << "\", \"";
162
0
  OS.write_escaped(FullName) << "\", ";
163
0
  OS << '\"' << getStringValue(R, "CmdFlag") << "\", ";
164
0
  OS << '\"';
165
0
  OS.write_escaped(getStringValue(R, "Desc")) << "\", ";
166
0
  OS << '\"';
167
0
  OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", ";
168
0
  OS << '\"';
169
0
  OS << getDevelopmentStage(R) << "\", ";
170
171
0
  if (!R.getValueAsBit("Hidden"))
172
0
    OS << "false";
173
0
  else
174
0
    OS << "true";
175
0
}
176
177
0
void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
178
0
  std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
179
0
  std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
180
181
0
  using SortedRecords = llvm::StringMap<const Record *>;
182
183
0
  OS << "// This file is automatically generated. Do not edit this file by "
184
0
        "hand.\n";
185
186
  // Emit packages.
187
  //
188
  // PACKAGE(PACKAGENAME)
189
  //   - PACKAGENAME: The name of the package.
190
0
  OS << "\n"
191
0
        "#ifdef GET_PACKAGES\n";
192
0
  {
193
0
    SortedRecords sortedPackages;
194
0
    for (unsigned i = 0, e = packages.size(); i != e; ++i)
195
0
      sortedPackages[getPackageFullName(packages[i])] = packages[i];
196
  
197
0
    for (SortedRecords::iterator
198
0
           I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
199
0
      const Record &R = *I->second;
200
  
201
0
      OS << "PACKAGE(" << "\"";
202
0
      OS.write_escaped(getPackageFullName(&R)) << '\"';
203
0
      OS << ")\n";
204
0
    }
205
0
  }
206
0
  OS << "#endif // GET_PACKAGES\n"
207
0
        "\n";
208
209
  // Emit a package option.
210
  //
211
  // PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT)
212
  //   - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
213
  //                 This is important for validating user input. Note that
214
  //                 it's a string, rather than an actual type: since we can
215
  //                 load checkers runtime, we can't use template hackery for
216
  //                 sorting this out compile-time.
217
  //   - PACKAGENAME: Name of the package.
218
  //   - OPTIONNAME: Name of the option.
219
  //   - DESCRIPTION
220
  //   - DEFAULT: The default value for this option.
221
  //
222
  // The full option can be specified in the command like like this:
223
  //   -analyzer-config PACKAGENAME:OPTIONNAME=VALUE
224
0
  OS << "\n"
225
0
        "#ifdef GET_PACKAGE_OPTIONS\n";
226
0
  for (const Record *Package : packages) {
227
228
0
    if (Package->isValueUnset("PackageOptions"))
229
0
      continue;
230
231
0
    std::vector<Record *> PackageOptions = Package
232
0
                                       ->getValueAsListOfDefs("PackageOptions");
233
0
    for (Record *PackageOpt : PackageOptions) {
234
0
      OS << "PACKAGE_OPTION(";
235
0
      printOption(OS, getPackageFullName(Package), *PackageOpt);
236
0
      OS << ")\n";
237
0
    }
238
0
  }
239
0
  OS << "#endif // GET_PACKAGE_OPTIONS\n"
240
0
        "\n";
241
242
  // Emit checkers.
243
  //
244
  // CHECKER(FULLNAME, CLASS, HELPTEXT)
245
  //   - FULLNAME: The full name of the checker, including packages, e.g.:
246
  //               alpha.cplusplus.UninitializedObject
247
  //   - CLASS: The name of the checker, with "Checker" appended, e.g.:
248
  //            UninitializedObjectChecker
249
  //   - HELPTEXT: The description of the checker.
250
0
  OS << "\n"
251
0
        "#ifdef GET_CHECKERS\n"
252
0
        "\n";
253
0
  for (const Record *checker : checkers) {
254
0
    printChecker(OS, *checker);
255
0
  }
256
0
  OS << "\n"
257
0
        "#endif // GET_CHECKERS\n"
258
0
        "\n";
259
260
  // Emit dependencies.
261
  //
262
  // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
263
  //   - FULLNAME: The full name of the checker that depends on another checker.
264
  //   - DEPENDENCY: The full name of the checker FULLNAME depends on.
265
0
  OS << "\n"
266
0
        "#ifdef GET_CHECKER_DEPENDENCIES\n";
267
0
  for (const Record *Checker : checkers) {
268
0
    if (Checker->isValueUnset("Dependencies"))
269
0
      continue;
270
271
0
    for (const Record *Dependency :
272
0
                            Checker->getValueAsListOfDefs("Dependencies")) {
273
0
      OS << "CHECKER_DEPENDENCY(";
274
0
      OS << '\"';
275
0
      OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
276
0
      OS << '\"';
277
0
      OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
278
0
      OS << ")\n";
279
0
    }
280
0
  }
281
0
  OS << "\n"
282
0
        "#endif // GET_CHECKER_DEPENDENCIES\n";
283
284
  // Emit weak dependencies.
285
  //
286
  // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
287
  //   - FULLNAME: The full name of the checker that is supposed to be
288
  //     registered first.
289
  //   - DEPENDENCY: The full name of the checker FULLNAME weak depends on.
290
0
  OS << "\n"
291
0
        "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n";
292
0
  for (const Record *Checker : checkers) {
293
0
    if (Checker->isValueUnset("WeakDependencies"))
294
0
      continue;
295
296
0
    for (const Record *Dependency :
297
0
         Checker->getValueAsListOfDefs("WeakDependencies")) {
298
0
      OS << "CHECKER_WEAK_DEPENDENCY(";
299
0
      OS << '\"';
300
0
      OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
301
0
      OS << '\"';
302
0
      OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
303
0
      OS << ")\n";
304
0
    }
305
0
  }
306
0
  OS << "\n"
307
0
        "#endif // GET_CHECKER_WEAK_DEPENDENCIES\n";
308
309
  // Emit a package option.
310
  //
311
  // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT)
312
  //   - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
313
  //                 This is important for validating user input. Note that
314
  //                 it's a string, rather than an actual type: since we can
315
  //                 load checkers runtime, we can't use template hackery for
316
  //                 sorting this out compile-time.
317
  //   - CHECKERNAME: Name of the package.
318
  //   - OPTIONNAME: Name of the option.
319
  //   - DESCRIPTION
320
  //   - DEFAULT: The default value for this option.
321
  //
322
  // The full option can be specified in the command like like this:
323
  //   -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
324
0
  OS << "\n"
325
0
        "#ifdef GET_CHECKER_OPTIONS\n";
326
0
  for (const Record *Checker : checkers) {
327
328
0
    if (Checker->isValueUnset("CheckerOptions"))
329
0
      continue;
330
331
0
    std::vector<Record *> CheckerOptions = Checker
332
0
                                       ->getValueAsListOfDefs("CheckerOptions");
333
0
    for (Record *CheckerOpt : CheckerOptions) {
334
0
      OS << "CHECKER_OPTION(";
335
0
      printOption(OS, getCheckerFullName(Checker), *CheckerOpt);
336
0
      OS << ")\n";
337
0
    }
338
0
  }
339
0
  OS << "#endif // GET_CHECKER_OPTIONS\n"
340
0
        "\n";
341
0
}