Skip to content

Commit e8df27d

Browse files
author
Kristof Umann
committed
[analyzer] Add a new frontend flag to display all checker options
Add the new frontend flag -analyzer-checker-option-help to display all checker/package options. Differential Revision: https://reviews.llvm.org/D57858 llvm-svn: 361552
1 parent dab3192 commit e8df27d

12 files changed

+168
-58
lines changed

clang/include/clang/Driver/CC1Options.td

+3
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ def analyzer_list_enabled_checkers : Flag<["-"], "analyzer-list-enabled-checkers
143143
def analyzer_config : Separate<["-"], "analyzer-config">,
144144
HelpText<"Choose analyzer options to enable">;
145145

146+
def analyzer_checker_option_help : Flag<["-"], "analyzer-checker-option-help">,
147+
HelpText<"Display the list of checker and package options">;
148+
146149
def analyzer_config_compatibility_mode : Separate<["-"], "analyzer-config-compatibility-mode">,
147150
HelpText<"Don't emit errors on invalid analyzer-config inputs">;
148151

clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h

+29-5
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
166166
static std::vector<StringRef>
167167
getRegisteredCheckers(bool IncludeExperimental = false);
168168

169+
/// Convenience function for printing options or checkers and their
170+
/// description in a formatted manner. If \p MinLineWidth is set to 0, no line
171+
/// breaks are introduced for the description.
172+
///
173+
/// Format, depending whether the option name's length is less then
174+
/// \p OptionWidth:
175+
///
176+
/// <padding>EntryName<padding>Description
177+
/// <---------padding--------->Description
178+
/// <---------padding--------->Description
179+
///
180+
/// <padding>VeryVeryLongOptionName
181+
/// <---------padding--------->Description
182+
/// <---------padding--------->Description
183+
/// ^~~~~~~~ InitialPad
184+
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~ EntryWidth
185+
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MinLineWidth
186+
static void printFormattedEntry(
187+
llvm::raw_ostream &Out,
188+
std::pair<StringRef, StringRef> EntryDescPair,
189+
size_t EntryWidth, size_t InitialPad, size_t MinLineWidth = 0);
190+
191+
169192
/// Pair of checker name and enable/disable.
170193
std::vector<std::pair<std::string, bool>> CheckersControlList;
171194

@@ -199,6 +222,7 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
199222
unsigned ShowCheckerHelp : 1;
200223
unsigned ShowCheckerHelpHidden : 1;
201224
unsigned ShowEnabledCheckerList : 1;
225+
unsigned ShowCheckerOptionList : 1;
202226
unsigned ShowConfigOptionsList : 1;
203227
unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
204228
unsigned AnalyzeAll : 1;
@@ -262,11 +286,11 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
262286
AnalyzerOptions()
263287
: DisableAllChecks(false), ShowCheckerHelp(false),
264288
ShowCheckerHelpHidden(false), ShowEnabledCheckerList(false),
265-
ShowConfigOptionsList(false), AnalyzeAll(false),
266-
AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false),
267-
eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
268-
visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false),
269-
PrintStats(false), NoRetryExhausted(false) {
289+
ShowCheckerOptionList(false), ShowConfigOptionsList(false),
290+
AnalyzeAll(false), AnalyzerDisplayProgress(false),
291+
AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false),
292+
TrimGraph(false), visualizeExplodedGraphWithGraphViz(false),
293+
UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false) {
270294
llvm::sort(AnalyzerConfigCmdFlags);
271295
}
272296

clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h

+1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ class CheckerRegistry {
272272
void printCheckerWithDescList(raw_ostream &Out,
273273
size_t MaxNameChars = 30) const;
274274
void printEnabledCheckerList(raw_ostream &Out) const;
275+
void printCheckerOptionList(raw_ostream &Out) const;
275276

276277
private:
277278
/// Collect all enabled checkers. The returned container preserves the order

clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ void printEnabledCheckerList(raw_ostream &OS, ArrayRef<std::string> plugins,
6161
DiagnosticsEngine &diags,
6262
const LangOptions &LangOpts);
6363
void printAnalyzerConfigList(raw_ostream &OS);
64+
void printCheckerConfigList(raw_ostream &OS, ArrayRef<std::string> plugins,
65+
AnalyzerOptions &opts,
66+
DiagnosticsEngine &diags,
67+
const LangOptions &LangOpts);
6468

6569
} // end GR namespace
6670

clang/lib/Frontend/CompilerInvocation.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
286286

287287
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
288288
Opts.ShowCheckerHelpHidden = Args.hasArg(OPT_analyzer_checker_help_hidden);
289+
Opts.ShowCheckerOptionList = Args.hasArg(OPT_analyzer_checker_option_help);
289290
Opts.ShowConfigOptionsList = Args.hasArg(OPT_analyzer_config_help);
290291
Opts.ShowEnabledCheckerList = Args.hasArg(OPT_analyzer_list_enabled_checkers);
291292
Opts.ShouldEmitErrorsOnInvalidConfigValue =

clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,16 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
247247
return true;
248248
}
249249

250+
// Honor -analyzer-checker-option-help.
251+
if (Clang->getAnalyzerOpts()->ShowCheckerOptionList) {
252+
ento::printCheckerConfigList(llvm::outs(),
253+
Clang->getFrontendOpts().Plugins,
254+
*Clang->getAnalyzerOpts(),
255+
Clang->getDiagnostics(),
256+
Clang->getLangOpts());
257+
return true;
258+
}
259+
250260
// Honor -analyzer-list-enabled-checkers.
251261
if (AnOpts.ShowEnabledCheckerList) {
252262
ento::printEnabledCheckerList(llvm::outs(),

clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/Twine.h"
2020
#include "llvm/Support/ErrorHandling.h"
2121
#include "llvm/Support/FileSystem.h"
22+
#include "llvm/Support/FormattedStream.h"
2223
#include "llvm/Support/raw_ostream.h"
2324
#include <cassert>
2425
#include <cstddef>
@@ -48,6 +49,37 @@ AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
4849
return Result;
4950
}
5051

52+
void AnalyzerOptions::printFormattedEntry(
53+
llvm::raw_ostream &Out,
54+
std::pair<StringRef, StringRef> EntryDescPair,
55+
size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
56+
57+
llvm::formatted_raw_ostream FOut(Out);
58+
59+
const size_t PadForDesc = InitialPad + EntryWidth;
60+
61+
FOut.PadToColumn(InitialPad) << EntryDescPair.first;
62+
// If the buffer's length is greater then PadForDesc, print a newline.
63+
if (FOut.getColumn() > PadForDesc)
64+
FOut << '\n';
65+
66+
FOut.PadToColumn(PadForDesc);
67+
68+
if (MinLineWidth == 0) {
69+
FOut << EntryDescPair.second;
70+
return;
71+
}
72+
73+
for (char C : EntryDescPair.second) {
74+
if (FOut.getColumn() > MinLineWidth && C == ' ') {
75+
FOut << '\n';
76+
FOut.PadToColumn(PadForDesc);
77+
continue;
78+
}
79+
FOut << C;
80+
}
81+
}
82+
5183
ExplorationStrategyKind
5284
AnalyzerOptions::getExplorationStrategy() const {
5385
auto K =

clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp

+16-35
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
1919
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
2020
#include "llvm/ADT/SmallVector.h"
21-
#include "llvm/Support/FormattedStream.h"
2221
#include "llvm/Support/raw_ostream.h"
2322
#include <memory>
2423

@@ -65,17 +64,20 @@ void ento::printEnabledCheckerList(raw_ostream &out,
6564
.printEnabledCheckerList(out);
6665
}
6766

67+
void ento::printCheckerConfigList(raw_ostream &OS,
68+
ArrayRef<std::string> plugins,
69+
AnalyzerOptions &opts,
70+
DiagnosticsEngine &diags,
71+
const LangOptions &LangOpts) {
72+
CheckerRegistry(plugins, diags, opts, LangOpts)
73+
.printCheckerOptionList(OS);
74+
}
75+
6876
void ento::printAnalyzerConfigList(raw_ostream &out) {
6977
out << "OVERVIEW: Clang Static Analyzer -analyzer-config Option List\n\n";
70-
out << "USAGE: clang -cc1 [CLANG_OPTIONS] -analyzer-config "
71-
"<OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
72-
out << " clang -cc1 [CLANG_OPTIONS] -analyzer-config OPTION1=VALUE, "
73-
"-analyzer-config OPTION2=VALUE, ...\n\n";
74-
out << " clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang"
75-
"<OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
76-
out << " clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang "
77-
"OPTION1=VALUE, -Xclang -analyzer-config -Xclang "
78-
"OPTION2=VALUE, ...\n\n";
78+
out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
79+
out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
80+
"OPTION2=VALUE, ...\n\n";
7981
out << "OPTIONS:\n\n";
8082

8183
using OptionAndDescriptionTy = std::pair<StringRef, std::string>;
@@ -109,31 +111,10 @@ void ento::printAnalyzerConfigList(raw_ostream &out) {
109111
return LHS.first < RHS.first;
110112
});
111113

112-
constexpr size_t MinLineWidth = 70;
113-
constexpr size_t PadForOpt = 2;
114-
constexpr size_t OptionWidth = 30;
115-
constexpr size_t PadForDesc = PadForOpt + OptionWidth;
116-
static_assert(MinLineWidth > PadForDesc, "MinLineWidth must be greater!");
117-
118-
llvm::formatted_raw_ostream FOut(out);
119-
120114
for (const auto &Pair : PrintableOptions) {
121-
FOut.PadToColumn(PadForOpt) << Pair.first;
122-
123-
// If the buffer's length is greater then PadForDesc, print a newline.
124-
if (FOut.getColumn() > PadForDesc)
125-
FOut << '\n';
126-
127-
FOut.PadToColumn(PadForDesc);
128-
129-
for (char C : Pair.second) {
130-
if (FOut.getColumn() > MinLineWidth && C == ' ') {
131-
FOut << '\n';
132-
FOut.PadToColumn(PadForDesc);
133-
continue;
134-
}
135-
FOut << C;
136-
}
137-
FOut << "\n\n";
115+
AnalyzerOptions::printFormattedEntry(out, Pair, /*InitialPad*/ 2,
116+
/*EntryWidth*/ 30,
117+
/*MinLineWidth*/ 70);
118+
out << "\n\n";
138119
}
139120
}

clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp

+40-11
Original file line numberDiff line numberDiff line change
@@ -518,17 +518,8 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
518518
if (!AnOpts.ShowCheckerHelpHidden && Checker.IsHidden)
519519
continue;
520520

521-
Out.indent(InitialPad) << Checker.FullName;
522-
523-
int Pad = OptionFieldWidth - Checker.FullName.size();
524-
525-
// Break on long option names.
526-
if (Pad < 0) {
527-
Out << '\n';
528-
Pad = OptionFieldWidth + InitialPad;
529-
}
530-
Out.indent(Pad + 2) << Checker.Desc;
531-
521+
AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Checker.Desc},
522+
InitialPad, OptionFieldWidth);
532523
Out << '\n';
533524
}
534525
}
@@ -540,3 +531,41 @@ void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
540531
for (const auto *i : EnabledCheckers)
541532
Out << i->FullName << '\n';
542533
}
534+
535+
void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const {
536+
Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
537+
Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
538+
Out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
539+
"OPTION2=VALUE, ...\n\n";
540+
Out << "OPTIONS:\n\n";
541+
542+
std::multimap<StringRef, const CmdLineOption &> OptionMap;
543+
544+
for (const CheckerInfo &Checker : Checkers) {
545+
for (const CmdLineOption &Option : Checker.CmdLineOptions) {
546+
OptionMap.insert({Checker.FullName, Option});
547+
}
548+
}
549+
550+
for (const PackageInfo &Package : Packages) {
551+
for (const CmdLineOption &Option : Package.CmdLineOptions) {
552+
OptionMap.insert({Package.FullName, Option});
553+
}
554+
}
555+
556+
for (const std::pair<StringRef, const CmdLineOption &> &Entry : OptionMap) {
557+
const CmdLineOption &Option = Entry.second;
558+
std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
559+
560+
std::string Desc =
561+
("(" + Option.OptionType + ") " + Option.Description + " (default: " +
562+
(Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
563+
.str();
564+
565+
AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
566+
/*InitialPad*/ 2,
567+
/*EntryWidth*/ 50,
568+
/*MinLineWidth*/ 90);
569+
Out << "\n\n";
570+
}
571+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -analyzer-checker-option-help 2>&1 | FileCheck %s
2+
3+
// CHECK: OVERVIEW: Clang Static Analyzer Checker and Package Option List
4+
//
5+
// CHECK: USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
6+
//
7+
// CHECK: -analyzer-config OPTION1=VALUE, -analyzer-config
8+
// CHECK-SAME: OPTION2=VALUE, ...
9+
//
10+
// CHECK: OPTIONS:
11+
//
12+
// CHECK: alpha.clone.CloneChecker:MinimumCloneComplexity
13+
// CHECK-SAME: (int) Ensures that every clone has at least
14+
// CHECK: the given complexity. Complexity is here
15+
// CHECK: defined as the total amount of children
16+
// CHECK: of a statement. This constraint assumes
17+
// CHECK: the first statement in the group is representative
18+
// CHECK: for all other statements in the group in
19+
// CHECK: terms of complexity. (default: 50)

clang/test/Analysis/analyzer-list-configs.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
// RUN: %clang_cc1 -analyzer-config-help 2>&1 | FileCheck %s
2+
23
// CHECK: OVERVIEW: Clang Static Analyzer -analyzer-config Option List
34
//
4-
// CHECK: USAGE: clang -cc1 [CLANG_OPTIONS] -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
5-
//
6-
// CHECK: clang -cc1 [CLANG_OPTIONS] -analyzer-config OPTION1=VALUE, -analyzer-config OPTION2=VALUE, ...
7-
//
8-
// CHECK: clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang<OPTION1=VALUE,OPTION2=VALUE,...>
9-
//
10-
// CHECK: clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang OPTION1=VALUE, -Xclang -analyzer-config -Xclang OPTION2=VALUE, ...
5+
// CHECK: USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
116
//
7+
// CHECK: -analyzer-config OPTION1=VALUE, -analyzer-config
8+
// CHECK-SAME: OPTION2=VALUE, ...
129
//
1310
// CHECK: OPTIONS:
1411
//

clang/test/Analysis/checker-plugins.c

+9
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,12 @@ void caller() {
104104
// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-CORRECTED-BOOL-VALUE
105105

106106
// CHECK-CORRECTED-BOOL-VALUE: example.MyChecker:ExampleOption = false
107+
108+
// RUN: %clang_analyze_cc1 %s \
109+
// RUN: -load %llvmshlibdir/CheckerOptionHandlingAnalyzerPlugin%pluginext\
110+
// RUN: -analyzer-checker=example.MyChecker \
111+
// RUN: -analyzer-checker-option-help \
112+
// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-CHECKER-OPTION-HELP
113+
114+
// CHECK-CHECKER-OPTION-HELP: example.MyChecker:ExampleOption (bool) This is an
115+
// CHECK-CHECKER-OPTION-HELP-SAME: example checker opt. (default: false)

0 commit comments

Comments
 (0)