Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
Line
Count
Source (jump to first uncovered line)
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
0
LLVM_DUMP_METHOD void CmdLineOption::dump() const {
22
0
  dumpToStream(llvm::errs());
23
0
}
24
25
LLVM_DUMP_METHOD void
26
0
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
0
  Out << OptionName << " (" << OptionType << ", "
30
0
      << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
31
0
      << DefaultValStr;
32
0
}
33
34
0
static StringRef toString(StateFromCmdLine Kind) {
35
0
  switch (Kind) {
36
0
  case StateFromCmdLine::State_Disabled:
37
0
    return "Disabled";
38
0
  case StateFromCmdLine::State_Enabled:
39
0
    return "Enabled";
40
0
  case StateFromCmdLine::State_Unspecified:
41
0
    return "Unspecified";
42
0
  }
43
0
  llvm_unreachable("Unhandled StateFromCmdLine enum");
44
0
}
45
46
0
LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); }
47
48
0
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
0
  Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
52
0
      << ")\n";
53
0
  Out << "  Options:\n";
54
0
  for (const CmdLineOption &Option : CmdLineOptions) {
55
0
    Out << "    ";
56
0
    Option.dumpToStream(Out);
57
0
    Out << '\n';
58
0
  }
59
0
  Out << "  Dependencies:\n";
60
0
  for (const CheckerInfo *Dependency : Dependencies) {
61
0
    Out << "  " << Dependency->FullName << '\n';
62
0
  }
63
0
  Out << "  Weak dependencies:\n";
64
0
  for (const CheckerInfo *Dependency : WeakDependencies) {
65
0
    Out << "    " << Dependency->FullName << '\n';
66
0
  }
67
0
}
68
69
0
LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); }
70
71
0
LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
72
0
  Out << FullName << "\n";
73
0
  Out << "  Options:\n";
74
0
  for (const CmdLineOption &Option : CmdLineOptions) {
75
0
    Out << "    ";
76
0
    Option.dumpToStream(Out);
77
0
    Out << '\n';
78
0
  }
79
0
}
80
81
static constexpr char PackageSeparator = '.';
82
83
3.60k
static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
84
  // Does the checker's full name have the package as a prefix?
85
3.60k
  if (!Checker.FullName.startswith(PackageName))
86
1
    return false;
87
88
  // Is the package actually just the name of a specific checker?
89
3.60k
  if (Checker.FullName.size() == PackageName.size())
90
1.86k
    return true;
91
92
  // Is the checker in the package (or a subpackage)?
93
1.73k
  if (Checker.FullName[PackageName.size()] == PackageSeparator)
94
1.73k
    return true;
95
96
0
  return false;
97
1.73k
}
98
99
CheckerInfoListRange
100
3.60k
CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
101
3.60k
  auto It = checker_registry::binaryFind(Checkers, CmdLineArg);
102
103
3.60k
  if (!isInPackage(*It, CmdLineArg))
104
1
    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
3.60k
  size_t Size = 1;
110
3.60k
  llvm::StringMap<size_t>::const_iterator PackageSize =
111
3.60k
      PackageSizes.find(CmdLineArg);
112
113
3.60k
  if (PackageSize != PackageSizes.end())
114
1.73k
    Size = PackageSize->getValue();
115
116
3.60k
  return {It, It + Size};
117
3.60k
}
118
//===----------------------------------------------------------------------===//
119
// Printing functions.
120
//===----------------------------------------------------------------------===//
121
122
void CheckerRegistryData::printCheckerWithDescList(
123
    const AnalyzerOptions &AnOpts, raw_ostream &Out,
124
9
    size_t MaxNameChars) const {
125
  // FIXME: Print available packages.
126
127
9
  Out << "CHECKERS:\n";
128
129
  // Find the maximum option length.
130
9
  size_t OptionFieldWidth = 0;
131
1.73k
  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
1.73k
    size_t NameLength = Checker.FullName.size();
135
1.73k
    if (NameLength <= MaxNameChars)
136
1.28k
      OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
137
1.73k
  }
138
139
9
  const size_t InitialPad = 2;
140
141
9
  auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
142
958
                   StringRef Description) {
143
958
    AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
144
958
                                         InitialPad, OptionFieldWidth);
145
958
    Out << '\n';
146
958
  };
147
148
1.73k
  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
1.73k
    if (Checker.IsHidden) {
156
441
      if (AnOpts.ShowCheckerHelpDeveloper)
157
196
        Print(Out, Checker, Checker.Desc);
158
441
      continue;
159
441
    }
160
161
1.29k
    if (Checker.FullName.startswith("alpha")) {
162
459
      if (AnOpts.ShowCheckerHelpAlpha)
163
204
        Print(Out, Checker,
164
204
              ("(Enable only for development!) " + Checker.Desc).str());
165
459
      continue;
166
459
    }
167
168
837
    if (AnOpts.ShowCheckerHelp)
169
558
      Print(Out, Checker, Checker.Desc);
170
837
  }
171
9
}
172
173
17
void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {
174
17
  for (const auto *i : EnabledCheckers)
175
130
    Out << i->FullName << '\n';
176
17
}
177
178
void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
179
7
                                                 raw_ostream &Out) const {
180
7
  Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
181
7
  Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
182
7
  Out << "       -analyzer-config OPTION1=VALUE, -analyzer-config "
183
7
         "OPTION2=VALUE, ...\n\n";
184
7
  Out << "OPTIONS:\n\n";
185
186
  // It's usually ill-advised to use multimap, but clang will terminate after
187
  // this function.
188
7
  std::multimap<StringRef, const CmdLineOption &> OptionMap;
189
190
1.35k
  for (const CheckerInfo &Checker : Checkers) {
191
1.35k
    for (const CmdLineOption &Option : Checker.CmdLineOptions) {
192
427
      OptionMap.insert({Checker.FullName, Option});
193
427
    }
194
1.35k
  }
195
196
350
  for (const PackageInfo &Package : Packages) {
197
350
    for (const CmdLineOption &Option : Package.CmdLineOptions) {
198
7
      OptionMap.insert({Package.FullName, Option});
199
7
    }
200
350
  }
201
202
7
  auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,
203
248
                  StringRef Desc) {
204
248
    AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
205
248
                                         /*InitialPad*/ 2,
206
248
                                         /*EntryWidth*/ 50,
207
248
                                         /*MinLineWidth*/ 90);
208
248
    Out << "\n\n";
209
248
  };
210
7
  for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
211
434
       OptionMap) {
212
434
    const CmdLineOption &Option = Entry.second;
213
434
    std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
214
215
434
    std::string Desc =
216
434
        ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
217
434
         (Option.DefaultValStr.empty() ? 
"\"\""7
:
Option.DefaultValStr427
) + ")")
218
434
            .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
434
    if (Option.IsHidden) {
225
196
      if (AnOpts.ShowCheckerOptionDeveloperList)
226
112
        Print(Out, FullOption, Desc);
227
196
      continue;
228
196
    }
229
230
238
    if (Option.DevelopmentStatus == "alpha" ||
231
238
        
Entry.first.startswith("alpha")161
) {
232
119
      if (AnOpts.ShowCheckerOptionAlphaList)
233
68
        Print(Out, FullOption,
234
68
              llvm::Twine("(Enable only for development!) " + Desc).str());
235
119
      continue;
236
119
    }
237
238
119
    if (AnOpts.ShowCheckerOptionList)
239
68
      Print(Out, FullOption, Desc);
240
119
  }
241
7
}