Coverage Report

Created: 2020-09-22 08:39

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