clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
708 lines
26 KiB
C++
708 lines
26 KiB
C++
//===- CheckerManager.h - Static Analyzer Checker Manager -------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Defines the Static Analyzer Checker Manager.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
|
|
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
|
|
|
|
#include "clang/Analysis/ProgramPoint.h"
|
|
#include "clang/Basic/Diagnostic.h"
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <vector>
|
|
|
|
namespace clang {
|
|
|
|
class AnalyzerOptions;
|
|
class CallExpr;
|
|
class Decl;
|
|
class LocationContext;
|
|
class Stmt;
|
|
class TranslationUnitDecl;
|
|
|
|
namespace ento {
|
|
|
|
class AnalysisManager;
|
|
class CXXAllocatorCall;
|
|
class BugReporter;
|
|
class CallEvent;
|
|
class CheckerBase;
|
|
class CheckerContext;
|
|
class CheckerRegistry;
|
|
struct CheckerRegistryData;
|
|
class ExplodedGraph;
|
|
class ExplodedNode;
|
|
class ExplodedNodeSet;
|
|
class ExprEngine;
|
|
struct EvalCallOptions;
|
|
class MemRegion;
|
|
class NodeBuilderContext;
|
|
class ObjCMethodCall;
|
|
class RegionAndSymbolInvalidationTraits;
|
|
class SVal;
|
|
class SymbolReaper;
|
|
|
|
template <typename T> class CheckerFn;
|
|
|
|
template <typename RET, typename... Ps>
|
|
class CheckerFn<RET(Ps...)> {
|
|
using Func = RET (*)(void *, Ps...);
|
|
|
|
Func Fn;
|
|
|
|
public:
|
|
CheckerBase *Checker;
|
|
|
|
CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) {}
|
|
|
|
RET operator()(Ps... ps) const {
|
|
return Fn(Checker, ps...);
|
|
}
|
|
};
|
|
|
|
/// Describes the different reasons a pointer escapes
|
|
/// during analysis.
|
|
enum PointerEscapeKind {
|
|
/// A pointer escapes due to binding its value to a location
|
|
/// that the analyzer cannot track.
|
|
PSK_EscapeOnBind,
|
|
|
|
/// The pointer has been passed to a function call directly.
|
|
PSK_DirectEscapeOnCall,
|
|
|
|
/// The pointer has been passed to a function indirectly.
|
|
/// For example, the pointer is accessible through an
|
|
/// argument to a function.
|
|
PSK_IndirectEscapeOnCall,
|
|
|
|
|
|
/// Escape for a new symbol that was generated into a region
|
|
/// that the analyzer cannot follow during a conservative call.
|
|
PSK_EscapeOutParameters,
|
|
|
|
/// The reason for pointer escape is unknown. For example,
|
|
/// a region containing this pointer is invalidated.
|
|
PSK_EscapeOther
|
|
};
|
|
|
|
/// This wrapper is used to ensure that only StringRefs originating from the
|
|
/// CheckerRegistry are used as check names. We want to make sure all checker
|
|
/// name strings have a lifetime that keeps them alive at least until the path
|
|
/// diagnostics have been processed, since they are expected to be constexpr
|
|
/// string literals (most likely generated by TblGen).
|
|
class CheckerNameRef {
|
|
friend class ::clang::ento::CheckerRegistry;
|
|
|
|
StringRef Name;
|
|
|
|
explicit CheckerNameRef(StringRef Name) : Name(Name) {}
|
|
|
|
public:
|
|
CheckerNameRef() = default;
|
|
|
|
StringRef getName() const { return Name; }
|
|
operator StringRef() const { return Name; }
|
|
};
|
|
|
|
enum class ObjCMessageVisitKind {
|
|
Pre,
|
|
Post,
|
|
MessageNil
|
|
};
|
|
|
|
class CheckerManager {
|
|
ASTContext *Context = nullptr;
|
|
const LangOptions LangOpts;
|
|
const AnalyzerOptions &AOptions;
|
|
const Preprocessor *PP = nullptr;
|
|
CheckerNameRef CurrentCheckerName;
|
|
DiagnosticsEngine &Diags;
|
|
std::unique_ptr<CheckerRegistryData> RegistryData;
|
|
|
|
public:
|
|
// These constructors are defined in the Frontend library, because
|
|
// CheckerRegistry, a crucial component of the initialization is in there.
|
|
// CheckerRegistry cannot be moved to the Core library, because the checker
|
|
// registration functions are defined in the Checkers library, and the library
|
|
// dependencies look like this: Core -> Checkers -> Frontend.
|
|
|
|
CheckerManager(
|
|
ASTContext &Context, AnalyzerOptions &AOptions, const Preprocessor &PP,
|
|
ArrayRef<std::string> plugins,
|
|
ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns);
|
|
|
|
/// Constructs a CheckerManager that ignores all non TblGen-generated
|
|
/// checkers. Useful for unit testing, unless the checker infrastructure
|
|
/// itself is tested.
|
|
CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions,
|
|
const Preprocessor &PP)
|
|
: CheckerManager(Context, AOptions, PP, {}, {}) {}
|
|
|
|
/// Constructs a CheckerManager without requiring an AST. No checker
|
|
/// registration will take place. Only useful when one needs to print the
|
|
/// help flags through CheckerRegistryData, and the AST is unavailable.
|
|
CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts,
|
|
DiagnosticsEngine &Diags, ArrayRef<std::string> plugins);
|
|
|
|
~CheckerManager();
|
|
|
|
void setCurrentCheckerName(CheckerNameRef name) { CurrentCheckerName = name; }
|
|
CheckerNameRef getCurrentCheckerName() const { return CurrentCheckerName; }
|
|
|
|
bool hasPathSensitiveCheckers() const;
|
|
|
|
void finishedCheckerRegistration();
|
|
|
|
const LangOptions &getLangOpts() const { return LangOpts; }
|
|
const AnalyzerOptions &getAnalyzerOptions() const { return AOptions; }
|
|
const Preprocessor &getPreprocessor() const {
|
|
assert(PP);
|
|
return *PP;
|
|
}
|
|
const CheckerRegistryData &getCheckerRegistryData() const {
|
|
return *RegistryData;
|
|
}
|
|
DiagnosticsEngine &getDiagnostics() const { return Diags; }
|
|
ASTContext &getASTContext() const {
|
|
assert(Context);
|
|
return *Context;
|
|
}
|
|
|
|
/// Emits an error through a DiagnosticsEngine about an invalid user supplied
|
|
/// checker option value.
|
|
void reportInvalidCheckerOptionValue(const CheckerBase *C,
|
|
StringRef OptionName,
|
|
StringRef ExpectedValueDesc) const;
|
|
|
|
using CheckerRef = CheckerBase *;
|
|
using CheckerTag = const void *;
|
|
using CheckerDtor = CheckerFn<void ()>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Checker registration.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Used to register checkers.
|
|
/// All arguments are automatically passed through to the checker
|
|
/// constructor.
|
|
///
|
|
/// \returns a pointer to the checker object.
|
|
template <typename CHECKER, typename... AT>
|
|
CHECKER *registerChecker(AT &&... Args) {
|
|
CheckerTag tag = getTag<CHECKER>();
|
|
CheckerRef &ref = CheckerTags[tag];
|
|
assert(!ref && "Checker already registered, use getChecker!");
|
|
|
|
CHECKER *checker = new CHECKER(std::forward<AT>(Args)...);
|
|
checker->Name = CurrentCheckerName;
|
|
CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
|
|
CHECKER::_register(checker, *this);
|
|
ref = checker;
|
|
return checker;
|
|
}
|
|
|
|
template <typename CHECKER>
|
|
CHECKER *getChecker() {
|
|
CheckerTag tag = getTag<CHECKER>();
|
|
assert(CheckerTags.count(tag) != 0 &&
|
|
"Requested checker is not registered! Maybe you should add it as a "
|
|
"dependency in Checkers.td?");
|
|
return static_cast<CHECKER *>(CheckerTags[tag]);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Functions for running checkers for AST traversing.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Run checkers handling Decls.
|
|
void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
|
|
BugReporter &BR);
|
|
|
|
/// Run checkers handling Decls containing a Stmt body.
|
|
void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
|
|
BugReporter &BR);
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Functions for running checkers for path-sensitive checking.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Run checkers for pre-visiting Stmts.
|
|
///
|
|
/// The notification is performed for every explored CFGElement, which does
|
|
/// not include the control flow statements such as IfStmt.
|
|
///
|
|
/// \sa runCheckersForBranchCondition, runCheckersForPostStmt
|
|
void runCheckersForPreStmt(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const Stmt *S,
|
|
ExprEngine &Eng) {
|
|
runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng);
|
|
}
|
|
|
|
/// Run checkers for post-visiting Stmts.
|
|
///
|
|
/// The notification is performed for every explored CFGElement, which does
|
|
/// not include the control flow statements such as IfStmt.
|
|
///
|
|
/// \sa runCheckersForBranchCondition, runCheckersForPreStmt
|
|
void runCheckersForPostStmt(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const Stmt *S,
|
|
ExprEngine &Eng,
|
|
bool wasInlined = false) {
|
|
runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined);
|
|
}
|
|
|
|
/// Run checkers for visiting Stmts.
|
|
void runCheckersForStmt(bool isPreVisit,
|
|
ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
|
|
const Stmt *S, ExprEngine &Eng,
|
|
bool wasInlined = false);
|
|
|
|
/// Run checkers for pre-visiting obj-c messages.
|
|
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const ObjCMethodCall &msg,
|
|
ExprEngine &Eng) {
|
|
runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng);
|
|
}
|
|
|
|
/// Run checkers for post-visiting obj-c messages.
|
|
void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const ObjCMethodCall &msg,
|
|
ExprEngine &Eng,
|
|
bool wasInlined = false) {
|
|
runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng,
|
|
wasInlined);
|
|
}
|
|
|
|
/// Run checkers for visiting an obj-c message to nil.
|
|
void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const ObjCMethodCall &msg,
|
|
ExprEngine &Eng) {
|
|
runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg,
|
|
Eng);
|
|
}
|
|
|
|
/// Run checkers for visiting obj-c messages.
|
|
void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
|
|
ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const ObjCMethodCall &msg, ExprEngine &Eng,
|
|
bool wasInlined = false);
|
|
|
|
/// Run checkers for pre-visiting obj-c messages.
|
|
void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
|
|
const CallEvent &Call, ExprEngine &Eng) {
|
|
runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng);
|
|
}
|
|
|
|
/// Run checkers for post-visiting obj-c messages.
|
|
void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
|
|
const CallEvent &Call, ExprEngine &Eng,
|
|
bool wasInlined = false) {
|
|
runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng,
|
|
wasInlined);
|
|
}
|
|
|
|
/// Run checkers for visiting obj-c messages.
|
|
void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
const CallEvent &Call, ExprEngine &Eng,
|
|
bool wasInlined = false);
|
|
|
|
/// Run checkers for load/store of a location.
|
|
void runCheckersForLocation(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
SVal location,
|
|
bool isLoad,
|
|
const Stmt *NodeEx,
|
|
const Stmt *BoundEx,
|
|
ExprEngine &Eng);
|
|
|
|
/// Run checkers for binding of a value to a location.
|
|
void runCheckersForBind(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
SVal location, SVal val,
|
|
const Stmt *S, ExprEngine &Eng,
|
|
const ProgramPoint &PP);
|
|
|
|
/// Run checkers for end of analysis.
|
|
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
|
|
ExprEngine &Eng);
|
|
|
|
/// Run checkers on beginning of function.
|
|
void runCheckersForBeginFunction(ExplodedNodeSet &Dst,
|
|
const BlockEdge &L,
|
|
ExplodedNode *Pred,
|
|
ExprEngine &Eng);
|
|
|
|
/// Run checkers on end of function.
|
|
void runCheckersForEndFunction(NodeBuilderContext &BC,
|
|
ExplodedNodeSet &Dst,
|
|
ExplodedNode *Pred,
|
|
ExprEngine &Eng,
|
|
const ReturnStmt *RS);
|
|
|
|
/// Run checkers for branch condition.
|
|
void runCheckersForBranchCondition(const Stmt *condition,
|
|
ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
|
ExprEngine &Eng);
|
|
|
|
/// Run checkers between C++ operator new and constructor calls.
|
|
void runCheckersForNewAllocator(const CXXAllocatorCall &Call,
|
|
ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
|
ExprEngine &Eng, bool wasInlined = false);
|
|
|
|
/// Run checkers for live symbols.
|
|
///
|
|
/// Allows modifying SymbolReaper object. For example, checkers can explicitly
|
|
/// register symbols of interest as live. These symbols will not be marked
|
|
/// dead and removed.
|
|
void runCheckersForLiveSymbols(ProgramStateRef state,
|
|
SymbolReaper &SymReaper);
|
|
|
|
/// Run checkers for dead symbols.
|
|
///
|
|
/// Notifies checkers when symbols become dead. For example, this allows
|
|
/// checkers to aggressively clean up/reduce the checker state and produce
|
|
/// precise diagnostics.
|
|
void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
|
|
const ExplodedNodeSet &Src,
|
|
SymbolReaper &SymReaper, const Stmt *S,
|
|
ExprEngine &Eng,
|
|
ProgramPoint::Kind K);
|
|
|
|
/// Run checkers for region changes.
|
|
///
|
|
/// This corresponds to the check::RegionChanges callback.
|
|
/// \param state The current program state.
|
|
/// \param invalidated A set of all symbols potentially touched by the change.
|
|
/// \param ExplicitRegions The regions explicitly requested for invalidation.
|
|
/// For example, in the case of a function call, these would be arguments.
|
|
/// \param Regions The transitive closure of accessible regions,
|
|
/// i.e. all regions that may have been touched by this change.
|
|
/// \param Call The call expression wrapper if the regions are invalidated
|
|
/// by a call.
|
|
ProgramStateRef
|
|
runCheckersForRegionChanges(ProgramStateRef state,
|
|
const InvalidatedSymbols *invalidated,
|
|
ArrayRef<const MemRegion *> ExplicitRegions,
|
|
ArrayRef<const MemRegion *> Regions,
|
|
const LocationContext *LCtx,
|
|
const CallEvent *Call);
|
|
|
|
/// Run checkers when pointers escape.
|
|
///
|
|
/// This notifies the checkers about pointer escape, which occurs whenever
|
|
/// the analyzer cannot track the symbol any more. For example, as a
|
|
/// result of assigning a pointer into a global or when it's passed to a
|
|
/// function call the analyzer cannot model.
|
|
///
|
|
/// \param State The state at the point of escape.
|
|
/// \param Escaped The list of escaped symbols.
|
|
/// \param Call The corresponding CallEvent, if the symbols escape as
|
|
/// parameters to the given call.
|
|
/// \param Kind The reason of pointer escape.
|
|
/// \param ITraits Information about invalidation for a particular
|
|
/// region/symbol.
|
|
/// \returns Checkers can modify the state by returning a new one.
|
|
ProgramStateRef
|
|
runCheckersForPointerEscape(ProgramStateRef State,
|
|
const InvalidatedSymbols &Escaped,
|
|
const CallEvent *Call,
|
|
PointerEscapeKind Kind,
|
|
RegionAndSymbolInvalidationTraits *ITraits);
|
|
|
|
/// Run checkers for handling assumptions on symbolic values.
|
|
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
|
|
SVal Cond, bool Assumption);
|
|
|
|
/// Run checkers for evaluating a call.
|
|
///
|
|
/// Warning: Currently, the CallEvent MUST come from a CallExpr!
|
|
void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
|
|
const CallEvent &CE, ExprEngine &Eng,
|
|
const EvalCallOptions &CallOpts);
|
|
|
|
/// Run checkers for the entire Translation Unit.
|
|
void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
|
|
AnalysisManager &mgr,
|
|
BugReporter &BR);
|
|
|
|
/// Run checkers for debug-printing a ProgramState.
|
|
///
|
|
/// Unlike most other callbacks, any checker can simply implement the virtual
|
|
/// method CheckerBase::printState if it has custom data to print.
|
|
///
|
|
/// \param Out The output stream
|
|
/// \param State The state being printed
|
|
/// \param NL The preferred representation of a newline.
|
|
/// \param Space The preferred space between the left side and the message.
|
|
/// \param IsDot Whether the message will be printed in 'dot' format.
|
|
void runCheckersForPrintStateJson(raw_ostream &Out, ProgramStateRef State,
|
|
const char *NL = "\n",
|
|
unsigned int Space = 0,
|
|
bool IsDot = false) const;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Internal registration functions for AST traversing.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Functions used by the registration mechanism, checkers should not touch
|
|
// these directly.
|
|
|
|
using CheckDeclFunc =
|
|
CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>;
|
|
|
|
using HandlesDeclFunc = bool (*)(const Decl *D);
|
|
|
|
void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn);
|
|
|
|
void _registerForBody(CheckDeclFunc checkfn);
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Internal registration functions for path-sensitive checking.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
using CheckStmtFunc = CheckerFn<void (const Stmt *, CheckerContext &)>;
|
|
|
|
using CheckObjCMessageFunc =
|
|
CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>;
|
|
|
|
using CheckCallFunc =
|
|
CheckerFn<void (const CallEvent &, CheckerContext &)>;
|
|
|
|
using CheckLocationFunc = CheckerFn<void(SVal location, bool isLoad,
|
|
const Stmt *S, CheckerContext &)>;
|
|
|
|
using CheckBindFunc =
|
|
CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;
|
|
|
|
using CheckEndAnalysisFunc =
|
|
CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>;
|
|
|
|
using CheckBeginFunctionFunc = CheckerFn<void (CheckerContext &)>;
|
|
|
|
using CheckEndFunctionFunc =
|
|
CheckerFn<void (const ReturnStmt *, CheckerContext &)>;
|
|
|
|
using CheckBranchConditionFunc =
|
|
CheckerFn<void (const Stmt *, CheckerContext &)>;
|
|
|
|
using CheckNewAllocatorFunc =
|
|
CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>;
|
|
|
|
using CheckDeadSymbolsFunc =
|
|
CheckerFn<void (SymbolReaper &, CheckerContext &)>;
|
|
|
|
using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>;
|
|
|
|
using CheckRegionChangesFunc =
|
|
CheckerFn<ProgramStateRef (ProgramStateRef,
|
|
const InvalidatedSymbols *symbols,
|
|
ArrayRef<const MemRegion *> ExplicitRegions,
|
|
ArrayRef<const MemRegion *> Regions,
|
|
const LocationContext *LCtx,
|
|
const CallEvent *Call)>;
|
|
|
|
using CheckPointerEscapeFunc =
|
|
CheckerFn<ProgramStateRef (ProgramStateRef,
|
|
const InvalidatedSymbols &Escaped,
|
|
const CallEvent *Call, PointerEscapeKind Kind,
|
|
RegionAndSymbolInvalidationTraits *ITraits)>;
|
|
|
|
using EvalAssumeFunc =
|
|
CheckerFn<ProgramStateRef(ProgramStateRef, SVal cond, bool assumption)>;
|
|
|
|
using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>;
|
|
|
|
using CheckEndOfTranslationUnit =
|
|
CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &,
|
|
BugReporter &)>;
|
|
|
|
using HandlesStmtFunc = bool (*)(const Stmt *D);
|
|
|
|
void _registerForPreStmt(CheckStmtFunc checkfn,
|
|
HandlesStmtFunc isForStmtFn);
|
|
void _registerForPostStmt(CheckStmtFunc checkfn,
|
|
HandlesStmtFunc isForStmtFn);
|
|
|
|
void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
|
|
void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
|
|
|
|
void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn);
|
|
|
|
void _registerForPreCall(CheckCallFunc checkfn);
|
|
void _registerForPostCall(CheckCallFunc checkfn);
|
|
|
|
void _registerForLocation(CheckLocationFunc checkfn);
|
|
|
|
void _registerForBind(CheckBindFunc checkfn);
|
|
|
|
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
|
|
|
|
void _registerForBeginFunction(CheckBeginFunctionFunc checkfn);
|
|
void _registerForEndFunction(CheckEndFunctionFunc checkfn);
|
|
|
|
void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
|
|
|
|
void _registerForNewAllocator(CheckNewAllocatorFunc checkfn);
|
|
|
|
void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn);
|
|
|
|
void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn);
|
|
|
|
void _registerForRegionChanges(CheckRegionChangesFunc checkfn);
|
|
|
|
void _registerForPointerEscape(CheckPointerEscapeFunc checkfn);
|
|
|
|
void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn);
|
|
|
|
void _registerForEvalAssume(EvalAssumeFunc checkfn);
|
|
|
|
void _registerForEvalCall(EvalCallFunc checkfn);
|
|
|
|
void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Internal registration functions for events.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
using EventTag = void *;
|
|
using CheckEventFunc = CheckerFn<void (const void *event)>;
|
|
|
|
template <typename EVENT>
|
|
void _registerListenerForEvent(CheckEventFunc checkfn) {
|
|
EventInfo &info = Events[&EVENT::Tag];
|
|
info.Checkers.push_back(checkfn);
|
|
}
|
|
|
|
template <typename EVENT>
|
|
void _registerDispatcherForEvent() {
|
|
EventInfo &info = Events[&EVENT::Tag];
|
|
info.HasDispatcher = true;
|
|
}
|
|
|
|
template <typename EVENT>
|
|
void _dispatchEvent(const EVENT &event) const {
|
|
EventsTy::const_iterator I = Events.find(&EVENT::Tag);
|
|
if (I == Events.end())
|
|
return;
|
|
const EventInfo &info = I->second;
|
|
for (const auto &Checker : info.Checkers)
|
|
Checker(&event);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Implementation details.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
private:
|
|
template <typename CHECKER>
|
|
static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
|
|
|
|
template <typename T>
|
|
static void *getTag() { static int tag; return &tag; }
|
|
|
|
llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags;
|
|
|
|
std::vector<CheckerDtor> CheckerDtors;
|
|
|
|
struct DeclCheckerInfo {
|
|
CheckDeclFunc CheckFn;
|
|
HandlesDeclFunc IsForDeclFn;
|
|
};
|
|
std::vector<DeclCheckerInfo> DeclCheckers;
|
|
|
|
std::vector<CheckDeclFunc> BodyCheckers;
|
|
|
|
using CachedDeclCheckers = SmallVector<CheckDeclFunc, 4>;
|
|
using CachedDeclCheckersMapTy = llvm::DenseMap<unsigned, CachedDeclCheckers>;
|
|
CachedDeclCheckersMapTy CachedDeclCheckersMap;
|
|
|
|
struct StmtCheckerInfo {
|
|
CheckStmtFunc CheckFn;
|
|
HandlesStmtFunc IsForStmtFn;
|
|
bool IsPreVisit;
|
|
};
|
|
std::vector<StmtCheckerInfo> StmtCheckers;
|
|
|
|
using CachedStmtCheckers = SmallVector<CheckStmtFunc, 4>;
|
|
using CachedStmtCheckersMapTy = llvm::DenseMap<unsigned, CachedStmtCheckers>;
|
|
CachedStmtCheckersMapTy CachedStmtCheckersMap;
|
|
|
|
const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S,
|
|
bool isPreVisit);
|
|
|
|
/// Returns the checkers that have registered for callbacks of the
|
|
/// given \p Kind.
|
|
const std::vector<CheckObjCMessageFunc> &
|
|
getObjCMessageCheckers(ObjCMessageVisitKind Kind) const;
|
|
|
|
std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
|
|
std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
|
|
std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers;
|
|
|
|
std::vector<CheckCallFunc> PreCallCheckers;
|
|
std::vector<CheckCallFunc> PostCallCheckers;
|
|
|
|
std::vector<CheckLocationFunc> LocationCheckers;
|
|
|
|
std::vector<CheckBindFunc> BindCheckers;
|
|
|
|
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
|
|
|
|
std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers;
|
|
std::vector<CheckEndFunctionFunc> EndFunctionCheckers;
|
|
|
|
std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
|
|
|
|
std::vector<CheckNewAllocatorFunc> NewAllocatorCheckers;
|
|
|
|
std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers;
|
|
|
|
std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers;
|
|
|
|
std::vector<CheckRegionChangesFunc> RegionChangesCheckers;
|
|
|
|
std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers;
|
|
|
|
std::vector<EvalAssumeFunc> EvalAssumeCheckers;
|
|
|
|
std::vector<EvalCallFunc> EvalCallCheckers;
|
|
|
|
std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
|
|
|
|
struct EventInfo {
|
|
SmallVector<CheckEventFunc, 4> Checkers;
|
|
bool HasDispatcher = false;
|
|
|
|
EventInfo() = default;
|
|
};
|
|
|
|
using EventsTy = llvm::DenseMap<EventTag, EventInfo>;
|
|
EventsTy Events;
|
|
};
|
|
|
|
} // namespace ento
|
|
|
|
} // namespace clang
|
|
|
|
#endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
|