18#include "llvm/ADT/FoldingSet.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/Casting.h"
28using namespace tagged_union_modeling;
32namespace
clang::ento::tagged_union_modeling {
36 const auto *ConstructorCall = dyn_cast<CXXConstructorCall>(&
Call);
40 return ConstructorCall->getDecl();
46 return ConstructorDecl->isCopyConstructor();
51 const Decl *CopyAssignmentDecl =
Call.getDecl();
53 if (
const auto *AsMethodDecl =
54 dyn_cast_or_null<CXXMethodDecl>(CopyAssignmentDecl))
55 return AsMethodDecl->isCopyAssignmentOperator();
69 const Decl *CopyAssignmentDecl =
Call.getDecl();
71 const auto *AsMethodDecl =
72 dyn_cast_or_null<CXXMethodDecl>(CopyAssignmentDecl);
76 return AsMethodDecl->isMoveAssignmentOperator();
92static std::optional<ArrayRef<TemplateArgument>>
101static std::optional<QualType>
103 std::optional<ArrayRef<TemplateArgument>> VariantTemplates =
105 if (!VariantTemplates)
108 return (*VariantTemplates)[i].getAsType();
133 {
"std",
"variant",
"variant"}};
135 {
"std",
"variant",
"operator="}};
138 BugType BadVariantType{
this,
"BadVariantType",
"BadVariantType"};
150 return removeInformationStoredForDeadInstances<VariantHeldTypeMap>(
151 *
Call, State, Regions);
157 if (
Call.isCalledFromSystemHeader())
161 return handleStdGetCall(
Call,
C);
165 bool IsVariantConstructor =
167 bool IsVariantAssignmentOperatorCall =
168 isa<CXXMemberOperatorCall>(
Call) &&
171 if (IsVariantConstructor || IsVariantAssignmentOperatorCall) {
172 if (
Call.getNumArgs() == 0 && IsVariantConstructor) {
173 handleDefaultConstructor(cast<CXXConstructorCall>(&
Call),
C);
179 if (
Call.getNumArgs() != 1)
183 if (IsVariantConstructor) {
184 const auto &AsConstructorCall = cast<CXXConstructorCall>(
Call);
185 ThisSVal = AsConstructorCall.getCXXThisVal();
186 }
else if (IsVariantAssignmentOperatorCall) {
187 const auto &AsMemberOpCall = cast<CXXMemberOperatorCall>(
Call);
188 ThisSVal = AsMemberOpCall.getCXXThisVal();
193 handleConstructorAndAssignment<VariantHeldTypeMap>(
Call,
C, ThisSVal);
207 const auto *
const ThisMemRegion = ThisSVal.
getAsRegion();
217 State = State->set<VariantHeldTypeMap>(ThisMemRegion, *DefaultType);
218 C.addTransition(State);
224 const auto &ArgType =
Call.getArgSVal(0)
225 .getType(
C.getASTContext())
235 const MemRegion *ArgMemRegion =
Call.getArgSVal(0).getAsRegion();
236 const QualType *StoredType = State->get<VariantHeldTypeMap>(ArgMemRegion);
240 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
251 switch (TypeOut.getKind()) {
252 case TemplateArgument::ArgKind::Type:
253 RetrievedType = TypeOut.getAsType();
255 case TemplateArgument::ArgKind::Integral:
258 if (std::optional<QualType> NthTemplate =
260 ArgType, TypeOut.getAsIntegral().getSExtValue())) {
261 RetrievedType = *NthTemplate;
270 QualType StoredCanonicalType = StoredType->getCanonicalType();
271 if (RetrievedCanonicalType == StoredCanonicalType)
278 llvm::raw_svector_ostream OS(Str);
279 std::string StoredTypeName = StoredType->getAsString();
280 std::string RetrievedTypeName = RetrievedType.
getAsString();
283 << StoredTypeName <<
"\', not "
285 << RetrievedTypeName <<
"\'";
286 auto R = std::make_unique<PathSensitiveBugReport>(BadVariantType, OS.str(),
288 C.emitReport(std::move(R));
293bool 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...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
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
Represents a function declaration or definition.
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.
Represents a type template specialization; the template must be a class template, a type alias templa...
ArrayRef< TemplateArgument > template_arguments() const
The base class of the type hierarchy.
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>'.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
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...
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
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)
Used to register checkers.
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
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)
bool isStdVariant(const Type *Type)
bool isMoveConstructorCall(const CallEvent &Call)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
The JSON file list parser is used to communicate input to InstallAPI.