18#include "llvm/ADT/FoldingSet.h"
19#include "llvm/ADT/StringRef.h"
34 const auto *ConstructorCall = dyn_cast<CXXConstructorCall>(&
Call);
38 return ConstructorCall->getDecl();
44 return ConstructorDecl->isCopyConstructor();
49 const Decl *CopyAssignmentDecl =
Call.getDecl();
51 if (
const auto *AsMethodDecl =
52 dyn_cast_or_null<CXXMethodDecl>(CopyAssignmentDecl))
53 return AsMethodDecl->isCopyAssignmentOperator();
67 const Decl *CopyAssignmentDecl =
Call.getDecl();
69 const auto *AsMethodDecl =
70 dyn_cast_or_null<CXXMethodDecl>(CopyAssignmentDecl);
74 return AsMethodDecl->isMoveAssignmentOperator();
90static std::optional<ArrayRef<TemplateArgument>>
92 const auto *TempSpecType = VariantType->
getAs<TemplateSpecializationType>();
93 while (TempSpecType && TempSpecType->isTypeAlias())
95 TempSpecType->getAliasedType()->getAs<TemplateSpecializationType>();
99 return TempSpecType->template_arguments();
102static std::optional<QualType>
104 std::optional<ArrayRef<TemplateArgument>> VariantTemplates =
106 if (!VariantTemplates)
109 return (*VariantTemplates)[i].getAsType();
134 {
"std",
"variant",
"variant"}};
136 {
"std",
"variant",
"operator="}};
139 BugType BadVariantType{
this,
"BadVariantType",
"BadVariantType"};
152 *
Call, State, Regions);
158 if (
Call.isCalledFromSystemHeader())
161 if (StdGet.matches(
Call))
162 return handleStdGetCall(
Call,
C);
166 bool IsVariantConstructor =
168 bool IsVariantAssignmentOperatorCall =
170 VariantAssignmentOperator.matches(
Call);
172 if (IsVariantConstructor || IsVariantAssignmentOperatorCall) {
173 if (
Call.getNumArgs() == 0 && IsVariantConstructor) {
180 if (
Call.getNumArgs() != 1)
184 if (IsVariantConstructor) {
186 ThisSVal = AsConstructorCall.getCXXThisVal();
187 }
else if (IsVariantAssignmentOperatorCall) {
189 ThisSVal = AsMemberOpCall.getCXXThisVal();
208 const auto *
const ThisMemRegion = ThisSVal.
getAsRegion();
218 State = State->set<VariantHeldTypeMap>(ThisMemRegion, *DefaultType);
219 C.addTransition(State);
222 bool handleStdGetCall(
const CallEvent &
Call, CheckerContext &
C)
const {
225 SVal ArgSVal =
Call.getArgSVal(0);
229 const auto &ArgType =
238 const MemRegion *ArgMemRegion =
Call.getArgSVal(0).getAsRegion();
239 const QualType *StoredType = State->get<VariantHeldTypeMap>(ArgMemRegion);
253 QualType RetrievedType;
254 switch (TypeOut.getKind()) {
255 case TemplateArgument::ArgKind::Type:
256 RetrievedType = TypeOut.getAsType();
258 case TemplateArgument::ArgKind::Integral:
261 if (std::optional<QualType> NthTemplate =
263 ArgType, TypeOut.getAsIntegral().getSExtValue())) {
264 RetrievedType = *NthTemplate;
273 QualType StoredCanonicalType = StoredType->getCanonicalType();
274 if (RetrievedCanonicalType == StoredCanonicalType)
277 ExplodedNode *ErrNode =
C.generateNonFatalErrorNode();
280 llvm::SmallString<128> Str;
281 llvm::raw_svector_ostream
OS(Str);
282 std::string StoredTypeName = StoredType->getAsString();
283 std::string RetrievedTypeName = RetrievedType.
getAsString();
286 << StoredTypeName <<
"\', not "
288 << RetrievedTypeName <<
"\'";
289 auto R = std::make_unique<PathSensitiveBugReport>(BadVariantType,
OS.str(),
291 C.emitReport(std::move(R));
296bool clang::ento::shouldRegisterStdVariantChecker(
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static std::optional< ArrayRef< TemplateArgument > > getTemplateArgsFromVariant(const Type *VariantType)
static std::optional< QualType > getNthTemplateTypeArgFromVariant(const Type *varType, unsigned i)
static llvm::StringRef indefiniteArticleBasedOnVowel(char a)
static bool isVowel(char a)
C Language Family Type Representation.
ProgramStateRef checkRegionChanges(ProgramStateRef State, const InvalidatedSymbols *, ArrayRef< const MemRegion * >, ArrayRef< const MemRegion * > Regions, const LocationContext *, const CallEvent *Call) const
bool evalCall(const CallEvent &Call, CheckerContext &C) const
Represents a C++ constructor within a class.
bool isMoveConstructor(unsigned &TypeQuals) const
Determine whether this constructor is a move constructor (C++11 [class.copy]p3), which can be used to...
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
const TemplateArgumentList * getTemplateSpecializationArgs() const
Retrieve the template arguments used to produce this function template specialization from the primar...
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
QualType getCanonicalType() const
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
unsigned size() const
Retrieve the number of template arguments in this template argument list.
ArrayRef< TemplateArgument > asArray() const
Produce this as an array ref.
The base class of the type hierarchy.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
SVal getCXXThisVal() const
Returns the value of the implicit 'this' object.
Represents a call to a C++ constructor.
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
MemRegion - The root abstract class for all memory regions.
std::string getDescriptiveName(bool UseQuotes=true) const
Get descriptive name for memory region.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
QualType getType(const ASTContext &) const
Try to get a reasonable type for the given value.
const MemRegion * getAsRegion() const
ProgramStateRef removeInformationStoredForDeadInstances(const CallEvent &Call, ProgramStateRef State, ArrayRef< const MemRegion * > Regions)
bool isCopyAssignmentCall(const CallEvent &Call)
static const CXXConstructorDecl * getConstructorDeclarationForCall(const CallEvent &Call)
static bool isStdType(const Type *Type, llvm::StringRef TypeName)
bool isMoveAssignmentCall(const CallEvent &Call)
bool isCopyConstructorCall(const CallEvent &Call)
void handleConstructorAndAssignment(const CallEvent &Call, CheckerContext &C, SVal ThisSVal)
bool isStdVariant(const Type *Type)
bool isMoveConstructorCall(const CallEvent &Call)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)