34#include "llvm/ADT/StringMap.h"
35#include "llvm/Support/ErrorHandling.h"
45 :
public Checker<eval::Call, check::DeadSymbols, check::RegionChanges,
48 bool isBoolConversionMethod(
const CallEvent &Call)
const;
52 bool ModelSmartPtrDereference =
false;
62 const char *Sep)
const override;
81 std::pair<SVal, ProgramStateRef>
86 using SmartPtrMethodHandlerFn =
89 {{{
"reset"}}, &SmartPtrModeling::handleReset},
90 {{{
"release"}}, &SmartPtrModeling::handleRelease},
91 {{{
"swap"}, 1}, &SmartPtrModeling::handleSwapMethod},
92 {{{
"get"}}, &SmartPtrModeling::handleGet}};
96 {
"std",
"make_unique_for_overwrite"}};
105 if (!RD || !RD->getDeclContext()->isStdNamespace())
107 if (RD->getDeclName().isIdentifier())
108 return llvm::is_contained(Names, RD->getName());
128 const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
129 if (!MethodDecl || !MethodDecl->getParent())
139 StringRef Name = RD->
getName();
140 return Name ==
"shared_ptr" || Name ==
"unique_ptr" || Name ==
"weak_ptr";
150 const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
151 return InnerPointVal &&
159static TrackedRegionMapTy
161 TrackedRegionMapTy::Factory &RegionMapFactory,
165 for (
const auto &E : RegionMap) {
166 if (E.first->isSubRegionOf(Region))
167 RegionMap = RegionMapFactory.remove(RegionMap, E.first);
174 const SVal *RegionInnerPointerVal) {
175 if (RegionInnerPointerVal) {
176 State = State->set<TrackedRegionMap>(Region, *RegionInnerPointerVal);
178 State = State->remove<TrackedRegionMap>(Region);
187 const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
191 auto TemplateArgs = TSD->getTemplateArgs().asArray();
192 if (TemplateArgs.empty())
194 auto InnerValueType = TemplateArgs[0].getAsType();
195 return C.getASTContext().getPointerType(InnerValueType.getCanonicalType());
203 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
204 if (!FD || !FD->isFunctionTemplateSpecialization())
206 const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray();
207 if (TemplateArgs.size() == 0)
209 auto ValueType = TemplateArgs[0].getAsType();
210 return C.getASTContext().getPointerType(ValueType.getCanonicalType());
216 const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
217 if (!MethodDecl || !MethodDecl->getParent())
233bool SmartPtrModeling::isBoolConversionMethod(
const CallEvent &Call)
const {
238 const auto *CD = dyn_cast_or_null<CXXConversionDecl>(
Call.getDecl());
239 return CD && CD->getConversionType()->isBooleanType();
250 return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
256 const auto *FC = dyn_cast<SimpleFunctionCall>(&Call);
263 if (OOK != clang::OO_LessLess)
276bool SmartPtrModeling::evalCall(
const CallEvent &Call,
284 if (handleComparisionOp(Call,
C))
288 return handleOstreamOperator(Call,
C);
290 if (StdSwapCall.matches(Call)) {
292 assert(
Call.getNumArgs() == 2 &&
"std::swap should have two arguments");
293 const Expr *FirstArg =
Call.getArgExpr(0);
296 return handleSwap(State,
Call.getArgSVal(0),
Call.getArgSVal(1),
C);
299 if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) {
300 if (!ModelSmartPtrDereference)
303 const std::optional<SVal> ThisRegionOpt =
304 Call.getReturnValueUnderConstruction();
308 const auto PtrVal =
C.getSValBuilder().getConjuredHeapSymbolVal(
309 Call.getOriginExpr(),
C.getLocationContext(),
312 const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
313 State = State->set<TrackedRegionMap>(ThisRegion, PtrVal);
314 State = State->assume(PtrVal,
true);
332 auto &Engine = State->getStateManager().getOwningEngine();
333 State = Engine.updateObjectsUnderConstruction(
334 *ThisRegionOpt,
nullptr, State,
C.getLocationContext(),
335 Call.getConstructionContext(), {});
339 C.addTransition(State);
346 if (isBoolConversionMethod(Call)) {
348 cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
350 if (ModelSmartPtrDereference) {
355 handleBoolConversion(Call,
C);
365 C.addTransition(State->BindExpr(
366 Call.getOriginExpr(),
C.getLocationContext(),
367 C.getSValBuilder().makeZeroVal(
Call.getResultType())));
373 if (!ModelSmartPtrDereference)
376 if (
const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
377 if (CC->getDecl()->isCopyConstructor())
380 const MemRegion *ThisRegion = CC->getCXXThisVal().getAsRegion();
384 QualType ThisType = cast<CXXMethodDecl>(
Call.getDecl())->getThisType();
386 if (CC->getDecl()->isMoveConstructor())
387 return handleMoveCtr(Call,
C, ThisRegion);
389 if (
Call.getNumArgs() == 0) {
390 auto NullVal =
C.getSValBuilder().makeNullWithType(ThisType);
391 State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
395 llvm::raw_ostream &OS) {
396 if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
397 !BR.isInteresting(ThisRegion))
399 OS <<
"Default constructed smart pointer";
400 checkAndPrettyPrintRegion(OS, ThisRegion);
404 const auto *TrackingExpr =
Call.getArgExpr(0);
405 assert(TrackingExpr->getType()->isPointerType() &&
406 "Adding a non pointer value to TrackedRegionMap");
407 auto ArgVal =
Call.getArgSVal(0);
408 State = State->set<TrackedRegionMap>(ThisRegion, ArgVal);
410 C.addTransition(State,
C.getNoteTag([ThisRegion, TrackingExpr,
412 llvm::raw_ostream &OS) {
413 if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
414 !BR.isInteresting(ThisRegion))
416 bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
417 OS <<
"Smart pointer";
418 checkAndPrettyPrintRegion(OS, ThisRegion);
419 if (ArgVal.isZeroConstant())
420 OS <<
" is constructed using a null value";
422 OS <<
" is constructed";
428 if (handleAssignOp(Call,
C))
431 const SmartPtrMethodHandlerFn *Handler = SmartPtrMethodHandlers.lookup(Call);
434 (this->**Handler)(Call,
C);
436 return C.isDifferent();
439std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal(
442 const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion);
444 return {*Ptr, State};
445 auto Val =
C.getSValBuilder().conjureSymbolVal(E,
C.getLocationContext(),
446 Type,
C.blockCount());
447 State = State->set<TrackedRegionMap>(ThisRegion, Val);
451bool SmartPtrModeling::handleComparisionOp(
const CallEvent &Call,
453 const auto *FC = dyn_cast<SimpleFunctionCall>(&Call);
460 if (!(OOK == OO_EqualEqual || OOK == OO_ExclaimEqual || OOK == OO_Less ||
461 OOK == OO_LessEqual || OOK == OO_Greater || OOK == OO_GreaterEqual ||
462 OOK == OO_Spaceship))
472 SVal S) -> std::pair<SVal, ProgramStateRef> {
473 if (S.isZeroConstant()) {
478 "this pointer of std::unique_ptr should be obtainable as MemRegion");
480 return retrieveOrConjureInnerPtrVal(State, Reg, E,
Type,
C);
485 const auto *FirstExpr =
Call.getArgExpr(0);
486 const auto *SecondExpr =
Call.getArgExpr(1);
488 const auto *ResultExpr =
Call.getOriginExpr();
489 const auto *LCtx =
C.getLocationContext();
490 auto &Bldr =
C.getSValBuilder();
493 SVal FirstPtrVal, SecondPtrVal;
494 std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr,
First);
495 std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second);
498 auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal,
499 Call.getResultType());
501 if (OOK != OO_Spaceship) {
503 std::tie(TrueState, FalseState) =
507 TrueState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(
true)));
510 FalseState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(
false)));
512 C.addTransition(State->BindExpr(ResultExpr, LCtx, RetVal));
517bool SmartPtrModeling::handleOstreamOperator(
const CallEvent &Call,
528 const auto StreamVal =
Call.getArgSVal(0);
529 const MemRegion *StreamThisRegion = StreamVal.getAsRegion();
530 if (!StreamThisRegion)
533 State->invalidateRegions({StreamThisRegion},
Call.getOriginExpr(),
534 C.blockCount(),
C.getLocationContext(),
false);
536 State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(), StreamVal);
537 C.addTransition(State);
541void SmartPtrModeling::checkDeadSymbols(
SymbolReaper &SymReaper,
545 TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
546 for (
auto E : TrackedRegions) {
551 State = State->remove<TrackedRegionMap>(Region);
553 C.addTransition(State);
556void SmartPtrModeling::printState(raw_ostream &Out,
ProgramStateRef State,
557 const char *NL,
const char *Sep)
const {
558 TrackedRegionMapTy RS = State->get<TrackedRegionMap>();
561 Out << Sep <<
"Smart ptr regions :" << NL;
563 I.first->dumpToStream(Out);
578 TrackedRegionMapTy RegionMap = State->get<TrackedRegionMap>();
579 TrackedRegionMapTy::Factory &RegionMapFactory =
580 State->get_context<TrackedRegionMap>();
581 for (
const auto *Region : Regions)
584 return State->set<TrackedRegionMap>(RegionMap);
590 TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
591 for (
auto I = TrackedRegions.begin(), E = TrackedRegions.end(); I != E; ++I) {
592 SVal Val = I->second;
599void SmartPtrModeling::handleReset(
const CallEvent &Call,
602 const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
606 const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
610 assert(
Call.getArgExpr(0)->getType()->isPointerType() &&
611 "Adding a non pointer value to TrackedRegionMap");
612 State = State->set<TrackedRegionMap>(ThisRegion,
Call.getArgSVal(0));
613 const auto *TrackingExpr =
Call.getArgExpr(0);
616 llvm::raw_ostream &OS) {
617 if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
618 !BR.isInteresting(ThisRegion))
620 bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
621 OS <<
"Smart pointer";
622 checkAndPrettyPrintRegion(OS, ThisRegion);
623 OS <<
" reset using a null value";
629void SmartPtrModeling::handleRelease(
const CallEvent &Call,
632 const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
636 const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
640 const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
643 State = State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
647 QualType ThisType = cast<CXXMethodDecl>(
Call.getDecl())->getThisType();
648 auto ValueToUpdate =
C.getSValBuilder().makeNullWithType(ThisType);
649 State = State->set<TrackedRegionMap>(ThisRegion, ValueToUpdate);
652 llvm::raw_ostream &OS) {
653 if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
654 !BR.isInteresting(ThisRegion))
657 OS <<
"Smart pointer";
658 checkAndPrettyPrintRegion(OS, ThisRegion);
659 OS <<
" is released and set to null";
665void SmartPtrModeling::handleSwapMethod(
const CallEvent &Call,
668 const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
672 auto State =
C.getState();
673 handleSwap(State, IC->getCXXThisVal(),
Call.getArgSVal(0),
C);
679 if (!FirstThisRegion)
682 if (!SecondThisRegion)
685 const auto *FirstInnerPtrVal = State->get<TrackedRegionMap>(FirstThisRegion);
686 const auto *SecondInnerPtrVal =
687 State->get<TrackedRegionMap>(SecondThisRegion);
692 C.addTransition(State,
C.getNoteTag([FirstThisRegion, SecondThisRegion](
694 llvm::raw_ostream &OS) {
695 if (&BR.getBugType() != smartptr::getNullDereferenceBugType())
697 if (BR.isInteresting(FirstThisRegion) &&
698 !BR.isInteresting(SecondThisRegion)) {
699 BR.markInteresting(SecondThisRegion);
700 BR.markNotInteresting(FirstThisRegion);
704 BR.markInteresting(FirstThisRegion);
705 BR.markNotInteresting(SecondThisRegion);
713void SmartPtrModeling::handleGet(
const CallEvent &Call,
716 const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
720 const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
724 SVal InnerPointerVal;
725 std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal(
726 State, ThisRegion,
Call.getOriginExpr(),
Call.getResultType(),
C);
727 State = State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
730 C.addTransition(State);
733bool SmartPtrModeling::handleAssignOp(
const CallEvent &Call,
736 const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
742 const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
746 QualType ThisType = cast<CXXMethodDecl>(
Call.getDecl())->getThisType();
748 const MemRegion *OtherSmartPtrRegion = OC->getArgSVal(0).getAsRegion();
750 if (!OtherSmartPtrRegion) {
751 bool AssignedNull =
Call.getArgSVal(0).isZeroConstant();
754 auto NullVal =
C.getSValBuilder().makeNullWithType(ThisType);
755 State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
757 llvm::raw_ostream &OS) {
758 if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
759 !BR.isInteresting(ThisRegion))
761 OS <<
"Smart pointer";
762 checkAndPrettyPrintRegion(OS, ThisRegion);
763 OS <<
" is assigned to null";
768 return updateMovedSmartPointers(
C, ThisRegion, OtherSmartPtrRegion, Call);
773 const auto *OtherSmartPtrRegion =
Call.getArgSVal(0).getAsRegion();
774 if (!OtherSmartPtrRegion)
777 return updateMovedSmartPointers(
C, ThisRegion, OtherSmartPtrRegion, Call);
780bool SmartPtrModeling::updateMovedSmartPointers(
784 QualType ThisType = cast<CXXMethodDecl>(
Call.getDecl())->getThisType();
785 const auto *OtherInnerPtr = State->get<TrackedRegionMap>(OtherSmartPtrRegion);
787 State = State->set<TrackedRegionMap>(ThisRegion, *OtherInnerPtr);
789 auto NullVal =
C.getSValBuilder().makeNullWithType(ThisType);
790 State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
791 bool IsArgValNull = OtherInnerPtr->isZeroConstant();
795 C.getNoteTag([ThisRegion, OtherSmartPtrRegion, IsArgValNull](
800 OS <<
"Smart pointer";
802 OS <<
" is null after being moved to";
806 OS <<
"A null pointer value is moved to";
816 auto NullVal =
C.getSValBuilder().makeNullWithType(ThisType);
817 State = State->remove<TrackedRegionMap>(ThisRegion);
818 State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
819 C.addTransition(State,
C.getNoteTag([OtherSmartPtrRegion,
821 llvm::raw_ostream &OS) {
825 OS <<
"Smart pointer";
827 OS <<
" is null after; previous value moved to";
835void SmartPtrModeling::handleBoolConversion(
const CallEvent &Call,
841 cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
843 QualType ThisType = cast<CXXMethodDecl>(
Call.getDecl())->getThisType();
845 SVal InnerPointerVal;
846 if (
const auto *InnerValPtr = State->get<TrackedRegionMap>(ThisRegion)) {
847 InnerPointerVal = *InnerValPtr;
852 if (InnerPointerType.isNull())
856 InnerPointerVal =
C.getSValBuilder().conjureSymbolVal(
857 CallExpr, LC, InnerPointerType,
C.blockCount());
858 State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
861 if (State->isNull(InnerPointerVal).isConstrainedTrue()) {
862 State = State->BindExpr(
CallExpr,
C.getLocationContext(),
863 C.getSValBuilder().makeTruthVal(
false));
865 C.addTransition(State);
867 }
else if (State->isNonNull(InnerPointerVal).isConstrainedTrue()) {
868 State = State->BindExpr(
CallExpr,
C.getLocationContext(),
869 C.getSValBuilder().makeTruthVal(
true));
871 C.addTransition(State);
875 State->BindExpr(
CallExpr,
C.getLocationContext(),
876 C.getSValBuilder().makeZeroVal(
Call.getResultType())));
880 std::tie(NotNullState, NullState) =
883 auto NullVal =
C.getSValBuilder().makeNullWithType(ThisType);
885 NullState = NullState->set<TrackedRegionMap>(ThisRegion, NullVal);
887 NullState = NullState->BindExpr(
CallExpr,
C.getLocationContext(),
888 C.getSValBuilder().makeTruthVal(
false));
889 C.addTransition(NullState,
C.getNoteTag(
891 llvm::raw_ostream &OS) {
892 OS <<
"Assuming smart pointer";
893 checkAndPrettyPrintRegion(OS, ThisRegion);
898 NotNullState->BindExpr(
CallExpr,
C.getLocationContext(),
899 C.getSValBuilder().makeTruthVal(
true));
904 OS <<
"Assuming smart pointer";
905 checkAndPrettyPrintRegion(OS, ThisRegion);
906 OS <<
" is non-null";
915 Checker->ModelSmartPtrDereference =
917 Checker,
"ModelSmartPtrDereference");
920bool ento::shouldRegisterSmartPtrModeling(
const CheckerManager &mgr) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static bool isStdFunctionCall(const CallEvent &Call)
bool isStdBasicOstream(const Expr *E)
static void checkAndPrettyPrintRegion(llvm::raw_ostream &OS, const MemRegion *Region)
bool isStdOstreamOperatorCall(const CallEvent &Call)
static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD)
static ProgramStateRef updateSwappedRegion(ProgramStateRef State, const MemRegion *Region, const SVal *RegionInnerPointerVal)
static TrackedRegionMapTy removeTrackedSubregions(TrackedRegionMapTy RegionMap, TrackedRegionMapTy::Factory &RegionMapFactory, const MemRegion *Region)
static bool isPotentiallyComparisionOpCall(const CallEvent &Call)
static QualType getPointerTypeFromTemplateArg(const CallEvent &Call, CheckerContext &C)
static bool hasStdClassWithName(const CXXRecordDecl *RD, ArrayRef< llvm::StringLiteral > Names)
static bool isStdSmartPtr(const CXXRecordDecl *RD)
constexpr llvm::StringLiteral BASIC_OSTREAM_NAMES[]
constexpr llvm::StringLiteral STD_PTR_NAMES[]
C Language Family Type Representation.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
Represents a C++ struct/union/class.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
DeclContext * getParent()
getParent - Returns the containing DeclContext.
bool isStdNamespace() const
bool isInStdNamespace() const
DeclContext * getDeclContext()
bool isIdentifier() const
Predicate functions for querying what type of name this is.
This represents one expression.
Represents a function declaration or definition.
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
A (possibly-)qualified type.
Represents a struct/union/class.
StringLiteral - This represents a string literal expression, e.g.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const BugType & getBugType() const
An immutable map from CallDescriptions to arbitrary data.
This class represents a description of a function call using the number of arguments and the name of ...
Represents an abstract call to a function or method along a particular path.
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const LangOptions & getLangOpts() const
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
BinaryOperatorKind GetBinaryOpUnsafe() const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
bool isInteresting(SymbolRef sym) const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymExpr::symbol_iterator symbol_begin() const
SymExpr::symbol_iterator symbol_end() const
const MemRegion * getAsRegion() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
A class responsible for cleaning up unused symbols.
void markLive(SymbolRef sym)
Unconditionally marks a symbol as live.
bool isLiveRegion(const MemRegion *region)
bool isMovedFrom(ProgramStateRef State, const MemRegion *Region)
Returns true if the object is known to have been recently std::moved.
const BugType * getNullDereferenceBugType()
bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion)
Returns whether the smart pointer is null or not.
bool isStdSmartPtr(const CXXRecordDecl *RD)
bool isStdSmartPtrCall(const CallEvent &Call)
Returns true if the event call is on smart pointer.
OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK, bool IsBinary)
bool Call(InterpState &S, CodePtr OpPC, const Function *Func)
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ C
Languages that the frontend can parse and compile.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
YAML serialization mapping.