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>();
96 return TempSpecType->template_arguments();
99static std::optional<QualType>
101 std::optional<ArrayRef<TemplateArgument>> VariantTemplates =
103 if (!VariantTemplates)
106 return (*VariantTemplates)[i].getAsType();
131 {
"std",
"variant",
"variant"}};
133 {
"std",
"variant",
"operator="}};
136 BugType BadVariantType{
this,
"BadVariantType",
"BadVariantType"};
149 *
Call, State, Regions);
155 if (
Call.isCalledFromSystemHeader())
158 if (StdGet.matches(
Call))
159 return handleStdGetCall(
Call,
C);
163 bool IsVariantConstructor =
165 bool IsVariantAssignmentOperatorCall =
167 VariantAssignmentOperator.matches(
Call);
169 if (IsVariantConstructor || IsVariantAssignmentOperatorCall) {
170 if (
Call.getNumArgs() == 0 && IsVariantConstructor) {
177 if (
Call.getNumArgs() != 1)
181 if (IsVariantConstructor) {
183 ThisSVal = AsConstructorCall.getCXXThisVal();
184 }
else if (IsVariantAssignmentOperatorCall) {
186 ThisSVal = AsMemberOpCall.getCXXThisVal();
205 const auto *
const ThisMemRegion = ThisSVal.
getAsRegion();
215 State = State->set<VariantHeldTypeMap>(ThisMemRegion, *DefaultType);
216 C.addTransition(State);
219 bool handleStdGetCall(
const CallEvent &
Call, CheckerContext &
C)
const {
222 const auto &ArgType =
Call.getArgSVal(0)
223 .getType(
C.getASTContext())
233 const MemRegion *ArgMemRegion =
Call.getArgSVal(0).getAsRegion();
234 const QualType *StoredType = State->get<VariantHeldTypeMap>(ArgMemRegion);
248 QualType RetrievedType;
249 switch (TypeOut.getKind()) {
250 case TemplateArgument::ArgKind::Type:
251 RetrievedType = TypeOut.getAsType();
253 case TemplateArgument::ArgKind::Integral:
256 if (std::optional<QualType> NthTemplate =
258 ArgType, TypeOut.getAsIntegral().getSExtValue())) {
259 RetrievedType = *NthTemplate;
268 QualType StoredCanonicalType = StoredType->getCanonicalType();
269 if (RetrievedCanonicalType == StoredCanonicalType)
272 ExplodedNode *ErrNode =
C.generateNonFatalErrorNode();
275 llvm::SmallString<128> Str;
276 llvm::raw_svector_ostream
OS(Str);
277 std::string StoredTypeName = StoredType->getAsString();
278 std::string RetrievedTypeName = RetrievedType.
getAsString();
281 << StoredTypeName <<
"\', not "
283 << RetrievedTypeName <<
"\'";
284 auto R = std::make_unique<PathSensitiveBugReport>(BadVariantType,
OS.str(),
286 C.emitReport(std::move(R));
291bool 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.
const ProgramStateRef & getState() const
The state in which the call is being evaluated.
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)