aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
blob: 1b3e8b11549dd9d5b029649e6b94adcd52d8b971 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/Twine.h"
#include <map>

using namespace clang;
using namespace ento;

//===----------------------------------------------------------------------===//
// Methods of CmdLineOption, PackageInfo and CheckerInfo.
//===----------------------------------------------------------------------===//

LLVM_DUMP_METHOD void CmdLineOption::dump() const {
  dumpToStream(llvm::errs());
}

LLVM_DUMP_METHOD void
CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
  // The description can be just checked in Checkers.inc, the point here is to
  // debug whether we succeeded in parsing it.
  Out << OptionName << " (" << OptionType << ", "
      << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
      << DefaultValStr;
}

static StringRef toString(StateFromCmdLine Kind) {
  switch (Kind) {
  case StateFromCmdLine::State_Disabled:
    return "Disabled";
  case StateFromCmdLine::State_Enabled:
    return "Enabled";
  case StateFromCmdLine::State_Unspecified:
    return "Unspecified";
  }
  llvm_unreachable("Unhandled StateFromCmdLine enum");
}

LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); }

LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
  // The description can be just checked in Checkers.inc, the point here is to
  // debug whether we succeeded in parsing it. Same with documentation uri.
  Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
      << ")\n";
  Out << "  Options:\n";
  for (const CmdLineOption &Option : CmdLineOptions) {
    Out << "    ";
    Option.dumpToStream(Out);
    Out << '\n';
  }
  Out << "  Dependencies:\n";
  for (const CheckerInfo *Dependency : Dependencies) {
    Out << "  " << Dependency->FullName << '\n';
  }
  Out << "  Weak dependencies:\n";
  for (const CheckerInfo *Dependency : WeakDependencies) {
    Out << "    " << Dependency->FullName << '\n';
  }
}

LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); }

LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
  Out << FullName << "\n";
  Out << "  Options:\n";
  for (const CmdLineOption &Option : CmdLineOptions) {
    Out << "    ";
    Option.dumpToStream(Out);
    Out << '\n';
  }
}

static constexpr char PackageSeparator = '.';

static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
  // Does the checker's full name have the package as a prefix?
  if (!Checker.FullName.startswith(PackageName))
    return false;

  // Is the package actually just the name of a specific checker?
  if (Checker.FullName.size() == PackageName.size())
    return true;

  // Is the checker in the package (or a subpackage)?
  if (Checker.FullName[PackageName.size()] == PackageSeparator)
    return true;

  return false;
}

CheckerInfoListRange
CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
  auto It = checker_registry::binaryFind(Checkers, CmdLineArg);

  if (!isInPackage(*It, CmdLineArg))
    return {Checkers.end(), Checkers.end()};

  // See how large the package is.
  // If the package doesn't exist, assume the option refers to a single
  // checker.
  size_t Size = 1;
  llvm::StringMap<size_t>::const_iterator PackageSize =
      PackageSizes.find(CmdLineArg);

  if (PackageSize != PackageSizes.end())
    Size = PackageSize->getValue();

  return {It, It + Size};
}
//===----------------------------------------------------------------------===//
// Printing functions.
//===----------------------------------------------------------------------===//

void CheckerRegistryData::printCheckerWithDescList(
    const AnalyzerOptions &AnOpts, raw_ostream &Out,
    size_t MaxNameChars) const {
  // FIXME: Print available packages.

  Out << "CHECKERS:\n";

  // Find the maximum option length.
  size_t OptionFieldWidth = 0;
  for (const auto &Checker : Checkers) {
    // Limit the amount of padding we are willing to give up for alignment.
    //   Package.Name     Description  [Hidden]
    size_t NameLength = Checker.FullName.size();
    if (NameLength <= MaxNameChars)
      OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
  }

  const size_t InitialPad = 2;

  auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
                   StringRef Description) {
    AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
                                         InitialPad, OptionFieldWidth);
    Out << '\n';
  };

  for (const auto &Checker : Checkers) {
    // The order of this if branches is significant, we wouldn't like to display
    // developer checkers even in the alpha output. For example,
    // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
    // by default, and users (even when the user is a developer of an alpha
    // checker) shouldn't normally tinker with whether they should be enabled.

    if (Checker.IsHidden) {
      if (AnOpts.ShowCheckerHelpDeveloper)
        Print(Out, Checker, Checker.Desc);
      continue;
    }

    if (Checker.FullName.startswith("alpha")) {
      if (AnOpts.ShowCheckerHelpAlpha)
        Print(Out, Checker,
              ("(Enable only for development!) " + Checker.Desc).str());
      continue;
    }

    if (AnOpts.ShowCheckerHelp)
      Print(Out, Checker, Checker.Desc);
  }
}

void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {
  for (const auto *i : EnabledCheckers)
    Out << i->FullName << '\n';
}

void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
                                                 raw_ostream &Out) const {
  Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
  Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
  Out << "       -analyzer-config OPTION1=VALUE, -analyzer-config "
         "OPTION2=VALUE, ...\n\n";
  Out << "OPTIONS:\n\n";

  // It's usually ill-advised to use multimap, but clang will terminate after
  // this function.
  std::multimap<StringRef, const CmdLineOption &> OptionMap;

  for (const CheckerInfo &Checker : Checkers) {
    for (const CmdLineOption &Option : Checker.CmdLineOptions) {
      OptionMap.insert({Checker.FullName, Option});
    }
  }

  for (const PackageInfo &Package : Packages) {
    for (const CmdLineOption &Option : Package.CmdLineOptions) {
      OptionMap.insert({Package.FullName, Option});
    }
  }

  auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,
                  StringRef Desc) {
    AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
                                         /*InitialPad*/ 2,
                                         /*EntryWidth*/ 50,
                                         /*MinLineWidth*/ 90);
    Out << "\n\n";
  };
  for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
       OptionMap) {
    const CmdLineOption &Option = Entry.second;
    std::string FullOption = (Entry.first + ":" + Option.OptionName).str();

    std::string Desc =
        ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
         (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
            .str();

    // The list of these if branches is significant, we wouldn't like to
    // display hidden alpha checker options for
    // -analyzer-checker-option-help-alpha.

    if (Option.IsHidden) {
      if (AnOpts.ShowCheckerOptionDeveloperList)
        Print(Out, FullOption, Desc);
      continue;
    }

    if (Option.DevelopmentStatus == "alpha" ||
        Entry.first.startswith("alpha")) {
      if (AnOpts.ShowCheckerOptionAlphaList)
        Print(Out, FullOption,
              llvm::Twine("(Enable only for development!) " + Desc).str());
      continue;
    }

    if (AnOpts.ShowCheckerOptionList)
      Print(Out, FullOption, Desc);
  }
}