Home | History | Annotate | Line # | Download | only in Core
      1 //===- CheckerRegistry.h - Maintains all available checkers -----*- 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 #include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
     10 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
     11 #include "llvm/ADT/Twine.h"
     12 #include <map>
     13 
     14 using namespace clang;
     15 using namespace ento;
     16 
     17 //===----------------------------------------------------------------------===//
     18 // Methods of CmdLineOption, PackageInfo and CheckerInfo.
     19 //===----------------------------------------------------------------------===//
     20 
     21 LLVM_DUMP_METHOD void CmdLineOption::dump() const {
     22   dumpToStream(llvm::errs());
     23 }
     24 
     25 LLVM_DUMP_METHOD void
     26 CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
     27   // The description can be just checked in Checkers.inc, the point here is to
     28   // debug whether we succeeded in parsing it.
     29   Out << OptionName << " (" << OptionType << ", "
     30       << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
     31       << DefaultValStr;
     32 }
     33 
     34 static StringRef toString(StateFromCmdLine Kind) {
     35   switch (Kind) {
     36   case StateFromCmdLine::State_Disabled:
     37     return "Disabled";
     38   case StateFromCmdLine::State_Enabled:
     39     return "Enabled";
     40   case StateFromCmdLine::State_Unspecified:
     41     return "Unspecified";
     42   }
     43   llvm_unreachable("Unhandled StateFromCmdLine enum");
     44 }
     45 
     46 LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); }
     47 
     48 LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
     49   // The description can be just checked in Checkers.inc, the point here is to
     50   // debug whether we succeeded in parsing it. Same with documentation uri.
     51   Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
     52       << ")\n";
     53   Out << "  Options:\n";
     54   for (const CmdLineOption &Option : CmdLineOptions) {
     55     Out << "    ";
     56     Option.dumpToStream(Out);
     57     Out << '\n';
     58   }
     59   Out << "  Dependencies:\n";
     60   for (const CheckerInfo *Dependency : Dependencies) {
     61     Out << "  " << Dependency->FullName << '\n';
     62   }
     63   Out << "  Weak dependencies:\n";
     64   for (const CheckerInfo *Dependency : WeakDependencies) {
     65     Out << "    " << Dependency->FullName << '\n';
     66   }
     67 }
     68 
     69 LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); }
     70 
     71 LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
     72   Out << FullName << "\n";
     73   Out << "  Options:\n";
     74   for (const CmdLineOption &Option : CmdLineOptions) {
     75     Out << "    ";
     76     Option.dumpToStream(Out);
     77     Out << '\n';
     78   }
     79 }
     80 
     81 static constexpr char PackageSeparator = '.';
     82 
     83 static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
     84   // Does the checker's full name have the package as a prefix?
     85   if (!Checker.FullName.startswith(PackageName))
     86     return false;
     87 
     88   // Is the package actually just the name of a specific checker?
     89   if (Checker.FullName.size() == PackageName.size())
     90     return true;
     91 
     92   // Is the checker in the package (or a subpackage)?
     93   if (Checker.FullName[PackageName.size()] == PackageSeparator)
     94     return true;
     95 
     96   return false;
     97 }
     98 
     99 CheckerInfoListRange
    100 CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
    101   auto It = checker_registry::binaryFind(Checkers, CmdLineArg);
    102 
    103   if (!isInPackage(*It, CmdLineArg))
    104     return {Checkers.end(), Checkers.end()};
    105 
    106   // See how large the package is.
    107   // If the package doesn't exist, assume the option refers to a single
    108   // checker.
    109   size_t Size = 1;
    110   llvm::StringMap<size_t>::const_iterator PackageSize =
    111       PackageSizes.find(CmdLineArg);
    112 
    113   if (PackageSize != PackageSizes.end())
    114     Size = PackageSize->getValue();
    115 
    116   return {It, It + Size};
    117 }
    118 //===----------------------------------------------------------------------===//
    119 // Printing functions.
    120 //===----------------------------------------------------------------------===//
    121 
    122 void CheckerRegistryData::printCheckerWithDescList(
    123     const AnalyzerOptions &AnOpts, raw_ostream &Out,
    124     size_t MaxNameChars) const {
    125   // FIXME: Print available packages.
    126 
    127   Out << "CHECKERS:\n";
    128 
    129   // Find the maximum option length.
    130   size_t OptionFieldWidth = 0;
    131   for (const auto &Checker : Checkers) {
    132     // Limit the amount of padding we are willing to give up for alignment.
    133     //   Package.Name     Description  [Hidden]
    134     size_t NameLength = Checker.FullName.size();
    135     if (NameLength <= MaxNameChars)
    136       OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
    137   }
    138 
    139   const size_t InitialPad = 2;
    140 
    141   auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
    142                    StringRef Description) {
    143     AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
    144                                          InitialPad, OptionFieldWidth);
    145     Out << '\n';
    146   };
    147 
    148   for (const auto &Checker : Checkers) {
    149     // The order of this if branches is significant, we wouldn't like to display
    150     // developer checkers even in the alpha output. For example,
    151     // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
    152     // by default, and users (even when the user is a developer of an alpha
    153     // checker) shouldn't normally tinker with whether they should be enabled.
    154 
    155     if (Checker.IsHidden) {
    156       if (AnOpts.ShowCheckerHelpDeveloper)
    157         Print(Out, Checker, Checker.Desc);
    158       continue;
    159     }
    160 
    161     if (Checker.FullName.startswith("alpha")) {
    162       if (AnOpts.ShowCheckerHelpAlpha)
    163         Print(Out, Checker,
    164               ("(Enable only for development!) " + Checker.Desc).str());
    165       continue;
    166     }
    167 
    168     if (AnOpts.ShowCheckerHelp)
    169       Print(Out, Checker, Checker.Desc);
    170   }
    171 }
    172 
    173 void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {
    174   for (const auto *i : EnabledCheckers)
    175     Out << i->FullName << '\n';
    176 }
    177 
    178 void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
    179                                                  raw_ostream &Out) const {
    180   Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
    181   Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
    182   Out << "       -analyzer-config OPTION1=VALUE, -analyzer-config "
    183          "OPTION2=VALUE, ...\n\n";
    184   Out << "OPTIONS:\n\n";
    185 
    186   // It's usually ill-advised to use multimap, but clang will terminate after
    187   // this function.
    188   std::multimap<StringRef, const CmdLineOption &> OptionMap;
    189 
    190   for (const CheckerInfo &Checker : Checkers) {
    191     for (const CmdLineOption &Option : Checker.CmdLineOptions) {
    192       OptionMap.insert({Checker.FullName, Option});
    193     }
    194   }
    195 
    196   for (const PackageInfo &Package : Packages) {
    197     for (const CmdLineOption &Option : Package.CmdLineOptions) {
    198       OptionMap.insert({Package.FullName, Option});
    199     }
    200   }
    201 
    202   auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,
    203                   StringRef Desc) {
    204     AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
    205                                          /*InitialPad*/ 2,
    206                                          /*EntryWidth*/ 50,
    207                                          /*MinLineWidth*/ 90);
    208     Out << "\n\n";
    209   };
    210   for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
    211        OptionMap) {
    212     const CmdLineOption &Option = Entry.second;
    213     std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
    214 
    215     std::string Desc =
    216         ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
    217          (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
    218             .str();
    219 
    220     // The list of these if branches is significant, we wouldn't like to
    221     // display hidden alpha checker options for
    222     // -analyzer-checker-option-help-alpha.
    223 
    224     if (Option.IsHidden) {
    225       if (AnOpts.ShowCheckerOptionDeveloperList)
    226         Print(Out, FullOption, Desc);
    227       continue;
    228     }
    229 
    230     if (Option.DevelopmentStatus == "alpha" ||
    231         Entry.first.startswith("alpha")) {
    232       if (AnOpts.ShowCheckerOptionAlphaList)
    233         Print(Out, FullOption,
    234               llvm::Twine("(Enable only for development!) " + Desc).str());
    235       continue;
    236     }
    237 
    238     if (AnOpts.ShowCheckerOptionList)
    239       Print(Out, FullOption, Desc);
    240   }
    241 }
    242