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