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...
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)