Home | History | Annotate | Line # | Download | only in TableGen
ClangSACheckersEmitter.cpp revision 1.1.1.2
      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 static std::string getParentPackageFullName(const Record *R) {
     30   std::string name;
     31   if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
     32     name = getPackageFullName(DI->getDef());
     33   return name;
     34 }
     35 
     36 static std::string getPackageFullName(const Record *R) {
     37   std::string name = getParentPackageFullName(R);
     38   if (!name.empty())
     39     name += ".";
     40   assert(!R->getValueAsString("PackageName").empty());
     41   name += R->getValueAsString("PackageName");
     42   return name;
     43 }
     44 
     45 static std::string getCheckerFullName(const Record *R) {
     46   std::string name = getParentPackageFullName(R);
     47   if (!name.empty())
     48     name += ".";
     49   assert(!R->getValueAsString("CheckerName").empty());
     50   name += R->getValueAsString("CheckerName");
     51   return name;
     52 }
     53 
     54 static std::string getStringValue(const Record &R, StringRef field) {
     55   if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
     56     return std::string(SI->getValue());
     57   return std::string();
     58 }
     59 
     60 // Calculates the integer value representing the BitsInit object
     61 static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) {
     62   assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
     63 
     64   uint64_t Value = 0;
     65   for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
     66     const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
     67     if (Bit)
     68       Value |= uint64_t(Bit->getValue()) << i;
     69     else
     70       PrintFatalError(R.getLoc(),
     71                       "missing Documentation for " + getCheckerFullName(&R));
     72   }
     73   return Value;
     74 }
     75 
     76 static std::string getCheckerDocs(const Record &R) {
     77   StringRef LandingPage;
     78   if (BitsInit *BI = R.getValueAsBitsInit("Documentation")) {
     79     uint64_t V = getValueFromBitsInit(BI, R);
     80     if (V == 1)
     81       LandingPage = "available_checks.html";
     82     else if (V == 2)
     83       LandingPage = "alpha_checks.html";
     84   }
     85 
     86   if (LandingPage.empty())
     87     return "";
     88 
     89   return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" +
     90           getCheckerFullName(&R))
     91       .str();
     92 }
     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 static std::string getCheckerOptionType(const Record &R) {
     98   if (BitsInit *BI = R.getValueAsBitsInit("Type")) {
     99     switch(getValueFromBitsInit(BI, R)) {
    100     case 0:
    101       return "int";
    102     case 1:
    103       return "string";
    104     case 2:
    105       return "bool";
    106     }
    107   }
    108   PrintFatalError(R.getLoc(),
    109                   "unable to parse command line option type for "
    110                   + getCheckerFullName(&R));
    111   return "";
    112 }
    113 
    114 static std::string getDevelopmentStage(const Record &R) {
    115   if (BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
    116     switch(getValueFromBitsInit(BI, R)) {
    117     case 0:
    118       return "alpha";
    119     case 1:
    120       return "released";
    121     }
    122   }
    123 
    124   PrintFatalError(R.getLoc(),
    125                   "unable to parse command line option type for "
    126                   + getCheckerFullName(&R));
    127   return "";
    128 }
    129 
    130 static bool isHidden(const Record *R) {
    131   if (R->getValueAsBit("Hidden"))
    132     return true;
    133 
    134   // Not declared as hidden, check the parent package if it is hidden.
    135   if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
    136     return isHidden(DI->getDef());
    137 
    138   return false;
    139 }
    140 
    141 static void printChecker(llvm::raw_ostream &OS, const Record &R) {
    142   OS << "CHECKER(" << "\"";
    143   OS.write_escaped(getCheckerFullName(&R)) << "\", ";
    144   OS << R.getName() << ", ";
    145   OS << "\"";
    146   OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
    147   OS << "\"";
    148   OS.write_escaped(getCheckerDocs(R));
    149   OS << "\", ";
    150 
    151   if (!isHidden(&R))
    152     OS << "false";
    153   else
    154     OS << "true";
    155 
    156   OS << ")\n";
    157 }
    158 
    159 static void printOption(llvm::raw_ostream &OS, StringRef FullName,
    160                         const Record &R) {
    161   OS << "\"";
    162   OS.write_escaped(getCheckerOptionType(R)) << "\", \"";
    163   OS.write_escaped(FullName) << "\", ";
    164   OS << '\"' << getStringValue(R, "CmdFlag") << "\", ";
    165   OS << '\"';
    166   OS.write_escaped(getStringValue(R, "Desc")) << "\", ";
    167   OS << '\"';
    168   OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", ";
    169   OS << '\"';
    170   OS << getDevelopmentStage(R) << "\", ";
    171 
    172   if (!R.getValueAsBit("Hidden"))
    173     OS << "false";
    174   else
    175     OS << "true";
    176 }
    177 
    178 void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
    179   std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
    180   std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
    181 
    182   using SortedRecords = llvm::StringMap<const Record *>;
    183 
    184   OS << "// This file is automatically generated. Do not edit this file by "
    185         "hand.\n";
    186 
    187   // Emit packages.
    188   //
    189   // PACKAGE(PACKAGENAME)
    190   //   - PACKAGENAME: The name of the package.
    191   OS << "\n"
    192         "#ifdef GET_PACKAGES\n";
    193   {
    194     SortedRecords sortedPackages;
    195     for (unsigned i = 0, e = packages.size(); i != e; ++i)
    196       sortedPackages[getPackageFullName(packages[i])] = packages[i];
    197 
    198     for (SortedRecords::iterator
    199            I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
    200       const Record &R = *I->second;
    201 
    202       OS << "PACKAGE(" << "\"";
    203       OS.write_escaped(getPackageFullName(&R)) << '\"';
    204       OS << ")\n";
    205     }
    206   }
    207   OS << "#endif // GET_PACKAGES\n"
    208         "\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   OS << "\n"
    226         "#ifdef GET_PACKAGE_OPTIONS\n";
    227   for (const Record *Package : packages) {
    228 
    229     if (Package->isValueUnset("PackageOptions"))
    230       continue;
    231 
    232     std::vector<Record *> PackageOptions = Package
    233                                        ->getValueAsListOfDefs("PackageOptions");
    234     for (Record *PackageOpt : PackageOptions) {
    235       OS << "PACKAGE_OPTION(";
    236       printOption(OS, getPackageFullName(Package), *PackageOpt);
    237       OS << ")\n";
    238     }
    239   }
    240   OS << "#endif // GET_PACKAGE_OPTIONS\n"
    241         "\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   OS << "\n"
    252         "#ifdef GET_CHECKERS\n"
    253         "\n";
    254   for (const Record *checker : checkers) {
    255     printChecker(OS, *checker);
    256   }
    257   OS << "\n"
    258         "#endif // GET_CHECKERS\n"
    259         "\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   OS << "\n"
    267         "#ifdef GET_CHECKER_DEPENDENCIES\n";
    268   for (const Record *Checker : checkers) {
    269     if (Checker->isValueUnset("Dependencies"))
    270       continue;
    271 
    272     for (const Record *Dependency :
    273                             Checker->getValueAsListOfDefs("Dependencies")) {
    274       OS << "CHECKER_DEPENDENCY(";
    275       OS << '\"';
    276       OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
    277       OS << '\"';
    278       OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
    279       OS << ")\n";
    280     }
    281   }
    282   OS << "\n"
    283         "#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   OS << "\n"
    292         "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n";
    293   for (const Record *Checker : checkers) {
    294     if (Checker->isValueUnset("WeakDependencies"))
    295       continue;
    296 
    297     for (const Record *Dependency :
    298          Checker->getValueAsListOfDefs("WeakDependencies")) {
    299       OS << "CHECKER_WEAK_DEPENDENCY(";
    300       OS << '\"';
    301       OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
    302       OS << '\"';
    303       OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
    304       OS << ")\n";
    305     }
    306   }
    307   OS << "\n"
    308         "#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   OS << "\n"
    326         "#ifdef GET_CHECKER_OPTIONS\n";
    327   for (const Record *Checker : checkers) {
    328 
    329     if (Checker->isValueUnset("CheckerOptions"))
    330       continue;
    331 
    332     std::vector<Record *> CheckerOptions = Checker
    333                                        ->getValueAsListOfDefs("CheckerOptions");
    334     for (Record *CheckerOpt : CheckerOptions) {
    335       OS << "CHECKER_OPTION(";
    336       printOption(OS, getCheckerFullName(Checker), *CheckerOpt);
    337       OS << ")\n";
    338     }
    339   }
    340   OS << "#endif // GET_CHECKER_OPTIONS\n"
    341         "\n";
    342 }
    343