blob: 7514eee7244f8457b927194dfd5a6fb78b351765 [file] [log] [blame]
//===- AnalyzerOptions.h - Analysis Engine Options --------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This header defines various options for the static analyzer that are set
// by the frontend and are consulted throughout the analyzer.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
#define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include <string>
#include <utility>
#include <vector>
namespace clang {
namespace ento {
class CheckerBase;
} // namespace ento
/// Analysis - Set of available source code analyses.
enum Analyses {
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
#include "clang/StaticAnalyzer/Core/Analyses.def"
NumAnalyses
};
/// AnalysisStores - Set of available analysis store models.
enum AnalysisStores {
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
#include "clang/StaticAnalyzer/Core/Analyses.def"
NumStores
};
/// AnalysisConstraints - Set of available constraint models.
enum AnalysisConstraints {
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
#include "clang/StaticAnalyzer/Core/Analyses.def"
NumConstraints
};
/// AnalysisDiagClients - Set of available diagnostic clients for rendering
/// analysis results.
enum AnalysisDiagClients {
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) PD_##NAME,
#include "clang/StaticAnalyzer/Core/Analyses.def"
PD_NONE,
NUM_ANALYSIS_DIAG_CLIENTS
};
/// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
enum AnalysisPurgeMode {
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
#include "clang/StaticAnalyzer/Core/Analyses.def"
NumPurgeModes
};
/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
enum AnalysisInliningMode {
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
#include "clang/StaticAnalyzer/Core/Analyses.def"
NumInliningModes
};
/// Describes the different kinds of C++ member functions which can be
/// considered for inlining by the analyzer.
///
/// These options are cumulative; enabling one kind of member function will
/// enable all kinds with lower enum values.
enum CXXInlineableMemberKind {
// Uninitialized = 0,
/// A dummy mode in which no C++ inlining is enabled.
CIMK_None,
/// Refers to regular member function and operator calls.
CIMK_MemberFunctions,
/// Refers to constructors (implicit or explicit).
///
/// Note that a constructor will not be inlined if the corresponding
/// destructor is non-trivial.
CIMK_Constructors,
/// Refers to destructors (implicit or explicit).
CIMK_Destructors
};
/// Describes the different modes of inter-procedural analysis.
enum IPAKind {
/// Perform only intra-procedural analysis.
IPAK_None = 1,
/// Inline C functions and blocks when their definitions are available.
IPAK_BasicInlining = 2,
/// Inline callees(C, C++, ObjC) when their definitions are available.
IPAK_Inlining = 3,
/// Enable inlining of dynamically dispatched methods.
IPAK_DynamicDispatch = 4,
/// Enable inlining of dynamically dispatched methods, bifurcate paths when
/// exact type info is unavailable.
IPAK_DynamicDispatchBifurcate = 5
};
enum class ExplorationStrategyKind {
DFS,
BFS,
UnexploredFirst,
UnexploredFirstQueue,
UnexploredFirstLocationQueue,
BFSBlockDFSContents,
};
/// Describes the kinds for high-level analyzer mode.
enum UserModeKind {
/// Perform shallow but fast analyzes.
UMK_Shallow = 1,
/// Perform deep analyzes.
UMK_Deep = 2
};
/// Stores options for the analyzer from the command line.
///
/// Some options are frontend flags (e.g.: -analyzer-output), but some are
/// analyzer configuration options, which are preceded by -analyzer-config
/// (e.g.: -analyzer-config notes-as-events=true).
///
/// If you'd like to add a new frontend flag, add it to
/// include/clang/Driver/CC1Options.td, add a new field to store the value of
/// that flag in this class, and initialize it in
/// lib/Frontend/CompilerInvocation.cpp.
///
/// If you'd like to add a new non-checker configuration, register it in
/// include/clang/StaticAnalyzer/Core/AnalyzerOptions.def, and refer to the
/// top of the file for documentation.
///
/// If you'd like to add a new checker option, call getChecker*Option()
/// whenever.
///
/// Some of the options are controlled by raw frontend flags for no good reason,
/// and should be eventually converted into -analyzer-config flags. New analyzer
/// options should not be implemented as frontend flags. Frontend flags still
/// make sense for things that do not affect the actual analysis.
class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
public:
using ConfigTable = llvm::StringMap<std::string>;
/// Retrieves the list of checkers generated from Checkers.td. This doesn't
/// contain statically linked but non-generated checkers and plugin checkers!
static std::vector<StringRef>
getRegisteredCheckers(bool IncludeExperimental = false);
/// Retrieves the list of packages generated from Checkers.td. This doesn't
/// contain statically linked but non-generated packages and plugin packages!
static std::vector<StringRef>
getRegisteredPackages(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 than
/// \p EntryWidth:
///
/// <padding>EntryName<padding>Description
/// <---------padding--------->Description
/// <---------padding--------->Description
///
/// <padding>VeryVeryLongEntryName
/// <---------padding--------->Description
/// <---------padding--------->Description
/// ^~~~~~~~~InitialPad
/// ^~~~~~~~~~~~~~~~~~EntryWidth
/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MinLineWidth
static void printFormattedEntry(llvm::raw_ostream &Out,
std::pair<StringRef, StringRef> EntryDescPair,
size_t InitialPad, size_t EntryWidth,
size_t MinLineWidth = 0);
/// Pairs of checker/package name and enable/disable.
std::vector<std::pair<std::string, bool>> CheckersAndPackages;
/// Vector of checker/package names which will not emit warnings.
std::vector<std::string> SilencedCheckersAndPackages;
/// A key-value table of use-specified configuration values.
// TODO: This shouldn't be public.
ConfigTable Config;
AnalysisStores AnalysisStoreOpt = RegionStoreModel;
AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel;
AnalysisDiagClients AnalysisDiagOpt = PD_HTML;
AnalysisPurgeMode AnalysisPurgeOpt = PurgeStmt;
std::string AnalyzeSpecificFunction;
/// File path to which the exploded graph should be dumped.
std::string DumpExplodedGraphTo;
/// Store full compiler invocation for reproducible instructions in the
/// generated report.
std::string FullCompilerInvocation;
/// The maximum number of times the analyzer visits a block.
unsigned maxBlockVisitOnPath;
/// Disable all analyzer checkers.
///
/// This flag allows one to disable analyzer checkers on the code processed by
/// the given analysis consumer. Note, the code will get parsed and the
/// command-line options will get checked.
unsigned DisableAllCheckers : 1;
unsigned ShowCheckerHelp : 1;
unsigned ShowCheckerHelpAlpha : 1;
unsigned ShowCheckerHelpDeveloper : 1;
unsigned ShowCheckerOptionList : 1;
unsigned ShowCheckerOptionAlphaList : 1;
unsigned ShowCheckerOptionDeveloperList : 1;
unsigned ShowEnabledCheckerList : 1;
unsigned ShowConfigOptionsList : 1;
unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
unsigned AnalyzeAll : 1;
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
unsigned eagerlyAssumeBinOpBifurcation : 1;
unsigned TrimGraph : 1;
unsigned visualizeExplodedGraphWithGraphViz : 1;
unsigned UnoptimizedCFG : 1;
unsigned PrintStats : 1;
/// Do not re-analyze paths leading to exhausted nodes with a different
/// strategy. We get better code coverage when retry is enabled.
unsigned NoRetryExhausted : 1;
/// Emit analyzer warnings as errors.
bool AnalyzerWerror : 1;
/// The inlining stack depth limit.
unsigned InlineMaxStackDepth;
/// The mode of function selection used during inlining.
AnalysisInliningMode InliningMode = NoRedundancy;
// Create a field for each -analyzer-config option.
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
SHALLOW_VAL, DEEP_VAL) \
ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
TYPE NAME;
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
#undef ANALYZER_OPTION
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
// Create an array of all -analyzer-config command line options. Sort it in
// the constructor.
std::vector<llvm::StringLiteral> AnalyzerConfigCmdFlags = {
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
SHALLOW_VAL, DEEP_VAL) \
ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
llvm::StringLiteral(CMDFLAG),
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
#undef ANALYZER_OPTION
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
};
bool isUnknownAnalyzerConfig(StringRef Name) const {
assert(llvm::is_sorted(AnalyzerConfigCmdFlags));
return !std::binary_search(AnalyzerConfigCmdFlags.begin(),
AnalyzerConfigCmdFlags.end(), Name);
}
AnalyzerOptions()
: DisableAllCheckers(false), ShowCheckerHelp(false),
ShowCheckerHelpAlpha(false), ShowCheckerHelpDeveloper(false),
ShowCheckerOptionList(false), ShowCheckerOptionAlphaList(false),
ShowCheckerOptionDeveloperList(false), ShowEnabledCheckerList(false),
ShowConfigOptionsList(false), AnalyzeAll(false),
AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false),
eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false),
PrintStats(false), NoRetryExhausted(false), AnalyzerWerror(false) {
llvm::sort(AnalyzerConfigCmdFlags);
}
/// Interprets an option's string value as a boolean. The "true" string is
/// interpreted as true and the "false" string is interpreted as false.
///
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] CheckerName The *full name* of the checker. One may retrieve
/// this from the checker object's field \c Name, or through \c
/// CheckerManager::getCurrentCheckerName within the checker's registry
/// function.
/// Checker options are retrieved in the following format:
/// `-analyzer-config CheckerName:OptionName=Value.
/// @param [in] OptionName Name for option to retrieve.
/// @param [in] SearchInParents If set to true and the searched option was not
/// specified for the given checker the options for the parent packages will
/// be searched as well. The inner packages take precedence over the outer
/// ones.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName,
bool SearchInParents = false) const;
bool getCheckerBooleanOption(const ento::CheckerBase *C, StringRef OptionName,
bool SearchInParents = false) const;
/// Interprets an option's string value as an integer value.
///
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] CheckerName The *full name* of the checker. One may retrieve
/// this from the checker object's field \c Name, or through \c
/// CheckerManager::getCurrentCheckerName within the checker's registry
/// function.
/// Checker options are retrieved in the following format:
/// `-analyzer-config CheckerName:OptionName=Value.
/// @param [in] OptionName Name for option to retrieve.
/// @param [in] SearchInParents If set to true and the searched option was not
/// specified for the given checker the options for the parent packages will
/// be searched as well. The inner packages take precedence over the outer
/// ones.
int getCheckerIntegerOption(StringRef CheckerName, StringRef OptionName,
bool SearchInParents = false) const;
int getCheckerIntegerOption(const ento::CheckerBase *C, StringRef OptionName,
bool SearchInParents = false) const;
/// Query an option's string value.
///
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] CheckerName The *full name* of the checker. One may retrieve
/// this from the checker object's field \c Name, or through \c
/// CheckerManager::getCurrentCheckerName within the checker's registry
/// function.
/// Checker options are retrieved in the following format:
/// `-analyzer-config CheckerName:OptionName=Value.
/// @param [in] OptionName Name for option to retrieve.
/// @param [in] SearchInParents If set to true and the searched option was not
/// specified for the given checker the options for the parent packages will
/// be searched as well. The inner packages take precedence over the outer
/// ones.
StringRef getCheckerStringOption(StringRef CheckerName, StringRef OptionName,
bool SearchInParents = false) const;
StringRef getCheckerStringOption(const ento::CheckerBase *C,
StringRef OptionName,
bool SearchInParents = false) const;
/// Retrieves and sets the UserMode. This is a high-level option,
/// which is used to set other low-level options. It is not accessible
/// outside of AnalyzerOptions.
UserModeKind getUserMode() const;
ExplorationStrategyKind getExplorationStrategy() const;
/// Returns the inter-procedural analysis mode.
IPAKind getIPAMode() const;
/// Returns the option controlling which C++ member functions will be
/// considered for inlining.
///
/// This is controlled by the 'c++-inlining' config option.
///
/// \sa CXXMemberInliningMode
bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const;
ento::PathDiagnosticConsumerOptions getDiagOpts() const {
return {FullCompilerInvocation,
ShouldDisplayMacroExpansions,
ShouldSerializeStats,
// The stable report filename option is deprecated because
// file names are now always stable. Now the old option acts as
// an alias to the new verbose filename option because this
// closely mimics the behavior under the old option.
ShouldWriteStableReportFilename || ShouldWriteVerboseReportFilename,
AnalyzerWerror,
ShouldApplyFixIts,
ShouldDisplayCheckerNameForText};
}
};
using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;
//===----------------------------------------------------------------------===//
// We'll use AnalyzerOptions in the frontend, but we can't link the frontend
// with clangStaticAnalyzerCore, because clangStaticAnalyzerCore depends on
// clangFrontend.
//
// For this reason, implement some methods in this header file.
//===----------------------------------------------------------------------===//
inline UserModeKind AnalyzerOptions::getUserMode() const {
auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(UserMode)
.Case("shallow", UMK_Shallow)
.Case("deep", UMK_Deep)
.Default(None);
assert(K.hasValue() && "User mode is invalid.");
return K.getValue();
}
inline std::vector<StringRef>
AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental) {
static constexpr llvm::StringLiteral StaticAnalyzerCheckerNames[] = {
#define GET_CHECKERS
#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
llvm::StringLiteral(FULLNAME),
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
#undef CHECKER
#undef GET_CHECKERS
};
std::vector<StringRef> Checkers;
for (StringRef CheckerName : StaticAnalyzerCheckerNames) {
if (!CheckerName.startswith("debug.") &&
(IncludeExperimental || !CheckerName.startswith("alpha.")))
Checkers.push_back(CheckerName);
}
return Checkers;
}
inline std::vector<StringRef>
AnalyzerOptions::getRegisteredPackages(bool IncludeExperimental) {
static constexpr llvm::StringLiteral StaticAnalyzerPackageNames[] = {
#define GET_PACKAGES
#define PACKAGE(FULLNAME) llvm::StringLiteral(FULLNAME),
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
#undef PACKAGE
#undef GET_PACKAGES
};
std::vector<StringRef> Packages;
for (StringRef PackageName : StaticAnalyzerPackageNames) {
if (PackageName != "debug" &&
(IncludeExperimental || PackageName != "alpha"))
Packages.push_back(PackageName);
}
return Packages;
}
} // namespace clang
#endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H