Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h @@ -30,7 +30,8 @@ namespace ento { /// Get dynamic type information for the region \p MR. -DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR); +const DynamicTypeInfo *getDynamicTypeInfo(ProgramStateRef State, + const MemRegion *MR); /// Get raw dynamic type information for the region \p MR. const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State, @@ -44,7 +45,7 @@ /// Set dynamic type information of the region; return the new state. ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, - DynamicTypeInfo NewTy); + const DynamicTypeInfo *NewTy); /// Set dynamic type information of the region; return the new state. ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h @@ -18,32 +18,29 @@ /// of a region in a given state along the analysis path. class DynamicTypeInfo { public: - DynamicTypeInfo() : DynTy(QualType()) {} + DynamicTypeInfo() : Ty(QualType()) {} - DynamicTypeInfo(QualType Ty, bool CanBeSub = true) - : DynTy(Ty), CanBeASubClass(CanBeSub) {} + DynamicTypeInfo(QualType Ty, bool CanBeASubClass = true) + : Ty(Ty), CanBeASubClass(CanBeASubClass) {} /// Returns false if the type information is precise (the type 'DynTy' is /// the only type in the lattice), true otherwise. bool canBeASubClass() const { return CanBeASubClass; } - /// Returns true if the dynamic type info is available. - bool isValid() const { return !DynTy.isNull(); } - /// Returns the currently inferred upper bound on the runtime type. - QualType getType() const { return DynTy; } + QualType getType() const { return Ty; } bool operator==(const DynamicTypeInfo &RHS) const { - return DynTy == RHS.DynTy && CanBeASubClass == RHS.CanBeASubClass; + return Ty == RHS.Ty && CanBeASubClass == RHS.CanBeASubClass; } void Profile(llvm::FoldingSetNodeID &ID) const { - ID.Add(DynTy); + ID.Add(Ty); ID.AddBoolean(CanBeASubClass); } private: - QualType DynTy; + QualType Ty; bool CanBeASubClass; }; Index: clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp @@ -93,13 +93,12 @@ ProgramStateRef State = N->getState(); ProgramStateRef StatePrev = N->getFirstPred()->getState(); - DynamicTypeInfo TrackedType = getDynamicTypeInfo(State, Reg); - DynamicTypeInfo TrackedTypePrev = getDynamicTypeInfo(StatePrev, Reg); - if (!TrackedType.isValid()) + const DynamicTypeInfo *TrackedType = getDynamicTypeInfo(State, Reg); + const DynamicTypeInfo *TrackedTypePrev = getDynamicTypeInfo(StatePrev, Reg); + if (!TrackedType) return nullptr; - if (TrackedTypePrev.isValid() && - TrackedTypePrev.getType() == TrackedType.getType()) + if (TrackedTypePrev && TrackedTypePrev->getType() == TrackedType->getType()) return nullptr; // Retrieve the associated statement. @@ -112,7 +111,7 @@ SmallString<256> Buf; llvm::raw_svector_ostream OS(Buf); OS << "Type '"; - QualType::print(TrackedType.getType().getTypePtr(), Qualifiers(), OS, + QualType::print(TrackedType->getType().getTypePtr(), Qualifiers(), OS, LangOpts, llvm::Twine()); OS << "' is inferred from "; @@ -162,12 +161,11 @@ return; ProgramStateRef State = C.getState(); - DynamicTypeInfo DynTypeInfo = getDynamicTypeInfo(State, Region); - - if (!DynTypeInfo.isValid()) + const DynamicTypeInfo *DynTypeInfo = getDynamicTypeInfo(State, Region); + if (!DynTypeInfo) return; - QualType DynType = DynTypeInfo.getType(); + QualType DynType = DynTypeInfo->getType(); QualType StaticType = CE->getType(); const auto *DynObjCType = DynType->getAs(); @@ -192,7 +190,7 @@ if (ASTCtxt.canAssignObjCInterfaces(StaticObjCType, DynObjCType)) return; - if (DynTypeInfo.canBeASubClass() && + if (DynTypeInfo->canBeASubClass() && ASTCtxt.canAssignObjCInterfaces(DynObjCType, StaticObjCType)) return; Index: clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -224,7 +224,7 @@ const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); if (!RecReg) return; - DynamicTypeInfo RecDynType = getDynamicTypeInfo(State, RecReg); + const DynamicTypeInfo *RecDynType = getDynamicTypeInfo(State, RecReg); C.addTransition(setDynamicTypeInfo(State, RetReg, RecDynType)); break; } @@ -351,10 +351,15 @@ CastE->getType()->getAs(); if (!NewTy) return nullptr; - QualType OldDTy = getDynamicTypeInfo(C.getState(), ToR).getType(); + + QualType OldDTy; + if (const DynamicTypeInfo *DTI = getDynamicTypeInfo(C.getState(), ToR)) + OldDTy = DTI->getType(); + if (OldDTy.isNull()) { return NewTy; } + const ObjCObjectPointerType *OldTy = OldDTy->getAs(); if (!OldTy) Index: clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -1912,10 +1912,10 @@ const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, const MemRegion *Reg) { auto TI = getDynamicTypeInfo(State, Reg); - if (!TI.isValid()) + if (!TI) return nullptr; - auto Type = TI.getType(); + auto Type = TI->getType(); if (const auto *RefT = Type->getAs()) { Type = RefT->getPointeeType(); } Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -737,12 +737,12 @@ return {}; // Do we know anything about the type of 'this'? - DynamicTypeInfo DynType = getDynamicTypeInfo(getState(), R); - if (!DynType.isValid()) + const DynamicTypeInfo *DynType = getDynamicTypeInfo(getState(), R); + if (!DynType) return {}; // Is the type a C++ class? (This is mostly a defensive check.) - QualType RegionType = DynType.getType()->getPointeeType(); + QualType RegionType = DynType->getType()->getPointeeType(); assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer."); const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl(); @@ -771,7 +771,7 @@ // Does the decl that we found have an implementation? const FunctionDecl *Definition; if (!Result->hasBody(Definition)) { - if (!DynType.canBeASubClass()) + if (!DynType->canBeASubClass()) return AnyFunctionCall::getRuntimeDefinition(); return {}; } @@ -779,7 +779,7 @@ // We found a definition. If we're not sure that this devirtualization is // actually what will happen at runtime, make sure to provide the region so // that ExprEngine can decide what to do with it. - if (DynType.canBeASubClass()) + if (DynType->canBeASubClass()) return RuntimeDefinition(Definition, R->StripCasts()); return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr); } @@ -1208,15 +1208,15 @@ if (!Receiver) return {}; - DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver); - if (!DTI.isValid()) { + const DynamicTypeInfo *DTI = getDynamicTypeInfo(getState(), Receiver); + if (!DTI) { assert(isa(Receiver) && "Unhandled untyped region class!"); return {}; } - QualType DynType = DTI.getType(); - CanBeSubClassed = DTI.canBeASubClass(); + QualType DynType = DTI->getType(); + CanBeSubClassed = DTI->canBeASubClass(); ReceiverT = dyn_cast(DynType.getCanonicalType()); if (ReceiverT && CanBeSubClassed) Index: clang/lib/StaticAnalyzer/Core/DynamicType.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/DynamicType.cpp +++ clang/lib/StaticAnalyzer/Core/DynamicType.cpp @@ -37,23 +37,26 @@ namespace clang { namespace ento { -DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) { - MR = MR->StripCasts(); +static const MemRegion *getSimplifiedRegion(const MemRegion *MR) { + return MR->StripCasts(); +} + +const DynamicTypeInfo *getDynamicTypeInfo(ProgramStateRef State, + const MemRegion *MR) { + MR = getSimplifiedRegion(MR); // Look up the dynamic type in the GDM. if (const DynamicTypeInfo *DTI = State->get(MR)) - return *DTI; + return DTI; // Otherwise, fall back to what we know about the region. if (const auto *TR = dyn_cast(MR)) - return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false); + return new DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false); - if (const auto *SR = dyn_cast(MR)) { - SymbolRef Sym = SR->getSymbol(); - return DynamicTypeInfo(Sym->getType()); - } + if (const auto *SR = dyn_cast(MR)) + return new DynamicTypeInfo(SR->getSymbol()->getType()); - return {}; + return nullptr; } const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State, @@ -77,15 +80,20 @@ } ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, - DynamicTypeInfo NewTy) { - State = State->set(MR->StripCasts(), NewTy); + const DynamicTypeInfo *NewTy) { + assert((NewTy->getType()->isAnyPointerType() || + NewTy->getType()->isReferenceType()) && + "DynamicTypeInfo should always be a pointer."); + MR = getSimplifiedRegion(MR); + State = State->set(MR, *NewTy); assert(State); return State; } ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, QualType NewTy, bool CanBeSubClassed) { - return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed)); + return setDynamicTypeInfo(State, MR, + new DynamicTypeInfo(NewTy, CanBeSubClassed)); } ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State, @@ -154,7 +162,7 @@ const DynamicTypeInfo &DTI = I->second; Indent(Out, Space, IsDot) << "{ \"region\": \"" << MR << "\", \"dyn_type\": "; - if (!DTI.isValid()) { + if (DTI.getType().isNull()) { Out << "null"; } else { Out << '\"' << DTI.getType()->getPointeeType().getAsString()