forked from OSchip/llvm-project
[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
This commit is contained in:
parent
dab31924e9
commit
e8df27d925
|
@ -143,6 +143,9 @@ def analyzer_list_enabled_checkers : Flag<["-"], "analyzer-list-enabled-checkers
|
|||
def analyzer_config : Separate<["-"], "analyzer-config">,
|
||||
HelpText<"Choose analyzer options to enable">;
|
||||
|
||||
def analyzer_checker_option_help : Flag<["-"], "analyzer-checker-option-help">,
|
||||
HelpText<"Display the list of checker and package options">;
|
||||
|
||||
def analyzer_config_compatibility_mode : Separate<["-"], "analyzer-config-compatibility-mode">,
|
||||
HelpText<"Don't emit errors on invalid analyzer-config inputs">;
|
||||
|
||||
|
|
|
@ -166,6 +166,29 @@ public:
|
|||
static std::vector<StringRef>
|
||||
getRegisteredCheckers(bool IncludeExperimental = false);
|
||||
|
||||
/// Convenience function for printing options or checkers and their
|
||||
/// description in a formatted manner. If \p MinLineWidth is set to 0, no line
|
||||
/// breaks are introduced for the description.
|
||||
///
|
||||
/// Format, depending whether the option name's length is less then
|
||||
/// \p OptionWidth:
|
||||
///
|
||||
/// <padding>EntryName<padding>Description
|
||||
/// <---------padding--------->Description
|
||||
/// <---------padding--------->Description
|
||||
///
|
||||
/// <padding>VeryVeryLongOptionName
|
||||
/// <---------padding--------->Description
|
||||
/// <---------padding--------->Description
|
||||
/// ^~~~~~~~ InitialPad
|
||||
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~ EntryWidth
|
||||
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MinLineWidth
|
||||
static void printFormattedEntry(
|
||||
llvm::raw_ostream &Out,
|
||||
std::pair<StringRef, StringRef> EntryDescPair,
|
||||
size_t EntryWidth, size_t InitialPad, size_t MinLineWidth = 0);
|
||||
|
||||
|
||||
/// Pair of checker name and enable/disable.
|
||||
std::vector<std::pair<std::string, bool>> CheckersControlList;
|
||||
|
||||
|
@ -199,6 +222,7 @@ public:
|
|||
unsigned ShowCheckerHelp : 1;
|
||||
unsigned ShowCheckerHelpHidden : 1;
|
||||
unsigned ShowEnabledCheckerList : 1;
|
||||
unsigned ShowCheckerOptionList : 1;
|
||||
unsigned ShowConfigOptionsList : 1;
|
||||
unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
|
||||
unsigned AnalyzeAll : 1;
|
||||
|
@ -262,11 +286,11 @@ public:
|
|||
AnalyzerOptions()
|
||||
: DisableAllChecks(false), ShowCheckerHelp(false),
|
||||
ShowCheckerHelpHidden(false), ShowEnabledCheckerList(false),
|
||||
ShowConfigOptionsList(false), AnalyzeAll(false),
|
||||
AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false),
|
||||
eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
|
||||
visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false),
|
||||
PrintStats(false), NoRetryExhausted(false) {
|
||||
ShowCheckerOptionList(false), ShowConfigOptionsList(false),
|
||||
AnalyzeAll(false), AnalyzerDisplayProgress(false),
|
||||
AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false),
|
||||
TrimGraph(false), visualizeExplodedGraphWithGraphViz(false),
|
||||
UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false) {
|
||||
llvm::sort(AnalyzerConfigCmdFlags);
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,7 @@ public:
|
|||
void printCheckerWithDescList(raw_ostream &Out,
|
||||
size_t MaxNameChars = 30) const;
|
||||
void printEnabledCheckerList(raw_ostream &Out) const;
|
||||
void printCheckerOptionList(raw_ostream &Out) const;
|
||||
|
||||
private:
|
||||
/// Collect all enabled checkers. The returned container preserves the order
|
||||
|
|
|
@ -61,6 +61,10 @@ void printEnabledCheckerList(raw_ostream &OS, ArrayRef<std::string> plugins,
|
|||
DiagnosticsEngine &diags,
|
||||
const LangOptions &LangOpts);
|
||||
void printAnalyzerConfigList(raw_ostream &OS);
|
||||
void printCheckerConfigList(raw_ostream &OS, ArrayRef<std::string> plugins,
|
||||
AnalyzerOptions &opts,
|
||||
DiagnosticsEngine &diags,
|
||||
const LangOptions &LangOpts);
|
||||
|
||||
} // end GR namespace
|
||||
|
||||
|
|
|
@ -286,6 +286,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
|
|||
|
||||
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
|
||||
Opts.ShowCheckerHelpHidden = Args.hasArg(OPT_analyzer_checker_help_hidden);
|
||||
Opts.ShowCheckerOptionList = Args.hasArg(OPT_analyzer_checker_option_help);
|
||||
Opts.ShowConfigOptionsList = Args.hasArg(OPT_analyzer_config_help);
|
||||
Opts.ShowEnabledCheckerList = Args.hasArg(OPT_analyzer_list_enabled_checkers);
|
||||
Opts.ShouldEmitErrorsOnInvalidConfigValue =
|
||||
|
|
|
@ -247,6 +247,16 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Honor -analyzer-checker-option-help.
|
||||
if (Clang->getAnalyzerOpts()->ShowCheckerOptionList) {
|
||||
ento::printCheckerConfigList(llvm::outs(),
|
||||
Clang->getFrontendOpts().Plugins,
|
||||
*Clang->getAnalyzerOpts(),
|
||||
Clang->getDiagnostics(),
|
||||
Clang->getLangOpts());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Honor -analyzer-list-enabled-checkers.
|
||||
if (AnOpts.ShowEnabledCheckerList) {
|
||||
ento::printEnabledCheckerList(llvm::outs(),
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
@ -48,6 +49,37 @@ AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
|
|||
return Result;
|
||||
}
|
||||
|
||||
void AnalyzerOptions::printFormattedEntry(
|
||||
llvm::raw_ostream &Out,
|
||||
std::pair<StringRef, StringRef> EntryDescPair,
|
||||
size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
|
||||
|
||||
llvm::formatted_raw_ostream FOut(Out);
|
||||
|
||||
const size_t PadForDesc = InitialPad + EntryWidth;
|
||||
|
||||
FOut.PadToColumn(InitialPad) << EntryDescPair.first;
|
||||
// If the buffer's length is greater then PadForDesc, print a newline.
|
||||
if (FOut.getColumn() > PadForDesc)
|
||||
FOut << '\n';
|
||||
|
||||
FOut.PadToColumn(PadForDesc);
|
||||
|
||||
if (MinLineWidth == 0) {
|
||||
FOut << EntryDescPair.second;
|
||||
return;
|
||||
}
|
||||
|
||||
for (char C : EntryDescPair.second) {
|
||||
if (FOut.getColumn() > MinLineWidth && C == ' ') {
|
||||
FOut << '\n';
|
||||
FOut.PadToColumn(PadForDesc);
|
||||
continue;
|
||||
}
|
||||
FOut << C;
|
||||
}
|
||||
}
|
||||
|
||||
ExplorationStrategyKind
|
||||
AnalyzerOptions::getExplorationStrategy() const {
|
||||
auto K =
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
|
||||
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <memory>
|
||||
|
||||
|
@ -65,17 +64,20 @@ void ento::printEnabledCheckerList(raw_ostream &out,
|
|||
.printEnabledCheckerList(out);
|
||||
}
|
||||
|
||||
void ento::printCheckerConfigList(raw_ostream &OS,
|
||||
ArrayRef<std::string> plugins,
|
||||
AnalyzerOptions &opts,
|
||||
DiagnosticsEngine &diags,
|
||||
const LangOptions &LangOpts) {
|
||||
CheckerRegistry(plugins, diags, opts, LangOpts)
|
||||
.printCheckerOptionList(OS);
|
||||
}
|
||||
|
||||
void ento::printAnalyzerConfigList(raw_ostream &out) {
|
||||
out << "OVERVIEW: Clang Static Analyzer -analyzer-config Option List\n\n";
|
||||
out << "USAGE: clang -cc1 [CLANG_OPTIONS] -analyzer-config "
|
||||
"<OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
|
||||
out << " clang -cc1 [CLANG_OPTIONS] -analyzer-config OPTION1=VALUE, "
|
||||
"-analyzer-config OPTION2=VALUE, ...\n\n";
|
||||
out << " clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang"
|
||||
"<OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
|
||||
out << " clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang "
|
||||
"OPTION1=VALUE, -Xclang -analyzer-config -Xclang "
|
||||
"OPTION2=VALUE, ...\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";
|
||||
|
||||
using OptionAndDescriptionTy = std::pair<StringRef, std::string>;
|
||||
|
@ -109,31 +111,10 @@ void ento::printAnalyzerConfigList(raw_ostream &out) {
|
|||
return LHS.first < RHS.first;
|
||||
});
|
||||
|
||||
constexpr size_t MinLineWidth = 70;
|
||||
constexpr size_t PadForOpt = 2;
|
||||
constexpr size_t OptionWidth = 30;
|
||||
constexpr size_t PadForDesc = PadForOpt + OptionWidth;
|
||||
static_assert(MinLineWidth > PadForDesc, "MinLineWidth must be greater!");
|
||||
|
||||
llvm::formatted_raw_ostream FOut(out);
|
||||
|
||||
for (const auto &Pair : PrintableOptions) {
|
||||
FOut.PadToColumn(PadForOpt) << Pair.first;
|
||||
|
||||
// If the buffer's length is greater then PadForDesc, print a newline.
|
||||
if (FOut.getColumn() > PadForDesc)
|
||||
FOut << '\n';
|
||||
|
||||
FOut.PadToColumn(PadForDesc);
|
||||
|
||||
for (char C : Pair.second) {
|
||||
if (FOut.getColumn() > MinLineWidth && C == ' ') {
|
||||
FOut << '\n';
|
||||
FOut.PadToColumn(PadForDesc);
|
||||
continue;
|
||||
}
|
||||
FOut << C;
|
||||
}
|
||||
FOut << "\n\n";
|
||||
AnalyzerOptions::printFormattedEntry(out, Pair, /*InitialPad*/ 2,
|
||||
/*EntryWidth*/ 30,
|
||||
/*MinLineWidth*/ 70);
|
||||
out << "\n\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -518,17 +518,8 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
|
|||
if (!AnOpts.ShowCheckerHelpHidden && Checker.IsHidden)
|
||||
continue;
|
||||
|
||||
Out.indent(InitialPad) << Checker.FullName;
|
||||
|
||||
int Pad = OptionFieldWidth - Checker.FullName.size();
|
||||
|
||||
// Break on long option names.
|
||||
if (Pad < 0) {
|
||||
Out << '\n';
|
||||
Pad = OptionFieldWidth + InitialPad;
|
||||
}
|
||||
Out.indent(Pad + 2) << Checker.Desc;
|
||||
|
||||
AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Checker.Desc},
|
||||
InitialPad, OptionFieldWidth);
|
||||
Out << '\n';
|
||||
}
|
||||
}
|
||||
|
@ -540,3 +531,41 @@ void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
|
|||
for (const auto *i : EnabledCheckers)
|
||||
Out << i->FullName << '\n';
|
||||
}
|
||||
|
||||
void CheckerRegistry::printCheckerOptionList(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";
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::pair<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();
|
||||
|
||||
AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
|
||||
/*InitialPad*/ 2,
|
||||
/*EntryWidth*/ 50,
|
||||
/*MinLineWidth*/ 90);
|
||||
Out << "\n\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// RUN: %clang_cc1 -analyzer-checker-option-help 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: OVERVIEW: Clang Static Analyzer Checker and Package Option List
|
||||
//
|
||||
// CHECK: USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
|
||||
//
|
||||
// CHECK: -analyzer-config OPTION1=VALUE, -analyzer-config
|
||||
// CHECK-SAME: OPTION2=VALUE, ...
|
||||
//
|
||||
// CHECK: OPTIONS:
|
||||
//
|
||||
// CHECK: alpha.clone.CloneChecker:MinimumCloneComplexity
|
||||
// CHECK-SAME: (int) Ensures that every clone has at least
|
||||
// CHECK: the given complexity. Complexity is here
|
||||
// CHECK: defined as the total amount of children
|
||||
// CHECK: of a statement. This constraint assumes
|
||||
// CHECK: the first statement in the group is representative
|
||||
// CHECK: for all other statements in the group in
|
||||
// CHECK: terms of complexity. (default: 50)
|
|
@ -1,14 +1,11 @@
|
|||
// RUN: %clang_cc1 -analyzer-config-help 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: OVERVIEW: Clang Static Analyzer -analyzer-config Option List
|
||||
//
|
||||
// CHECK: USAGE: clang -cc1 [CLANG_OPTIONS] -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
|
||||
//
|
||||
// CHECK: clang -cc1 [CLANG_OPTIONS] -analyzer-config OPTION1=VALUE, -analyzer-config OPTION2=VALUE, ...
|
||||
//
|
||||
// CHECK: clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang<OPTION1=VALUE,OPTION2=VALUE,...>
|
||||
//
|
||||
// CHECK: clang [CLANG_OPTIONS] -Xclang -analyzer-config -Xclang OPTION1=VALUE, -Xclang -analyzer-config -Xclang OPTION2=VALUE, ...
|
||||
// CHECK: USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
|
||||
//
|
||||
// CHECK: -analyzer-config OPTION1=VALUE, -analyzer-config
|
||||
// CHECK-SAME: OPTION2=VALUE, ...
|
||||
//
|
||||
// CHECK: OPTIONS:
|
||||
//
|
||||
|
|
|
@ -104,3 +104,12 @@ void caller() {
|
|||
// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-CORRECTED-BOOL-VALUE
|
||||
|
||||
// CHECK-CORRECTED-BOOL-VALUE: example.MyChecker:ExampleOption = false
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s \
|
||||
// RUN: -load %llvmshlibdir/CheckerOptionHandlingAnalyzerPlugin%pluginext\
|
||||
// RUN: -analyzer-checker=example.MyChecker \
|
||||
// RUN: -analyzer-checker-option-help \
|
||||
// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-CHECKER-OPTION-HELP
|
||||
|
||||
// CHECK-CHECKER-OPTION-HELP: example.MyChecker:ExampleOption (bool) This is an
|
||||
// CHECK-CHECKER-OPTION-HELP-SAME: example checker opt. (default: false)
|
||||
|
|
Loading…
Reference in New Issue