1261991Sdim//== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=// 2239313Sdim// 3239313Sdim// The LLVM Compiler Infrastructure 4239313Sdim// 5239313Sdim// This file is distributed under the University of Illinois Open Source 6239313Sdim// License. See LICENSE.TXT for details. 7239313Sdim// 8239313Sdim//===----------------------------------------------------------------------===// 9239313Sdim// 10296417Sdim// This file contains two checkers. One helps the static analyzer core to track 11296417Sdim// types, the other does type inference on Obj-C generics and report type 12296417Sdim// errors. 13296417Sdim// 14296417Sdim// Dynamic Type Propagation: 15239313Sdim// This checker defines the rules for dynamic type gathering and propagation. 16239313Sdim// 17296417Sdim// Generics Checker for Objective-C: 18296417Sdim// This checker tries to find type errors that the compiler is not able to catch 19296417Sdim// due to the implicit conversions that were introduced for backward 20296417Sdim// compatibility. 21296417Sdim// 22239313Sdim//===----------------------------------------------------------------------===// 23239313Sdim 24239313Sdim#include "ClangSACheckers.h" 25296417Sdim#include "clang/AST/RecursiveASTVisitor.h" 26249423Sdim#include "clang/Basic/Builtins.h" 27249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 28239313Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 29239313Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 30239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 31296417Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" 32239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 33239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 34239313Sdim 35239313Sdimusing namespace clang; 36239313Sdimusing namespace ento; 37239313Sdim 38296417Sdim// ProgramState trait - The type inflation is tracked by DynamicTypeMap. This is 39296417Sdim// an auxiliary map that tracks more information about generic types, because in 40296417Sdim// some cases the most derived type is not the most informative one about the 41296417Sdim// type parameters. This types that are stored for each symbol in this map must 42296417Sdim// be specialized. 43296417Sdim// TODO: In some case the type stored in this map is exactly the same that is 44296417Sdim// stored in DynamicTypeMap. We should no store duplicated information in those 45296417Sdim// cases. 46296417SdimREGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, 47296417Sdim const ObjCObjectPointerType *) 48296417Sdim 49239313Sdimnamespace { 50239313Sdimclass DynamicTypePropagation: 51239462Sdim public Checker< check::PreCall, 52239462Sdim check::PostCall, 53296417Sdim check::DeadSymbols, 54296417Sdim check::PostStmt<CastExpr>, 55296417Sdim check::PostStmt<CXXNewExpr>, 56296417Sdim check::PreObjCMessage, 57296417Sdim check::PostObjCMessage > { 58239313Sdim const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 59239313Sdim CheckerContext &C) const; 60239313Sdim 61239313Sdim /// \brief Return a better dynamic type if one can be derived from the cast. 62239313Sdim const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 63239313Sdim CheckerContext &C) const; 64296417Sdim 65296417Sdim ExplodedNode *dynamicTypePropagationOnCasts(const CastExpr *CE, 66296417Sdim ProgramStateRef &State, 67296417Sdim CheckerContext &C) const; 68296417Sdim 69296417Sdim mutable std::unique_ptr<BugType> ObjCGenericsBugType; 70296417Sdim void initBugType() const { 71296417Sdim if (!ObjCGenericsBugType) 72296417Sdim ObjCGenericsBugType.reset( 73296417Sdim new BugType(this, "Generics", categories::CoreFoundationObjectiveC)); 74296417Sdim } 75296417Sdim 76296417Sdim class GenericsBugVisitor : public BugReporterVisitorImpl<GenericsBugVisitor> { 77296417Sdim public: 78296417Sdim GenericsBugVisitor(SymbolRef S) : Sym(S) {} 79296417Sdim 80296417Sdim void Profile(llvm::FoldingSetNodeID &ID) const override { 81296417Sdim static int X = 0; 82296417Sdim ID.AddPointer(&X); 83296417Sdim ID.AddPointer(Sym); 84296417Sdim } 85296417Sdim 86296417Sdim PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 87296417Sdim const ExplodedNode *PrevN, 88296417Sdim BugReporterContext &BRC, 89296417Sdim BugReport &BR) override; 90296417Sdim 91296417Sdim private: 92296417Sdim // The tracked symbol. 93296417Sdim SymbolRef Sym; 94296417Sdim }; 95296417Sdim 96296417Sdim void reportGenericsBug(const ObjCObjectPointerType *From, 97296417Sdim const ObjCObjectPointerType *To, ExplodedNode *N, 98296417Sdim SymbolRef Sym, CheckerContext &C, 99296417Sdim const Stmt *ReportedNode = nullptr) const; 100239313Sdimpublic: 101239462Sdim void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 102239313Sdim void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 103296417Sdim void checkPostStmt(const CastExpr *CastE, CheckerContext &C) const; 104251662Sdim void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; 105296417Sdim void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 106296417Sdim void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 107296417Sdim void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 108296417Sdim 109296417Sdim /// This value is set to true, when the Generics checker is turned on. 110296417Sdim DefaultBool CheckGenerics; 111239313Sdim}; 112239313Sdim} 113239313Sdim 114296417Sdimvoid DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR, 115296417Sdim CheckerContext &C) const { 116296417Sdim ProgramStateRef State = C.getState(); 117296417Sdim DynamicTypeMapImpl TypeMap = State->get<DynamicTypeMap>(); 118296417Sdim for (DynamicTypeMapImpl::iterator I = TypeMap.begin(), E = TypeMap.end(); 119296417Sdim I != E; ++I) { 120296417Sdim if (!SR.isLiveRegion(I->first)) { 121296417Sdim State = State->remove<DynamicTypeMap>(I->first); 122296417Sdim } 123296417Sdim } 124296417Sdim 125296417Sdim if (!SR.hasDeadSymbols()) { 126296417Sdim C.addTransition(State); 127296417Sdim return; 128296417Sdim } 129296417Sdim 130296417Sdim MostSpecializedTypeArgsMapTy TyArgMap = 131296417Sdim State->get<MostSpecializedTypeArgsMap>(); 132296417Sdim for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(), 133296417Sdim E = TyArgMap.end(); 134296417Sdim I != E; ++I) { 135296417Sdim if (SR.isDead(I->first)) { 136296417Sdim State = State->remove<MostSpecializedTypeArgsMap>(I->first); 137296417Sdim } 138296417Sdim } 139296417Sdim 140296417Sdim C.addTransition(State); 141296417Sdim} 142296417Sdim 143239462Sdimstatic void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, 144239462Sdim CheckerContext &C) { 145239462Sdim assert(Region); 146239462Sdim assert(MD); 147239462Sdim 148239462Sdim ASTContext &Ctx = C.getASTContext(); 149239462Sdim QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); 150239462Sdim 151239462Sdim ProgramStateRef State = C.getState(); 152296417Sdim State = setDynamicTypeInfo(State, Region, Ty, /*CanBeSubclass=*/false); 153239462Sdim C.addTransition(State); 154239462Sdim return; 155239462Sdim} 156239462Sdim 157239462Sdimvoid DynamicTypePropagation::checkPreCall(const CallEvent &Call, 158239462Sdim CheckerContext &C) const { 159239462Sdim if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 160239462Sdim // C++11 [class.cdtor]p4: When a virtual function is called directly or 161239462Sdim // indirectly from a constructor or from a destructor, including during 162261991Sdim // the construction or destruction of the class's non-static data members, 163239462Sdim // and the object to which the call applies is the object under 164239462Sdim // construction or destruction, the function called is the final overrider 165239462Sdim // in the constructor's or destructor's class and not one overriding it in 166239462Sdim // a more-derived class. 167239462Sdim 168239462Sdim switch (Ctor->getOriginExpr()->getConstructionKind()) { 169239462Sdim case CXXConstructExpr::CK_Complete: 170239462Sdim case CXXConstructExpr::CK_Delegating: 171239462Sdim // No additional type info necessary. 172239462Sdim return; 173239462Sdim case CXXConstructExpr::CK_NonVirtualBase: 174239462Sdim case CXXConstructExpr::CK_VirtualBase: 175239462Sdim if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) 176239462Sdim recordFixedType(Target, Ctor->getDecl(), C); 177239462Sdim return; 178239462Sdim } 179239462Sdim 180239462Sdim return; 181239462Sdim } 182239462Sdim 183239462Sdim if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { 184239462Sdim // C++11 [class.cdtor]p4 (see above) 185243830Sdim if (!Dtor->isBaseDestructor()) 186243830Sdim return; 187239462Sdim 188239462Sdim const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 189239462Sdim if (!Target) 190239462Sdim return; 191239462Sdim 192243830Sdim const Decl *D = Dtor->getDecl(); 193239462Sdim if (!D) 194239462Sdim return; 195239462Sdim 196239462Sdim recordFixedType(Target, cast<CXXDestructorDecl>(D), C); 197239462Sdim return; 198239462Sdim } 199239462Sdim} 200239462Sdim 201239313Sdimvoid DynamicTypePropagation::checkPostCall(const CallEvent &Call, 202239313Sdim CheckerContext &C) const { 203239313Sdim // We can obtain perfect type info for return values from some calls. 204239313Sdim if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 205239313Sdim 206239313Sdim // Get the returned value if it's a region. 207243830Sdim const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); 208239313Sdim if (!RetReg) 209239313Sdim return; 210239313Sdim 211239313Sdim ProgramStateRef State = C.getState(); 212249423Sdim const ObjCMethodDecl *D = Msg->getDecl(); 213296417Sdim 214249423Sdim if (D && D->hasRelatedResultType()) { 215249423Sdim switch (Msg->getMethodFamily()) { 216249423Sdim default: 217249423Sdim break; 218239313Sdim 219249423Sdim // We assume that the type of the object returned by alloc and new are the 220249423Sdim // pointer to the object of the class specified in the receiver of the 221249423Sdim // message. 222249423Sdim case OMF_alloc: 223249423Sdim case OMF_new: { 224249423Sdim // Get the type of object that will get created. 225249423Sdim const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 226249423Sdim const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 227249423Sdim if (!ObjTy) 228249423Sdim return; 229249423Sdim QualType DynResTy = 230239313Sdim C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 231296417Sdim C.addTransition(setDynamicTypeInfo(State, RetReg, DynResTy, false)); 232249423Sdim break; 233249423Sdim } 234249423Sdim case OMF_init: { 235249423Sdim // Assume, the result of the init method has the same dynamic type as 236249423Sdim // the receiver and propagate the dynamic type info. 237249423Sdim const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 238249423Sdim if (!RecReg) 239249423Sdim return; 240296417Sdim DynamicTypeInfo RecDynType = getDynamicTypeInfo(State, RecReg); 241296417Sdim C.addTransition(setDynamicTypeInfo(State, RetReg, RecDynType)); 242249423Sdim break; 243249423Sdim } 244249423Sdim } 245239313Sdim } 246239462Sdim return; 247239313Sdim } 248239462Sdim 249239462Sdim if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 250239462Sdim // We may need to undo the effects of our pre-call check. 251239462Sdim switch (Ctor->getOriginExpr()->getConstructionKind()) { 252239462Sdim case CXXConstructExpr::CK_Complete: 253239462Sdim case CXXConstructExpr::CK_Delegating: 254239462Sdim // No additional work necessary. 255239462Sdim // Note: This will leave behind the actual type of the object for 256239462Sdim // complete constructors, but arguably that's a good thing, since it 257239462Sdim // means the dynamic type info will be correct even for objects 258239462Sdim // constructed with operator new. 259239462Sdim return; 260239462Sdim case CXXConstructExpr::CK_NonVirtualBase: 261239462Sdim case CXXConstructExpr::CK_VirtualBase: 262239462Sdim if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { 263239462Sdim // We just finished a base constructor. Now we can use the subclass's 264239462Sdim // type when resolving virtual calls. 265239462Sdim const Decl *D = C.getLocationContext()->getDecl(); 266239462Sdim recordFixedType(Target, cast<CXXConstructorDecl>(D), C); 267239462Sdim } 268239462Sdim return; 269239462Sdim } 270239462Sdim } 271239313Sdim} 272239313Sdim 273296417Sdim/// TODO: Handle explicit casts. 274296417Sdim/// Handle C++ casts. 275296417Sdim/// 276296417Sdim/// Precondition: the cast is between ObjCObjectPointers. 277296417SdimExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts( 278296417Sdim const CastExpr *CE, ProgramStateRef &State, CheckerContext &C) const { 279296417Sdim // We only track type info for regions. 280296417Sdim const MemRegion *ToR = C.getSVal(CE).getAsRegion(); 281239313Sdim if (!ToR) 282296417Sdim return C.getPredecessor(); 283239313Sdim 284296417Sdim if (isa<ExplicitCastExpr>(CE)) 285296417Sdim return C.getPredecessor(); 286296417Sdim 287296417Sdim if (const Type *NewTy = getBetterObjCType(CE, C)) { 288296417Sdim State = setDynamicTypeInfo(State, ToR, QualType(NewTy, 0)); 289296417Sdim return C.addTransition(State); 290239313Sdim } 291296417Sdim return C.getPredecessor(); 292239313Sdim} 293239313Sdim 294251662Sdimvoid DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, 295251662Sdim CheckerContext &C) const { 296251662Sdim if (NewE->isArray()) 297251662Sdim return; 298251662Sdim 299251662Sdim // We only track dynamic type info for regions. 300251662Sdim const MemRegion *MR = C.getSVal(NewE).getAsRegion(); 301251662Sdim if (!MR) 302251662Sdim return; 303296417Sdim 304296417Sdim C.addTransition(setDynamicTypeInfo(C.getState(), MR, NewE->getType(), 305296417Sdim /*CanBeSubclass=*/false)); 306251662Sdim} 307251662Sdim 308239313Sdimconst ObjCObjectType * 309239313SdimDynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 310239313Sdim CheckerContext &C) const { 311239313Sdim if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 312239313Sdim if (const ObjCObjectType *ObjTy 313239313Sdim = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 314239313Sdim return ObjTy; 315239313Sdim } 316239313Sdim 317239313Sdim if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 318239313Sdim if (const ObjCObjectType *ObjTy 319239313Sdim = MsgE->getSuperType()->getAs<ObjCObjectType>()) 320239313Sdim return ObjTy; 321239313Sdim } 322239313Sdim 323239313Sdim const Expr *RecE = MsgE->getInstanceReceiver(); 324239313Sdim if (!RecE) 325276479Sdim return nullptr; 326239313Sdim 327239313Sdim RecE= RecE->IgnoreParenImpCasts(); 328239313Sdim if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 329239313Sdim const StackFrameContext *SFCtx = C.getStackFrame(); 330239313Sdim // Are we calling [self alloc]? If this is self, get the type of the 331239313Sdim // enclosing ObjC class. 332239313Sdim if (DRE->getDecl() == SFCtx->getSelfDecl()) { 333239313Sdim if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 334239313Sdim if (const ObjCObjectType *ObjTy = 335239313Sdim dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 336239313Sdim return ObjTy; 337239313Sdim } 338239313Sdim } 339276479Sdim return nullptr; 340239313Sdim} 341239313Sdim 342239313Sdim// Return a better dynamic type if one can be derived from the cast. 343239313Sdim// Compare the current dynamic type of the region and the new type to which we 344239313Sdim// are casting. If the new type is lower in the inheritance hierarchy, pick it. 345239313Sdimconst ObjCObjectPointerType * 346239313SdimDynamicTypePropagation::getBetterObjCType(const Expr *CastE, 347239313Sdim CheckerContext &C) const { 348239313Sdim const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 349239313Sdim assert(ToR); 350239313Sdim 351239313Sdim // Get the old and new types. 352239313Sdim const ObjCObjectPointerType *NewTy = 353239313Sdim CastE->getType()->getAs<ObjCObjectPointerType>(); 354239313Sdim if (!NewTy) 355276479Sdim return nullptr; 356296417Sdim QualType OldDTy = getDynamicTypeInfo(C.getState(), ToR).getType(); 357239313Sdim if (OldDTy.isNull()) { 358239313Sdim return NewTy; 359239313Sdim } 360239313Sdim const ObjCObjectPointerType *OldTy = 361239313Sdim OldDTy->getAs<ObjCObjectPointerType>(); 362239313Sdim if (!OldTy) 363276479Sdim return nullptr; 364239313Sdim 365239313Sdim // Id the old type is 'id', the new one is more precise. 366239313Sdim if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 367239313Sdim return NewTy; 368239313Sdim 369239313Sdim // Return new if it's a subclass of old. 370239313Sdim const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 371239313Sdim const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 372239313Sdim if (ToI && FromI && FromI->isSuperClassOf(ToI)) 373239313Sdim return NewTy; 374239313Sdim 375276479Sdim return nullptr; 376239313Sdim} 377239313Sdim 378296417Sdimstatic const ObjCObjectPointerType *getMostInformativeDerivedClassImpl( 379296417Sdim const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, 380296417Sdim const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C) { 381296417Sdim // Checking if from and to are the same classes modulo specialization. 382296417Sdim if (From->getInterfaceDecl()->getCanonicalDecl() == 383296417Sdim To->getInterfaceDecl()->getCanonicalDecl()) { 384296417Sdim if (To->isSpecialized()) { 385296417Sdim assert(MostInformativeCandidate->isSpecialized()); 386296417Sdim return MostInformativeCandidate; 387296417Sdim } 388296417Sdim return From; 389296417Sdim } 390296417Sdim const auto *SuperOfTo = 391296417Sdim To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>(); 392296417Sdim assert(SuperOfTo); 393296417Sdim QualType SuperPtrOfToQual = 394296417Sdim C.getObjCObjectPointerType(QualType(SuperOfTo, 0)); 395296417Sdim const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>(); 396296417Sdim if (To->isUnspecialized()) 397296417Sdim return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo, 398296417Sdim C); 399296417Sdim else 400296417Sdim return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, 401296417Sdim MostInformativeCandidate, C); 402296417Sdim} 403296417Sdim 404296417Sdim/// A downcast may loose specialization information. E. g.: 405296417Sdim/// MutableMap<T, U> : Map 406296417Sdim/// The downcast to MutableMap looses the information about the types of the 407296417Sdim/// Map (due to the type parameters are not being forwarded to Map), and in 408296417Sdim/// general there is no way to recover that information from the 409296417Sdim/// declaration. In order to have to most information, lets find the most 410296417Sdim/// derived type that has all the type parameters forwarded. 411296417Sdim/// 412296417Sdim/// Get the a subclass of \p From (which has a lower bound \p To) that do not 413296417Sdim/// loose information about type parameters. \p To has to be a subclass of 414296417Sdim/// \p From. From has to be specialized. 415296417Sdimstatic const ObjCObjectPointerType * 416296417SdimgetMostInformativeDerivedClass(const ObjCObjectPointerType *From, 417296417Sdim const ObjCObjectPointerType *To, ASTContext &C) { 418296417Sdim return getMostInformativeDerivedClassImpl(From, To, To, C); 419296417Sdim} 420296417Sdim 421296417Sdim/// Inputs: 422296417Sdim/// \param StaticLowerBound Static lower bound for a symbol. The dynamic lower 423296417Sdim/// bound might be the subclass of this type. 424296417Sdim/// \param StaticUpperBound A static upper bound for a symbol. 425296417Sdim/// \p StaticLowerBound expected to be the subclass of \p StaticUpperBound. 426296417Sdim/// \param Current The type that was inferred for a symbol in a previous 427296417Sdim/// context. Might be null when this is the first time that inference happens. 428296417Sdim/// Precondition: 429296417Sdim/// \p StaticLowerBound or \p StaticUpperBound is specialized. If \p Current 430296417Sdim/// is not null, it is specialized. 431296417Sdim/// Possible cases: 432296417Sdim/// (1) The \p Current is null and \p StaticLowerBound <: \p StaticUpperBound 433296417Sdim/// (2) \p StaticLowerBound <: \p Current <: \p StaticUpperBound 434296417Sdim/// (3) \p Current <: \p StaticLowerBound <: \p StaticUpperBound 435296417Sdim/// (4) \p StaticLowerBound <: \p StaticUpperBound <: \p Current 436296417Sdim/// Effect: 437296417Sdim/// Use getMostInformativeDerivedClass with the upper and lower bound of the 438296417Sdim/// set {\p StaticLowerBound, \p Current, \p StaticUpperBound}. The computed 439296417Sdim/// lower bound must be specialized. If the result differs from \p Current or 440296417Sdim/// \p Current is null, store the result. 441296417Sdimstatic bool 442296417SdimstoreWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, 443296417Sdim const ObjCObjectPointerType *const *Current, 444296417Sdim const ObjCObjectPointerType *StaticLowerBound, 445296417Sdim const ObjCObjectPointerType *StaticUpperBound, 446296417Sdim ASTContext &C) { 447296417Sdim // Precondition 448296417Sdim assert(StaticUpperBound->isSpecialized() || 449296417Sdim StaticLowerBound->isSpecialized()); 450296417Sdim assert(!Current || (*Current)->isSpecialized()); 451296417Sdim 452296417Sdim // Case (1) 453296417Sdim if (!Current) { 454296417Sdim if (StaticUpperBound->isUnspecialized()) { 455296417Sdim State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound); 456296417Sdim return true; 457296417Sdim } 458296417Sdim // Upper bound is specialized. 459296417Sdim const ObjCObjectPointerType *WithMostInfo = 460296417Sdim getMostInformativeDerivedClass(StaticUpperBound, StaticLowerBound, C); 461296417Sdim State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); 462296417Sdim return true; 463296417Sdim } 464296417Sdim 465296417Sdim // Case (3) 466296417Sdim if (C.canAssignObjCInterfaces(StaticLowerBound, *Current)) { 467296417Sdim return false; 468296417Sdim } 469296417Sdim 470296417Sdim // Case (4) 471296417Sdim if (C.canAssignObjCInterfaces(*Current, StaticUpperBound)) { 472296417Sdim // The type arguments might not be forwarded at any point of inheritance. 473296417Sdim const ObjCObjectPointerType *WithMostInfo = 474296417Sdim getMostInformativeDerivedClass(*Current, StaticUpperBound, C); 475296417Sdim WithMostInfo = 476296417Sdim getMostInformativeDerivedClass(WithMostInfo, StaticLowerBound, C); 477296417Sdim if (WithMostInfo == *Current) 478296417Sdim return false; 479296417Sdim State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); 480296417Sdim return true; 481296417Sdim } 482296417Sdim 483296417Sdim // Case (2) 484296417Sdim const ObjCObjectPointerType *WithMostInfo = 485296417Sdim getMostInformativeDerivedClass(*Current, StaticLowerBound, C); 486296417Sdim if (WithMostInfo != *Current) { 487296417Sdim State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); 488296417Sdim return true; 489296417Sdim } 490296417Sdim 491296417Sdim return false; 492296417Sdim} 493296417Sdim 494296417Sdim/// Type inference based on static type information that is available for the 495296417Sdim/// cast and the tracked type information for the given symbol. When the tracked 496296417Sdim/// symbol and the destination type of the cast are unrelated, report an error. 497296417Sdimvoid DynamicTypePropagation::checkPostStmt(const CastExpr *CE, 498296417Sdim CheckerContext &C) const { 499296417Sdim if (CE->getCastKind() != CK_BitCast) 500296417Sdim return; 501296417Sdim 502296417Sdim QualType OriginType = CE->getSubExpr()->getType(); 503296417Sdim QualType DestType = CE->getType(); 504296417Sdim 505296417Sdim const auto *OrigObjectPtrType = OriginType->getAs<ObjCObjectPointerType>(); 506296417Sdim const auto *DestObjectPtrType = DestType->getAs<ObjCObjectPointerType>(); 507296417Sdim 508296417Sdim if (!OrigObjectPtrType || !DestObjectPtrType) 509296417Sdim return; 510296417Sdim 511296417Sdim ProgramStateRef State = C.getState(); 512296417Sdim ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C); 513296417Sdim 514296417Sdim ASTContext &ASTCtxt = C.getASTContext(); 515296417Sdim 516296417Sdim // This checker detects the subtyping relationships using the assignment 517296417Sdim // rules. In order to be able to do this the kindofness must be stripped 518296417Sdim // first. The checker treats every type as kindof type anyways: when the 519296417Sdim // tracked type is the subtype of the static type it tries to look up the 520296417Sdim // methods in the tracked type first. 521296417Sdim OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); 522296417Sdim DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); 523296417Sdim 524296417Sdim // TODO: erase tracked information when there is a cast to unrelated type 525296417Sdim // and everything is unspecialized statically. 526296417Sdim if (OrigObjectPtrType->isUnspecialized() && 527296417Sdim DestObjectPtrType->isUnspecialized()) 528296417Sdim return; 529296417Sdim 530296417Sdim SymbolRef Sym = State->getSVal(CE, C.getLocationContext()).getAsSymbol(); 531296417Sdim if (!Sym) 532296417Sdim return; 533296417Sdim 534296417Sdim // Check which assignments are legal. 535296417Sdim bool OrigToDest = 536296417Sdim ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType); 537296417Sdim bool DestToOrig = 538296417Sdim ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); 539296417Sdim const ObjCObjectPointerType *const *TrackedType = 540296417Sdim State->get<MostSpecializedTypeArgsMap>(Sym); 541296417Sdim 542296417Sdim // Downcasts and upcasts handled in an uniform way regardless of being 543296417Sdim // explicit. Explicit casts however can happen between mismatched types. 544296417Sdim if (isa<ExplicitCastExpr>(CE) && !OrigToDest && !DestToOrig) { 545296417Sdim // Mismatched types. If the DestType specialized, store it. Forget the 546296417Sdim // tracked type otherwise. 547296417Sdim if (DestObjectPtrType->isSpecialized()) { 548296417Sdim State = State->set<MostSpecializedTypeArgsMap>(Sym, DestObjectPtrType); 549296417Sdim C.addTransition(State, AfterTypeProp); 550296417Sdim } else if (TrackedType) { 551296417Sdim State = State->remove<MostSpecializedTypeArgsMap>(Sym); 552296417Sdim C.addTransition(State, AfterTypeProp); 553296417Sdim } 554296417Sdim return; 555296417Sdim } 556296417Sdim 557296417Sdim // The tracked type should be the sub or super class of the static destination 558296417Sdim // type. When an (implicit) upcast or a downcast happens according to static 559296417Sdim // types, and there is no subtyping relationship between the tracked and the 560296417Sdim // static destination types, it indicates an error. 561296417Sdim if (TrackedType && 562296417Sdim !ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, *TrackedType) && 563296417Sdim !ASTCtxt.canAssignObjCInterfaces(*TrackedType, DestObjectPtrType)) { 564296417Sdim static CheckerProgramPointTag IllegalConv(this, "IllegalConversion"); 565296417Sdim ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv); 566296417Sdim reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C); 567296417Sdim return; 568296417Sdim } 569296417Sdim 570296417Sdim // Handle downcasts and upcasts. 571296417Sdim 572296417Sdim const ObjCObjectPointerType *LowerBound = DestObjectPtrType; 573296417Sdim const ObjCObjectPointerType *UpperBound = OrigObjectPtrType; 574296417Sdim if (OrigToDest && !DestToOrig) 575296417Sdim std::swap(LowerBound, UpperBound); 576296417Sdim 577296417Sdim // The id type is not a real bound. Eliminate it. 578296417Sdim LowerBound = LowerBound->isObjCIdType() ? UpperBound : LowerBound; 579296417Sdim UpperBound = UpperBound->isObjCIdType() ? LowerBound : UpperBound; 580296417Sdim 581296417Sdim if (storeWhenMoreInformative(State, Sym, TrackedType, LowerBound, UpperBound, 582296417Sdim ASTCtxt)) { 583296417Sdim C.addTransition(State, AfterTypeProp); 584296417Sdim } 585296417Sdim} 586296417Sdim 587296417Sdimstatic const Expr *stripCastsAndSugar(const Expr *E) { 588296417Sdim E = E->IgnoreParenImpCasts(); 589296417Sdim if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) 590296417Sdim E = POE->getSyntacticForm()->IgnoreParenImpCasts(); 591296417Sdim if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) 592296417Sdim E = OVE->getSourceExpr()->IgnoreParenImpCasts(); 593296417Sdim return E; 594296417Sdim} 595296417Sdim 596296417Sdimstatic bool isObjCTypeParamDependent(QualType Type) { 597296417Sdim // It is illegal to typedef parameterized types inside an interface. Therfore 598296417Sdim // an Objective-C type can only be dependent on a type parameter when the type 599296417Sdim // parameter structurally present in the type itself. 600296417Sdim class IsObjCTypeParamDependentTypeVisitor 601296417Sdim : public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> { 602296417Sdim public: 603296417Sdim IsObjCTypeParamDependentTypeVisitor() : Result(false) {} 604296417Sdim bool VisitTypedefType(const TypedefType *Type) { 605296417Sdim if (isa<ObjCTypeParamDecl>(Type->getDecl())) { 606296417Sdim Result = true; 607296417Sdim return false; 608296417Sdim } 609296417Sdim return true; 610296417Sdim } 611296417Sdim 612296417Sdim bool Result; 613296417Sdim }; 614296417Sdim 615296417Sdim IsObjCTypeParamDependentTypeVisitor Visitor; 616296417Sdim Visitor.TraverseType(Type); 617296417Sdim return Visitor.Result; 618296417Sdim} 619296417Sdim 620296417Sdim/// A method might not be available in the interface indicated by the static 621296417Sdim/// type. However it might be available in the tracked type. In order to 622296417Sdim/// properly substitute the type parameters we need the declaration context of 623296417Sdim/// the method. The more specialized the enclosing class of the method is, the 624296417Sdim/// more likely that the parameter substitution will be successful. 625296417Sdimstatic const ObjCMethodDecl * 626296417SdimfindMethodDecl(const ObjCMessageExpr *MessageExpr, 627296417Sdim const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt) { 628296417Sdim const ObjCMethodDecl *Method = nullptr; 629296417Sdim 630296417Sdim QualType ReceiverType = MessageExpr->getReceiverType(); 631296417Sdim const auto *ReceiverObjectPtrType = 632296417Sdim ReceiverType->getAs<ObjCObjectPointerType>(); 633296417Sdim 634296417Sdim // Do this "devirtualization" on instance and class methods only. Trust the 635296417Sdim // static type on super and super class calls. 636296417Sdim if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Instance || 637296417Sdim MessageExpr->getReceiverKind() == ObjCMessageExpr::Class) { 638296417Sdim // When the receiver type is id, Class, or some super class of the tracked 639296417Sdim // type, look up the method in the tracked type, not in the receiver type. 640296417Sdim // This way we preserve more information. 641296417Sdim if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType() || 642296417Sdim ASTCtxt.canAssignObjCInterfaces(ReceiverObjectPtrType, TrackedType)) { 643296417Sdim const ObjCInterfaceDecl *InterfaceDecl = TrackedType->getInterfaceDecl(); 644296417Sdim // The method might not be found. 645296417Sdim Selector Sel = MessageExpr->getSelector(); 646296417Sdim Method = InterfaceDecl->lookupInstanceMethod(Sel); 647296417Sdim if (!Method) 648296417Sdim Method = InterfaceDecl->lookupClassMethod(Sel); 649296417Sdim } 650296417Sdim } 651296417Sdim 652296417Sdim // Fallback to statick method lookup when the one based on the tracked type 653296417Sdim // failed. 654296417Sdim return Method ? Method : MessageExpr->getMethodDecl(); 655296417Sdim} 656296417Sdim 657296417Sdim/// Get the returned ObjCObjectPointerType by a method based on the tracked type 658296417Sdim/// information, or null pointer when the returned type is not an 659296417Sdim/// ObjCObjectPointerType. 660296417Sdimstatic QualType getReturnTypeForMethod( 661296417Sdim const ObjCMethodDecl *Method, ArrayRef<QualType> TypeArgs, 662296417Sdim const ObjCObjectPointerType *SelfType, ASTContext &C) { 663296417Sdim QualType StaticResultType = Method->getReturnType(); 664296417Sdim 665296417Sdim // Is the return type declared as instance type? 666296417Sdim if (StaticResultType == C.getObjCInstanceType()) 667296417Sdim return QualType(SelfType, 0); 668296417Sdim 669296417Sdim // Check whether the result type depends on a type parameter. 670296417Sdim if (!isObjCTypeParamDependent(StaticResultType)) 671296417Sdim return QualType(); 672296417Sdim 673296417Sdim QualType ResultType = StaticResultType.substObjCTypeArgs( 674296417Sdim C, TypeArgs, ObjCSubstitutionContext::Result); 675296417Sdim 676296417Sdim return ResultType; 677296417Sdim} 678296417Sdim 679296417Sdim/// When the receiver has a tracked type, use that type to validate the 680296417Sdim/// argumments of the message expression and the return value. 681296417Sdimvoid DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, 682296417Sdim CheckerContext &C) const { 683296417Sdim ProgramStateRef State = C.getState(); 684296417Sdim SymbolRef Sym = M.getReceiverSVal().getAsSymbol(); 685296417Sdim if (!Sym) 686296417Sdim return; 687296417Sdim 688296417Sdim const ObjCObjectPointerType *const *TrackedType = 689296417Sdim State->get<MostSpecializedTypeArgsMap>(Sym); 690296417Sdim if (!TrackedType) 691296417Sdim return; 692296417Sdim 693296417Sdim // Get the type arguments from tracked type and substitute type arguments 694296417Sdim // before do the semantic check. 695296417Sdim 696296417Sdim ASTContext &ASTCtxt = C.getASTContext(); 697296417Sdim const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); 698296417Sdim const ObjCMethodDecl *Method = 699296417Sdim findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); 700296417Sdim 701296417Sdim // It is possible to call non-existent methods in Obj-C. 702296417Sdim if (!Method) 703296417Sdim return; 704296417Sdim 705296417Sdim Optional<ArrayRef<QualType>> TypeArgs = 706296417Sdim (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); 707296417Sdim // This case might happen when there is an unspecialized override of a 708296417Sdim // specialized method. 709296417Sdim if (!TypeArgs) 710296417Sdim return; 711296417Sdim 712296417Sdim for (unsigned i = 0; i < Method->param_size(); i++) { 713296417Sdim const Expr *Arg = MessageExpr->getArg(i); 714296417Sdim const ParmVarDecl *Param = Method->parameters()[i]; 715296417Sdim 716296417Sdim QualType OrigParamType = Param->getType(); 717296417Sdim if (!isObjCTypeParamDependent(OrigParamType)) 718296417Sdim continue; 719296417Sdim 720296417Sdim QualType ParamType = OrigParamType.substObjCTypeArgs( 721296417Sdim ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter); 722296417Sdim // Check if it can be assigned 723296417Sdim const auto *ParamObjectPtrType = ParamType->getAs<ObjCObjectPointerType>(); 724296417Sdim const auto *ArgObjectPtrType = 725296417Sdim stripCastsAndSugar(Arg)->getType()->getAs<ObjCObjectPointerType>(); 726296417Sdim if (!ParamObjectPtrType || !ArgObjectPtrType) 727296417Sdim continue; 728296417Sdim 729296417Sdim // Check if we have more concrete tracked type that is not a super type of 730296417Sdim // the static argument type. 731296417Sdim SVal ArgSVal = M.getArgSVal(i); 732296417Sdim SymbolRef ArgSym = ArgSVal.getAsSymbol(); 733296417Sdim if (ArgSym) { 734296417Sdim const ObjCObjectPointerType *const *TrackedArgType = 735296417Sdim State->get<MostSpecializedTypeArgsMap>(ArgSym); 736296417Sdim if (TrackedArgType && 737296417Sdim ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) { 738296417Sdim ArgObjectPtrType = *TrackedArgType; 739296417Sdim } 740296417Sdim } 741296417Sdim 742296417Sdim // Warn when argument is incompatible with the parameter. 743296417Sdim if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType, 744296417Sdim ArgObjectPtrType)) { 745296417Sdim static CheckerProgramPointTag Tag(this, "ArgTypeMismatch"); 746296417Sdim ExplodedNode *N = C.addTransition(State, &Tag); 747296417Sdim reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg); 748296417Sdim return; 749296417Sdim } 750296417Sdim } 751296417Sdim} 752296417Sdim 753296417Sdim/// This callback is used to infer the types for Class variables. This info is 754296417Sdim/// used later to validate messages that sent to classes. Class variables are 755296417Sdim/// initialized with by invoking the 'class' method on a class. 756296417Sdim/// This method is also used to infer the type information for the return 757296417Sdim/// types. 758296417Sdim// TODO: right now it only tracks generic types. Extend this to track every 759296417Sdim// type in the DynamicTypeMap and diagnose type errors! 760296417Sdimvoid DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M, 761296417Sdim CheckerContext &C) const { 762296417Sdim const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); 763296417Sdim 764296417Sdim SymbolRef RetSym = M.getReturnValue().getAsSymbol(); 765296417Sdim if (!RetSym) 766296417Sdim return; 767296417Sdim 768296417Sdim Selector Sel = MessageExpr->getSelector(); 769296417Sdim ProgramStateRef State = C.getState(); 770296417Sdim // Inference for class variables. 771296417Sdim // We are only interested in cases where the class method is invoked on a 772296417Sdim // class. This method is provided by the runtime and available on all classes. 773296417Sdim if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class && 774296417Sdim Sel.getAsString() == "class") { 775296417Sdim 776296417Sdim QualType ReceiverType = MessageExpr->getClassReceiver(); 777296417Sdim const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>(); 778296417Sdim QualType ReceiverClassPointerType = 779296417Sdim C.getASTContext().getObjCObjectPointerType( 780296417Sdim QualType(ReceiverClassType, 0)); 781296417Sdim 782296417Sdim if (!ReceiverClassType->isSpecialized()) 783296417Sdim return; 784296417Sdim const auto *InferredType = 785296417Sdim ReceiverClassPointerType->getAs<ObjCObjectPointerType>(); 786296417Sdim assert(InferredType); 787296417Sdim 788296417Sdim State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType); 789296417Sdim C.addTransition(State); 790296417Sdim return; 791296417Sdim } 792296417Sdim 793296417Sdim // Tracking for return types. 794296417Sdim SymbolRef RecSym = M.getReceiverSVal().getAsSymbol(); 795296417Sdim if (!RecSym) 796296417Sdim return; 797296417Sdim 798296417Sdim const ObjCObjectPointerType *const *TrackedType = 799296417Sdim State->get<MostSpecializedTypeArgsMap>(RecSym); 800296417Sdim if (!TrackedType) 801296417Sdim return; 802296417Sdim 803296417Sdim ASTContext &ASTCtxt = C.getASTContext(); 804296417Sdim const ObjCMethodDecl *Method = 805296417Sdim findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); 806296417Sdim if (!Method) 807296417Sdim return; 808296417Sdim 809296417Sdim Optional<ArrayRef<QualType>> TypeArgs = 810296417Sdim (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); 811296417Sdim if (!TypeArgs) 812296417Sdim return; 813296417Sdim 814296417Sdim QualType ResultType = 815296417Sdim getReturnTypeForMethod(Method, *TypeArgs, *TrackedType, ASTCtxt); 816296417Sdim // The static type is the same as the deduced type. 817296417Sdim if (ResultType.isNull()) 818296417Sdim return; 819296417Sdim 820296417Sdim const MemRegion *RetRegion = M.getReturnValue().getAsRegion(); 821296417Sdim ExplodedNode *Pred = C.getPredecessor(); 822296417Sdim // When there is an entry available for the return symbol in DynamicTypeMap, 823296417Sdim // the call was inlined, and the information in the DynamicTypeMap is should 824296417Sdim // be precise. 825296417Sdim if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) { 826296417Sdim // TODO: we have duplicated information in DynamicTypeMap and 827296417Sdim // MostSpecializedTypeArgsMap. We should only store anything in the later if 828296417Sdim // the stored data differs from the one stored in the former. 829296417Sdim State = setDynamicTypeInfo(State, RetRegion, ResultType, 830296417Sdim /*CanBeSubclass=*/true); 831296417Sdim Pred = C.addTransition(State); 832296417Sdim } 833296417Sdim 834296417Sdim const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>(); 835296417Sdim 836296417Sdim if (!ResultPtrType || ResultPtrType->isUnspecialized()) 837296417Sdim return; 838296417Sdim 839296417Sdim // When the result is a specialized type and it is not tracked yet, track it 840296417Sdim // for the result symbol. 841296417Sdim if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) { 842296417Sdim State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType); 843296417Sdim C.addTransition(State, Pred); 844296417Sdim } 845296417Sdim} 846296417Sdim 847296417Sdimvoid DynamicTypePropagation::reportGenericsBug( 848296417Sdim const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, 849296417Sdim ExplodedNode *N, SymbolRef Sym, CheckerContext &C, 850296417Sdim const Stmt *ReportedNode) const { 851296417Sdim if (!CheckGenerics) 852296417Sdim return; 853296417Sdim 854296417Sdim initBugType(); 855296417Sdim SmallString<192> Buf; 856296417Sdim llvm::raw_svector_ostream OS(Buf); 857296417Sdim OS << "Conversion from value of type '"; 858296417Sdim QualType::print(From, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); 859296417Sdim OS << "' to incompatible type '"; 860296417Sdim QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); 861296417Sdim OS << "'"; 862296417Sdim std::unique_ptr<BugReport> R( 863296417Sdim new BugReport(*ObjCGenericsBugType, OS.str(), N)); 864296417Sdim R->markInteresting(Sym); 865296417Sdim R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym)); 866296417Sdim if (ReportedNode) 867296417Sdim R->addRange(ReportedNode->getSourceRange()); 868296417Sdim C.emitReport(std::move(R)); 869296417Sdim} 870296417Sdim 871296417SdimPathDiagnosticPiece *DynamicTypePropagation::GenericsBugVisitor::VisitNode( 872296417Sdim const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, 873296417Sdim BugReport &BR) { 874296417Sdim ProgramStateRef state = N->getState(); 875296417Sdim ProgramStateRef statePrev = PrevN->getState(); 876296417Sdim 877296417Sdim const ObjCObjectPointerType *const *TrackedType = 878296417Sdim state->get<MostSpecializedTypeArgsMap>(Sym); 879296417Sdim const ObjCObjectPointerType *const *TrackedTypePrev = 880296417Sdim statePrev->get<MostSpecializedTypeArgsMap>(Sym); 881296417Sdim if (!TrackedType) 882296417Sdim return nullptr; 883296417Sdim 884296417Sdim if (TrackedTypePrev && *TrackedTypePrev == *TrackedType) 885296417Sdim return nullptr; 886296417Sdim 887296417Sdim // Retrieve the associated statement. 888296417Sdim const Stmt *S = nullptr; 889296417Sdim ProgramPoint ProgLoc = N->getLocation(); 890296417Sdim if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) { 891296417Sdim S = SP->getStmt(); 892296417Sdim } 893296417Sdim 894296417Sdim if (!S) 895296417Sdim return nullptr; 896296417Sdim 897296417Sdim const LangOptions &LangOpts = BRC.getASTContext().getLangOpts(); 898296417Sdim 899296417Sdim SmallString<256> Buf; 900296417Sdim llvm::raw_svector_ostream OS(Buf); 901296417Sdim OS << "Type '"; 902296417Sdim QualType::print(*TrackedType, Qualifiers(), OS, LangOpts, llvm::Twine()); 903296417Sdim OS << "' is inferred from "; 904296417Sdim 905296417Sdim if (const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) { 906296417Sdim OS << "explicit cast (from '"; 907296417Sdim QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(), 908296417Sdim Qualifiers(), OS, LangOpts, llvm::Twine()); 909296417Sdim OS << "' to '"; 910296417Sdim QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS, 911296417Sdim LangOpts, llvm::Twine()); 912296417Sdim OS << "')"; 913296417Sdim } else if (const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) { 914296417Sdim OS << "implicit cast (from '"; 915296417Sdim QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(), 916296417Sdim Qualifiers(), OS, LangOpts, llvm::Twine()); 917296417Sdim OS << "' to '"; 918296417Sdim QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS, 919296417Sdim LangOpts, llvm::Twine()); 920296417Sdim OS << "')"; 921296417Sdim } else { 922296417Sdim OS << "this context"; 923296417Sdim } 924296417Sdim 925296417Sdim // Generate the extra diagnostic. 926296417Sdim PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 927296417Sdim N->getLocationContext()); 928296417Sdim return new PathDiagnosticEventPiece(Pos, OS.str(), true, nullptr); 929296417Sdim} 930296417Sdim 931296417Sdim/// Register checkers. 932296417Sdimvoid ento::registerObjCGenericsChecker(CheckerManager &mgr) { 933296417Sdim DynamicTypePropagation *checker = 934296417Sdim mgr.registerChecker<DynamicTypePropagation>(); 935296417Sdim checker->CheckGenerics = true; 936296417Sdim} 937296417Sdim 938239313Sdimvoid ento::registerDynamicTypePropagation(CheckerManager &mgr) { 939239313Sdim mgr.registerChecker<DynamicTypePropagation>(); 940239313Sdim} 941