================ @@ -0,0 +1,312 @@ +//===- StdVariantChecker.cpp -------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Type.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/FoldingSet.h" + +#include "TaggedUnionModeling.h" + +using namespace clang; +using namespace ento; +using namespace variant_modeling; + +REGISTER_MAP_WITH_PROGRAMSTATE(VariantHeldTypeMap, const MemRegion *, QualType) + +namespace clang { +namespace ento { +namespace variant_modeling { + +// Returns the CallEvent representing the caller of the function +// It is needed because the CallEvent class does not contain enough information +// to tell who called it. Checker context is needed. +CallEventRef<> getCaller(const CallEvent &Call, const ProgramStateRef &State) { + const auto *CallLocationContext = Call.getLocationContext(); + if (!CallLocationContext) { + return nullptr; + } + + if (CallLocationContext->inTopFrame()) { + return nullptr; + } + const auto *CallStackFrameContext = CallLocationContext->getStackFrame(); + if (!CallStackFrameContext) { + return nullptr; + } + + CallEventManager &CEMgr = State->getStateManager().getCallEventManager(); + return CEMgr.getCaller(CallStackFrameContext, State); +} + +const CXXConstructorDecl * +getConstructorDeclarationForCall(const CallEvent &Call) { + const auto *ConstructorCall = dyn_cast<CXXConstructorCall>(&Call); + if (!ConstructorCall) { + return nullptr; + } + return ConstructorCall->getDecl(); +} + +bool isCopyConstructorCall(const CallEvent &Call) { + const CXXConstructorDecl *ConstructorDecl = + getConstructorDeclarationForCall(Call); + if (!ConstructorDecl) { + return false; + } + return ConstructorDecl->isCopyConstructor(); +} + +bool isCopyAssignmentCall(const CallEvent &Call) { + const Decl *CopyAssignmentDecl = Call.getDecl(); + if (!CopyAssignmentDecl) { + return false; + } + const auto *AsMethodDecl = dyn_cast<CXXMethodDecl>(CopyAssignmentDecl); + if (!AsMethodDecl) { + return false; + } + return AsMethodDecl->isCopyAssignmentOperator(); +} + +bool isMoveConstructorCall(const CallEvent &Call) { + const CXXConstructorDecl *ConstructorDecl = + getConstructorDeclarationForCall(Call); + if (!ConstructorDecl) { + return false; + } + return ConstructorDecl->isMoveConstructor(); +} + +bool isMoveAssignmentCall(const CallEvent &Call) { + const Decl *CopyAssignmentDecl = Call.getDecl(); + if (!CopyAssignmentDecl) { + return false; + } + const auto *AsMethodDecl = dyn_cast<CXXMethodDecl>(CopyAssignmentDecl); + if (!AsMethodDecl) { + return false; + } + return AsMethodDecl->isMoveAssignmentOperator(); +} + +const TemplateArgument &getFirstTemplateArgument(const CallEvent &Call) { + const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); + const FunctionDecl *FD = CE->getDirectCallee(); + assert(1 <= FD->getTemplateSpecializationArgs()->asArray().size() && + "std::get should have at least 1 template argument!"); + return FD->getTemplateSpecializationArgs()->asArray()[0]; +} + +bool isStdType(const Type *Type, const std::string &TypeName) { + auto *Decl = Type->getAsRecordDecl(); + if (!Decl) { + return false; + } + + return (Decl->getNameAsString() == TypeName) && Decl->isInStdNamespace(); +} + +bool isStdVariant(const Type *Type) { + return isStdType(Type, std::string("variant")); +} + +bool calledFromSystemHeader(const CallEvent &Call, + const ProgramStateRef &State) { + auto Caller = getCaller(Call, State); + if (Caller) { + return Caller->isInSystemHeader(); + } + return false; +} + +bool calledFromSystemHeader(const CallEvent &Call, CheckerContext &C) { + return calledFromSystemHeader(Call, C.getState()); +} + +} // end of namespace variant_modeling +} // end of namespace ento +} // end of namespace clang + +static ArrayRef<TemplateArgument> +getTemplateArgsFromVariant(const Type *VariantType) { + const auto *TempSpecType = VariantType->getAs<TemplateSpecializationType>(); + assert(TempSpecType && + "We are in a variant instance. It must be a template specialization!"); + return TempSpecType->template_arguments(); +} + +static QualType getNthTemplateTypeArgFromVariant(const Type *varType, + unsigned i) { + return getTemplateArgsFromVariant(varType)[i].getAsType(); ---------------- steakhal wrote:
Raw array accesses should be guarded by an assert right before. https://github.com/llvm/llvm-project/pull/66481 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits