106f32e7eSjoerg //== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg //  This file defines summaries implementation for retain counting, which
1006f32e7eSjoerg //  implements a reference count checker for Core Foundation, Cocoa
1106f32e7eSjoerg //  and OSObject (on Mac OS X).
1206f32e7eSjoerg //
1306f32e7eSjoerg //===----------------------------------------------------------------------===//
1406f32e7eSjoerg 
1506f32e7eSjoerg #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
1606f32e7eSjoerg #include "clang/Analysis/RetainSummaryManager.h"
1706f32e7eSjoerg #include "clang/AST/Attr.h"
1806f32e7eSjoerg #include "clang/AST/DeclCXX.h"
1906f32e7eSjoerg #include "clang/AST/DeclObjC.h"
2006f32e7eSjoerg #include "clang/AST/ParentMap.h"
2106f32e7eSjoerg #include "clang/ASTMatchers/ASTMatchFinder.h"
2206f32e7eSjoerg 
2306f32e7eSjoerg using namespace clang;
2406f32e7eSjoerg using namespace ento;
2506f32e7eSjoerg 
2606f32e7eSjoerg template <class T>
isOneOf()2706f32e7eSjoerg constexpr static bool isOneOf() {
2806f32e7eSjoerg   return false;
2906f32e7eSjoerg }
3006f32e7eSjoerg 
3106f32e7eSjoerg /// Helper function to check whether the class is one of the
3206f32e7eSjoerg /// rest of varargs.
3306f32e7eSjoerg template <class T, class P, class... ToCompare>
isOneOf()3406f32e7eSjoerg constexpr static bool isOneOf() {
3506f32e7eSjoerg   return std::is_same<T, P>::value || isOneOf<T, ToCompare...>();
3606f32e7eSjoerg }
3706f32e7eSjoerg 
3806f32e7eSjoerg namespace {
3906f32e7eSjoerg 
4006f32e7eSjoerg /// Fake attribute class for RC* attributes.
4106f32e7eSjoerg struct GeneralizedReturnsRetainedAttr {
classof__anonc33a131a0111::GeneralizedReturnsRetainedAttr4206f32e7eSjoerg   static bool classof(const Attr *A) {
4306f32e7eSjoerg     if (auto AA = dyn_cast<AnnotateAttr>(A))
4406f32e7eSjoerg       return AA->getAnnotation() == "rc_ownership_returns_retained";
4506f32e7eSjoerg     return false;
4606f32e7eSjoerg   }
4706f32e7eSjoerg };
4806f32e7eSjoerg 
4906f32e7eSjoerg struct GeneralizedReturnsNotRetainedAttr {
classof__anonc33a131a0111::GeneralizedReturnsNotRetainedAttr5006f32e7eSjoerg   static bool classof(const Attr *A) {
5106f32e7eSjoerg     if (auto AA = dyn_cast<AnnotateAttr>(A))
5206f32e7eSjoerg       return AA->getAnnotation() == "rc_ownership_returns_not_retained";
5306f32e7eSjoerg     return false;
5406f32e7eSjoerg   }
5506f32e7eSjoerg };
5606f32e7eSjoerg 
5706f32e7eSjoerg struct GeneralizedConsumedAttr {
classof__anonc33a131a0111::GeneralizedConsumedAttr5806f32e7eSjoerg   static bool classof(const Attr *A) {
5906f32e7eSjoerg     if (auto AA = dyn_cast<AnnotateAttr>(A))
6006f32e7eSjoerg       return AA->getAnnotation() == "rc_ownership_consumed";
6106f32e7eSjoerg     return false;
6206f32e7eSjoerg   }
6306f32e7eSjoerg };
6406f32e7eSjoerg 
6506f32e7eSjoerg }
6606f32e7eSjoerg 
6706f32e7eSjoerg template <class T>
hasAnyEnabledAttrOf(const Decl * D,QualType QT)6806f32e7eSjoerg Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
6906f32e7eSjoerg                                                             QualType QT) {
7006f32e7eSjoerg   ObjKind K;
7106f32e7eSjoerg   if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,
7206f32e7eSjoerg               CFReturnsNotRetainedAttr>()) {
7306f32e7eSjoerg     if (!TrackObjCAndCFObjects)
7406f32e7eSjoerg       return None;
7506f32e7eSjoerg 
7606f32e7eSjoerg     K = ObjKind::CF;
7706f32e7eSjoerg   } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
7806f32e7eSjoerg                      NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
7906f32e7eSjoerg                      NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
8006f32e7eSjoerg 
8106f32e7eSjoerg     if (!TrackObjCAndCFObjects)
8206f32e7eSjoerg       return None;
8306f32e7eSjoerg 
8406f32e7eSjoerg     if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
8506f32e7eSjoerg                 NSReturnsNotRetainedAttr>() &&
8606f32e7eSjoerg         !cocoa::isCocoaObjectRef(QT))
8706f32e7eSjoerg       return None;
8806f32e7eSjoerg     K = ObjKind::ObjC;
8906f32e7eSjoerg   } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,
9006f32e7eSjoerg                      OSReturnsNotRetainedAttr, OSReturnsRetainedAttr,
9106f32e7eSjoerg                      OSReturnsRetainedOnZeroAttr,
9206f32e7eSjoerg                      OSReturnsRetainedOnNonZeroAttr>()) {
9306f32e7eSjoerg     if (!TrackOSObjects)
9406f32e7eSjoerg       return None;
9506f32e7eSjoerg     K = ObjKind::OS;
9606f32e7eSjoerg   } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,
9706f32e7eSjoerg                      GeneralizedReturnsRetainedAttr,
9806f32e7eSjoerg                      GeneralizedConsumedAttr>()) {
9906f32e7eSjoerg     K = ObjKind::Generalized;
10006f32e7eSjoerg   } else {
10106f32e7eSjoerg     llvm_unreachable("Unexpected attribute");
10206f32e7eSjoerg   }
10306f32e7eSjoerg   if (D->hasAttr<T>())
10406f32e7eSjoerg     return K;
10506f32e7eSjoerg   return None;
10606f32e7eSjoerg }
10706f32e7eSjoerg 
10806f32e7eSjoerg template <class T1, class T2, class... Others>
hasAnyEnabledAttrOf(const Decl * D,QualType QT)10906f32e7eSjoerg Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
11006f32e7eSjoerg                                                             QualType QT) {
11106f32e7eSjoerg   if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))
11206f32e7eSjoerg     return Out;
11306f32e7eSjoerg   return hasAnyEnabledAttrOf<T2, Others...>(D, QT);
11406f32e7eSjoerg }
11506f32e7eSjoerg 
11606f32e7eSjoerg const RetainSummary *
getPersistentSummary(const RetainSummary & OldSumm)11706f32e7eSjoerg RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
11806f32e7eSjoerg   // Unique "simple" summaries -- those without ArgEffects.
11906f32e7eSjoerg   if (OldSumm.isSimple()) {
12006f32e7eSjoerg     ::llvm::FoldingSetNodeID ID;
12106f32e7eSjoerg     OldSumm.Profile(ID);
12206f32e7eSjoerg 
12306f32e7eSjoerg     void *Pos;
12406f32e7eSjoerg     CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
12506f32e7eSjoerg 
12606f32e7eSjoerg     if (!N) {
12706f32e7eSjoerg       N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
12806f32e7eSjoerg       new (N) CachedSummaryNode(OldSumm);
12906f32e7eSjoerg       SimpleSummaries.InsertNode(N, Pos);
13006f32e7eSjoerg     }
13106f32e7eSjoerg 
13206f32e7eSjoerg     return &N->getValue();
13306f32e7eSjoerg   }
13406f32e7eSjoerg 
13506f32e7eSjoerg   RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
13606f32e7eSjoerg   new (Summ) RetainSummary(OldSumm);
13706f32e7eSjoerg   return Summ;
13806f32e7eSjoerg }
13906f32e7eSjoerg 
isSubclass(const Decl * D,StringRef ClassName)14006f32e7eSjoerg static bool isSubclass(const Decl *D,
14106f32e7eSjoerg                        StringRef ClassName) {
14206f32e7eSjoerg   using namespace ast_matchers;
143*13fbcb42Sjoerg   DeclarationMatcher SubclassM =
144*13fbcb42Sjoerg       cxxRecordDecl(isSameOrDerivedFrom(std::string(ClassName)));
14506f32e7eSjoerg   return !(match(SubclassM, *D, D->getASTContext()).empty());
14606f32e7eSjoerg }
14706f32e7eSjoerg 
isOSObjectSubclass(const Decl * D)14806f32e7eSjoerg static bool isOSObjectSubclass(const Decl *D) {
14906f32e7eSjoerg   return D && isSubclass(D, "OSMetaClassBase");
15006f32e7eSjoerg }
15106f32e7eSjoerg 
isOSObjectDynamicCast(StringRef S)15206f32e7eSjoerg static bool isOSObjectDynamicCast(StringRef S) {
15306f32e7eSjoerg   return S == "safeMetaCast";
15406f32e7eSjoerg }
15506f32e7eSjoerg 
isOSObjectRequiredCast(StringRef S)15606f32e7eSjoerg static bool isOSObjectRequiredCast(StringRef S) {
15706f32e7eSjoerg   return S == "requiredMetaCast";
15806f32e7eSjoerg }
15906f32e7eSjoerg 
isOSObjectThisCast(StringRef S)16006f32e7eSjoerg static bool isOSObjectThisCast(StringRef S) {
16106f32e7eSjoerg   return S == "metaCast";
16206f32e7eSjoerg }
16306f32e7eSjoerg 
16406f32e7eSjoerg 
isOSObjectPtr(QualType QT)16506f32e7eSjoerg static bool isOSObjectPtr(QualType QT) {
16606f32e7eSjoerg   return isOSObjectSubclass(QT->getPointeeCXXRecordDecl());
16706f32e7eSjoerg }
16806f32e7eSjoerg 
isISLObjectRef(QualType Ty)16906f32e7eSjoerg static bool isISLObjectRef(QualType Ty) {
17006f32e7eSjoerg   return StringRef(Ty.getAsString()).startswith("isl_");
17106f32e7eSjoerg }
17206f32e7eSjoerg 
isOSIteratorSubclass(const Decl * D)17306f32e7eSjoerg static bool isOSIteratorSubclass(const Decl *D) {
17406f32e7eSjoerg   return isSubclass(D, "OSIterator");
17506f32e7eSjoerg }
17606f32e7eSjoerg 
hasRCAnnotation(const Decl * D,StringRef rcAnnotation)17706f32e7eSjoerg static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
17806f32e7eSjoerg   for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
17906f32e7eSjoerg     if (Ann->getAnnotation() == rcAnnotation)
18006f32e7eSjoerg       return true;
18106f32e7eSjoerg   }
18206f32e7eSjoerg   return false;
18306f32e7eSjoerg }
18406f32e7eSjoerg 
isRetain(const FunctionDecl * FD,StringRef FName)18506f32e7eSjoerg static bool isRetain(const FunctionDecl *FD, StringRef FName) {
18606f32e7eSjoerg   return FName.startswith_lower("retain") || FName.endswith_lower("retain");
18706f32e7eSjoerg }
18806f32e7eSjoerg 
isRelease(const FunctionDecl * FD,StringRef FName)18906f32e7eSjoerg static bool isRelease(const FunctionDecl *FD, StringRef FName) {
19006f32e7eSjoerg   return FName.startswith_lower("release") || FName.endswith_lower("release");
19106f32e7eSjoerg }
19206f32e7eSjoerg 
isAutorelease(const FunctionDecl * FD,StringRef FName)19306f32e7eSjoerg static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
19406f32e7eSjoerg   return FName.startswith_lower("autorelease") ||
19506f32e7eSjoerg          FName.endswith_lower("autorelease");
19606f32e7eSjoerg }
19706f32e7eSjoerg 
isMakeCollectable(StringRef FName)19806f32e7eSjoerg static bool isMakeCollectable(StringRef FName) {
19906f32e7eSjoerg   return FName.contains_lower("MakeCollectable");
20006f32e7eSjoerg }
20106f32e7eSjoerg 
20206f32e7eSjoerg /// A function is OSObject related if it is declared on a subclass
20306f32e7eSjoerg /// of OSObject, or any of the parameters is a subclass of an OSObject.
isOSObjectRelated(const CXXMethodDecl * MD)20406f32e7eSjoerg static bool isOSObjectRelated(const CXXMethodDecl *MD) {
20506f32e7eSjoerg   if (isOSObjectSubclass(MD->getParent()))
20606f32e7eSjoerg     return true;
20706f32e7eSjoerg 
20806f32e7eSjoerg   for (ParmVarDecl *Param : MD->parameters()) {
20906f32e7eSjoerg     QualType PT = Param->getType()->getPointeeType();
21006f32e7eSjoerg     if (!PT.isNull())
21106f32e7eSjoerg       if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl())
21206f32e7eSjoerg         if (isOSObjectSubclass(RD))
21306f32e7eSjoerg           return true;
21406f32e7eSjoerg   }
21506f32e7eSjoerg 
21606f32e7eSjoerg   return false;
21706f32e7eSjoerg }
21806f32e7eSjoerg 
21906f32e7eSjoerg bool
isKnownSmartPointer(QualType QT)22006f32e7eSjoerg RetainSummaryManager::isKnownSmartPointer(QualType QT) {
22106f32e7eSjoerg   QT = QT.getCanonicalType();
22206f32e7eSjoerg   const auto *RD = QT->getAsCXXRecordDecl();
22306f32e7eSjoerg   if (!RD)
22406f32e7eSjoerg     return false;
22506f32e7eSjoerg   const IdentifierInfo *II = RD->getIdentifier();
22606f32e7eSjoerg   if (II && II->getName() == "smart_ptr")
22706f32e7eSjoerg     if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()))
22806f32e7eSjoerg       if (ND->getNameAsString() == "os")
22906f32e7eSjoerg         return true;
23006f32e7eSjoerg   return false;
23106f32e7eSjoerg }
23206f32e7eSjoerg 
23306f32e7eSjoerg const RetainSummary *
getSummaryForOSObject(const FunctionDecl * FD,StringRef FName,QualType RetTy)23406f32e7eSjoerg RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
23506f32e7eSjoerg                                             StringRef FName, QualType RetTy) {
23606f32e7eSjoerg   assert(TrackOSObjects &&
23706f32e7eSjoerg          "Requesting a summary for an OSObject but OSObjects are not tracked");
23806f32e7eSjoerg 
23906f32e7eSjoerg   if (RetTy->isPointerType()) {
24006f32e7eSjoerg     const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl();
24106f32e7eSjoerg     if (PD && isOSObjectSubclass(PD)) {
24206f32e7eSjoerg       if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) ||
24306f32e7eSjoerg           isOSObjectThisCast(FName))
24406f32e7eSjoerg         return getDefaultSummary();
24506f32e7eSjoerg 
24606f32e7eSjoerg       // TODO: Add support for the slightly common *Matching(table) idiom.
24706f32e7eSjoerg       // Cf. IOService::nameMatching() etc. - these function have an unusual
24806f32e7eSjoerg       // contract of returning at +0 or +1 depending on their last argument.
24906f32e7eSjoerg       if (FName.endswith("Matching")) {
25006f32e7eSjoerg         return getPersistentStopSummary();
25106f32e7eSjoerg       }
25206f32e7eSjoerg 
25306f32e7eSjoerg       // All objects returned with functions *not* starting with 'get',
25406f32e7eSjoerg       // or iterators, are returned at +1.
25506f32e7eSjoerg       if ((!FName.startswith("get") && !FName.startswith("Get")) ||
25606f32e7eSjoerg           isOSIteratorSubclass(PD)) {
25706f32e7eSjoerg         return getOSSummaryCreateRule(FD);
25806f32e7eSjoerg       } else {
25906f32e7eSjoerg         return getOSSummaryGetRule(FD);
26006f32e7eSjoerg       }
26106f32e7eSjoerg     }
26206f32e7eSjoerg   }
26306f32e7eSjoerg 
26406f32e7eSjoerg   if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
26506f32e7eSjoerg     const CXXRecordDecl *Parent = MD->getParent();
26606f32e7eSjoerg     if (Parent && isOSObjectSubclass(Parent)) {
26706f32e7eSjoerg       if (FName == "release" || FName == "taggedRelease")
26806f32e7eSjoerg         return getOSSummaryReleaseRule(FD);
26906f32e7eSjoerg 
27006f32e7eSjoerg       if (FName == "retain" || FName == "taggedRetain")
27106f32e7eSjoerg         return getOSSummaryRetainRule(FD);
27206f32e7eSjoerg 
27306f32e7eSjoerg       if (FName == "free")
27406f32e7eSjoerg         return getOSSummaryFreeRule(FD);
27506f32e7eSjoerg 
27606f32e7eSjoerg       if (MD->getOverloadedOperator() == OO_New)
27706f32e7eSjoerg         return getOSSummaryCreateRule(MD);
27806f32e7eSjoerg     }
27906f32e7eSjoerg   }
28006f32e7eSjoerg 
28106f32e7eSjoerg   return nullptr;
28206f32e7eSjoerg }
28306f32e7eSjoerg 
getSummaryForObjCOrCFObject(const FunctionDecl * FD,StringRef FName,QualType RetTy,const FunctionType * FT,bool & AllowAnnotations)28406f32e7eSjoerg const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
28506f32e7eSjoerg     const FunctionDecl *FD,
28606f32e7eSjoerg     StringRef FName,
28706f32e7eSjoerg     QualType RetTy,
28806f32e7eSjoerg     const FunctionType *FT,
28906f32e7eSjoerg     bool &AllowAnnotations) {
29006f32e7eSjoerg 
29106f32e7eSjoerg   ArgEffects ScratchArgs(AF.getEmptyMap());
29206f32e7eSjoerg 
29306f32e7eSjoerg   std::string RetTyName = RetTy.getAsString();
29406f32e7eSjoerg   if (FName == "pthread_create" || FName == "pthread_setspecific") {
29506f32e7eSjoerg     // Part of: <rdar://problem/7299394> and <rdar://problem/11282706>.
29606f32e7eSjoerg     // This will be addressed better with IPA.
29706f32e7eSjoerg     return getPersistentStopSummary();
29806f32e7eSjoerg   } else if(FName == "NSMakeCollectable") {
29906f32e7eSjoerg     // Handle: id NSMakeCollectable(CFTypeRef)
30006f32e7eSjoerg     AllowAnnotations = false;
30106f32e7eSjoerg     return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing)
30206f32e7eSjoerg                                  : getPersistentStopSummary();
30306f32e7eSjoerg   } else if (FName == "CMBufferQueueDequeueAndRetain" ||
30406f32e7eSjoerg              FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
30506f32e7eSjoerg     // Part of: <rdar://problem/39390714>.
30606f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
30706f32e7eSjoerg                                 ScratchArgs,
30806f32e7eSjoerg                                 ArgEffect(DoNothing),
30906f32e7eSjoerg                                 ArgEffect(DoNothing));
31006f32e7eSjoerg   } else if (FName == "CFPlugInInstanceCreate") {
31106f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);
31206f32e7eSjoerg   } else if (FName == "IORegistryEntrySearchCFProperty" ||
31306f32e7eSjoerg              (RetTyName == "CFMutableDictionaryRef" &&
31406f32e7eSjoerg               (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||
31506f32e7eSjoerg                FName == "IOServiceNameMatching" ||
31606f32e7eSjoerg                FName == "IORegistryEntryIDMatching" ||
31706f32e7eSjoerg                FName == "IOOpenFirmwarePathMatching"))) {
31806f32e7eSjoerg     // Part of <rdar://problem/6961230>. (IOKit)
31906f32e7eSjoerg     // This should be addressed using a API table.
32006f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
32106f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
32206f32e7eSjoerg   } else if (FName == "IOServiceGetMatchingService" ||
32306f32e7eSjoerg              FName == "IOServiceGetMatchingServices") {
32406f32e7eSjoerg     // FIXES: <rdar://problem/6326900>
32506f32e7eSjoerg     // This should be addressed using a API table.  This strcmp is also
32606f32e7eSjoerg     // a little gross, but there is no need to super optimize here.
32706f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));
32806f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
32906f32e7eSjoerg                                 ScratchArgs,
33006f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
33106f32e7eSjoerg   } else if (FName == "IOServiceAddNotification" ||
33206f32e7eSjoerg              FName == "IOServiceAddMatchingNotification") {
33306f32e7eSjoerg     // Part of <rdar://problem/6961230>. (IOKit)
33406f32e7eSjoerg     // This should be addressed using a API table.
33506f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));
33606f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
33706f32e7eSjoerg                                 ScratchArgs,
33806f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
33906f32e7eSjoerg   } else if (FName == "CVPixelBufferCreateWithBytes") {
34006f32e7eSjoerg     // FIXES: <rdar://problem/7283567>
34106f32e7eSjoerg     // Eventually this can be improved by recognizing that the pixel
34206f32e7eSjoerg     // buffer passed to CVPixelBufferCreateWithBytes is released via
34306f32e7eSjoerg     // a callback and doing full IPA to make sure this is done correctly.
34406f32e7eSjoerg     // FIXME: This function has an out parameter that returns an
34506f32e7eSjoerg     // allocated object.
34606f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));
34706f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
34806f32e7eSjoerg                                 ScratchArgs,
34906f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
35006f32e7eSjoerg   } else if (FName == "CGBitmapContextCreateWithData") {
35106f32e7eSjoerg     // FIXES: <rdar://problem/7358899>
35206f32e7eSjoerg     // Eventually this can be improved by recognizing that 'releaseInfo'
35306f32e7eSjoerg     // passed to CGBitmapContextCreateWithData is released via
35406f32e7eSjoerg     // a callback and doing full IPA to make sure this is done correctly.
35506f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));
35606f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
35706f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
35806f32e7eSjoerg   } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
35906f32e7eSjoerg     // FIXES: <rdar://problem/7283567>
36006f32e7eSjoerg     // Eventually this can be improved by recognizing that the pixel
36106f32e7eSjoerg     // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
36206f32e7eSjoerg     // via a callback and doing full IPA to make sure this is done
36306f32e7eSjoerg     // correctly.
36406f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));
36506f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
36606f32e7eSjoerg                                 ScratchArgs,
36706f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
36806f32e7eSjoerg   } else if (FName == "VTCompressionSessionEncodeFrame") {
36906f32e7eSjoerg     // The context argument passed to VTCompressionSessionEncodeFrame()
37006f32e7eSjoerg     // is passed to the callback specified when creating the session
37106f32e7eSjoerg     // (e.g. with VTCompressionSessionCreate()) which can release it.
37206f32e7eSjoerg     // To account for this possibility, conservatively stop tracking
37306f32e7eSjoerg     // the context.
37406f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));
37506f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
37606f32e7eSjoerg                                 ScratchArgs,
37706f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
37806f32e7eSjoerg   } else if (FName == "dispatch_set_context" ||
37906f32e7eSjoerg              FName == "xpc_connection_set_context") {
38006f32e7eSjoerg     // <rdar://problem/11059275> - The analyzer currently doesn't have
38106f32e7eSjoerg     // a good way to reason about the finalizer function for libdispatch.
38206f32e7eSjoerg     // If we pass a context object that is memory managed, stop tracking it.
38306f32e7eSjoerg     // <rdar://problem/13783514> - Same problem, but for XPC.
38406f32e7eSjoerg     // FIXME: this hack should possibly go away once we can handle
38506f32e7eSjoerg     // libdispatch and XPC finalizers.
38606f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
38706f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
38806f32e7eSjoerg                                 ScratchArgs,
38906f32e7eSjoerg                                 ArgEffect(DoNothing), ArgEffect(DoNothing));
39006f32e7eSjoerg   } else if (FName.startswith("NSLog")) {
39106f32e7eSjoerg     return getDoNothingSummary();
39206f32e7eSjoerg   } else if (FName.startswith("NS") &&
39306f32e7eSjoerg              (FName.find("Insert") != StringRef::npos)) {
39406f32e7eSjoerg     // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
39506f32e7eSjoerg     // be deallocated by NSMapRemove. (radar://11152419)
39606f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
39706f32e7eSjoerg     ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));
39806f32e7eSjoerg     return getPersistentSummary(RetEffect::MakeNoRet(),
39906f32e7eSjoerg                                 ScratchArgs, ArgEffect(DoNothing),
40006f32e7eSjoerg                                 ArgEffect(DoNothing));
40106f32e7eSjoerg   }
40206f32e7eSjoerg 
40306f32e7eSjoerg   if (RetTy->isPointerType()) {
40406f32e7eSjoerg 
40506f32e7eSjoerg     // For CoreFoundation ('CF') types.
40606f32e7eSjoerg     if (cocoa::isRefType(RetTy, "CF", FName)) {
40706f32e7eSjoerg       if (isRetain(FD, FName)) {
40806f32e7eSjoerg         // CFRetain isn't supposed to be annotated. However, this may as
40906f32e7eSjoerg         // well be a user-made "safe" CFRetain function that is incorrectly
41006f32e7eSjoerg         // annotated as cf_returns_retained due to lack of better options.
41106f32e7eSjoerg         // We want to ignore such annotation.
41206f32e7eSjoerg         AllowAnnotations = false;
41306f32e7eSjoerg 
41406f32e7eSjoerg         return getUnarySummary(FT, IncRef);
41506f32e7eSjoerg       } else if (isAutorelease(FD, FName)) {
41606f32e7eSjoerg         // The headers use cf_consumed, but we can fully model CFAutorelease
41706f32e7eSjoerg         // ourselves.
41806f32e7eSjoerg         AllowAnnotations = false;
41906f32e7eSjoerg 
42006f32e7eSjoerg         return getUnarySummary(FT, Autorelease);
42106f32e7eSjoerg       } else if (isMakeCollectable(FName)) {
42206f32e7eSjoerg         AllowAnnotations = false;
42306f32e7eSjoerg         return getUnarySummary(FT, DoNothing);
42406f32e7eSjoerg       } else {
42506f32e7eSjoerg         return getCFCreateGetRuleSummary(FD);
42606f32e7eSjoerg       }
42706f32e7eSjoerg     }
42806f32e7eSjoerg 
42906f32e7eSjoerg     // For CoreGraphics ('CG') and CoreVideo ('CV') types.
43006f32e7eSjoerg     if (cocoa::isRefType(RetTy, "CG", FName) ||
43106f32e7eSjoerg         cocoa::isRefType(RetTy, "CV", FName)) {
43206f32e7eSjoerg       if (isRetain(FD, FName))
43306f32e7eSjoerg         return getUnarySummary(FT, IncRef);
43406f32e7eSjoerg       else
43506f32e7eSjoerg         return getCFCreateGetRuleSummary(FD);
43606f32e7eSjoerg     }
43706f32e7eSjoerg 
43806f32e7eSjoerg     // For all other CF-style types, use the Create/Get
43906f32e7eSjoerg     // rule for summaries but don't support Retain functions
44006f32e7eSjoerg     // with framework-specific prefixes.
44106f32e7eSjoerg     if (coreFoundation::isCFObjectRef(RetTy)) {
44206f32e7eSjoerg       return getCFCreateGetRuleSummary(FD);
44306f32e7eSjoerg     }
44406f32e7eSjoerg 
44506f32e7eSjoerg     if (FD->hasAttr<CFAuditedTransferAttr>()) {
44606f32e7eSjoerg       return getCFCreateGetRuleSummary(FD);
44706f32e7eSjoerg     }
44806f32e7eSjoerg   }
44906f32e7eSjoerg 
45006f32e7eSjoerg   // Check for release functions, the only kind of functions that we care
45106f32e7eSjoerg   // about that don't return a pointer type.
45206f32e7eSjoerg   if (FName.startswith("CG") || FName.startswith("CF")) {
45306f32e7eSjoerg     // Test for 'CGCF'.
45406f32e7eSjoerg     FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
45506f32e7eSjoerg 
45606f32e7eSjoerg     if (isRelease(FD, FName))
45706f32e7eSjoerg       return getUnarySummary(FT, DecRef);
45806f32e7eSjoerg     else {
45906f32e7eSjoerg       assert(ScratchArgs.isEmpty());
46006f32e7eSjoerg       // Remaining CoreFoundation and CoreGraphics functions.
46106f32e7eSjoerg       // We use to assume that they all strictly followed the ownership idiom
46206f32e7eSjoerg       // and that ownership cannot be transferred.  While this is technically
46306f32e7eSjoerg       // correct, many methods allow a tracked object to escape.  For example:
46406f32e7eSjoerg       //
46506f32e7eSjoerg       //   CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
46606f32e7eSjoerg       //   CFDictionaryAddValue(y, key, x);
46706f32e7eSjoerg       //   CFRelease(x);
46806f32e7eSjoerg       //   ... it is okay to use 'x' since 'y' has a reference to it
46906f32e7eSjoerg       //
47006f32e7eSjoerg       // We handle this and similar cases with the follow heuristic.  If the
47106f32e7eSjoerg       // function name contains "InsertValue", "SetValue", "AddValue",
47206f32e7eSjoerg       // "AppendValue", or "SetAttribute", then we assume that arguments may
47306f32e7eSjoerg       // "escape."  This means that something else holds on to the object,
47406f32e7eSjoerg       // allowing it be used even after its local retain count drops to 0.
47506f32e7eSjoerg       ArgEffectKind E =
47606f32e7eSjoerg           (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
47706f32e7eSjoerg            StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
47806f32e7eSjoerg            StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
47906f32e7eSjoerg            StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
48006f32e7eSjoerg            StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
48106f32e7eSjoerg               ? MayEscape
48206f32e7eSjoerg               : DoNothing;
48306f32e7eSjoerg 
48406f32e7eSjoerg       return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
48506f32e7eSjoerg                                   ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF));
48606f32e7eSjoerg     }
48706f32e7eSjoerg   }
48806f32e7eSjoerg 
48906f32e7eSjoerg   return nullptr;
49006f32e7eSjoerg }
49106f32e7eSjoerg 
49206f32e7eSjoerg const RetainSummary *
generateSummary(const FunctionDecl * FD,bool & AllowAnnotations)49306f32e7eSjoerg RetainSummaryManager::generateSummary(const FunctionDecl *FD,
49406f32e7eSjoerg                                       bool &AllowAnnotations) {
49506f32e7eSjoerg   // We generate "stop" summaries for implicitly defined functions.
49606f32e7eSjoerg   if (FD->isImplicit())
49706f32e7eSjoerg     return getPersistentStopSummary();
49806f32e7eSjoerg 
49906f32e7eSjoerg   const IdentifierInfo *II = FD->getIdentifier();
50006f32e7eSjoerg 
50106f32e7eSjoerg   StringRef FName = II ? II->getName() : "";
50206f32e7eSjoerg 
50306f32e7eSjoerg   // Strip away preceding '_'.  Doing this here will effect all the checks
50406f32e7eSjoerg   // down below.
50506f32e7eSjoerg   FName = FName.substr(FName.find_first_not_of('_'));
50606f32e7eSjoerg 
50706f32e7eSjoerg   // Inspect the result type. Strip away any typedefs.
50806f32e7eSjoerg   const auto *FT = FD->getType()->castAs<FunctionType>();
50906f32e7eSjoerg   QualType RetTy = FT->getReturnType();
51006f32e7eSjoerg 
51106f32e7eSjoerg   if (TrackOSObjects)
51206f32e7eSjoerg     if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))
51306f32e7eSjoerg       return S;
51406f32e7eSjoerg 
51506f32e7eSjoerg   if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
51606f32e7eSjoerg     if (!isOSObjectRelated(MD))
51706f32e7eSjoerg       return getPersistentSummary(RetEffect::MakeNoRet(),
51806f32e7eSjoerg                                   ArgEffects(AF.getEmptyMap()),
51906f32e7eSjoerg                                   ArgEffect(DoNothing),
52006f32e7eSjoerg                                   ArgEffect(StopTracking),
52106f32e7eSjoerg                                   ArgEffect(DoNothing));
52206f32e7eSjoerg 
52306f32e7eSjoerg   if (TrackObjCAndCFObjects)
52406f32e7eSjoerg     if (const RetainSummary *S =
52506f32e7eSjoerg             getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))
52606f32e7eSjoerg       return S;
52706f32e7eSjoerg 
52806f32e7eSjoerg   return getDefaultSummary();
52906f32e7eSjoerg }
53006f32e7eSjoerg 
53106f32e7eSjoerg const RetainSummary *
getFunctionSummary(const FunctionDecl * FD)53206f32e7eSjoerg RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
53306f32e7eSjoerg   // If we don't know what function we're calling, use our default summary.
53406f32e7eSjoerg   if (!FD)
53506f32e7eSjoerg     return getDefaultSummary();
53606f32e7eSjoerg 
53706f32e7eSjoerg   // Look up a summary in our cache of FunctionDecls -> Summaries.
53806f32e7eSjoerg   FuncSummariesTy::iterator I = FuncSummaries.find(FD);
53906f32e7eSjoerg   if (I != FuncSummaries.end())
54006f32e7eSjoerg     return I->second;
54106f32e7eSjoerg 
54206f32e7eSjoerg   // No summary?  Generate one.
54306f32e7eSjoerg   bool AllowAnnotations = true;
54406f32e7eSjoerg   const RetainSummary *S = generateSummary(FD, AllowAnnotations);
54506f32e7eSjoerg 
54606f32e7eSjoerg   // Annotations override defaults.
54706f32e7eSjoerg   if (AllowAnnotations)
54806f32e7eSjoerg     updateSummaryFromAnnotations(S, FD);
54906f32e7eSjoerg 
55006f32e7eSjoerg   FuncSummaries[FD] = S;
55106f32e7eSjoerg   return S;
55206f32e7eSjoerg }
55306f32e7eSjoerg 
55406f32e7eSjoerg //===----------------------------------------------------------------------===//
55506f32e7eSjoerg // Summary creation for functions (largely uses of Core Foundation).
55606f32e7eSjoerg //===----------------------------------------------------------------------===//
55706f32e7eSjoerg 
getStopTrackingHardEquivalent(ArgEffect E)55806f32e7eSjoerg static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
55906f32e7eSjoerg   switch (E.getKind()) {
56006f32e7eSjoerg   case DoNothing:
56106f32e7eSjoerg   case Autorelease:
56206f32e7eSjoerg   case DecRefBridgedTransferred:
56306f32e7eSjoerg   case IncRef:
56406f32e7eSjoerg   case UnretainedOutParameter:
56506f32e7eSjoerg   case RetainedOutParameter:
56606f32e7eSjoerg   case RetainedOutParameterOnZero:
56706f32e7eSjoerg   case RetainedOutParameterOnNonZero:
56806f32e7eSjoerg   case MayEscape:
56906f32e7eSjoerg   case StopTracking:
57006f32e7eSjoerg   case StopTrackingHard:
57106f32e7eSjoerg     return E.withKind(StopTrackingHard);
57206f32e7eSjoerg   case DecRef:
57306f32e7eSjoerg   case DecRefAndStopTrackingHard:
57406f32e7eSjoerg     return E.withKind(DecRefAndStopTrackingHard);
57506f32e7eSjoerg   case Dealloc:
57606f32e7eSjoerg     return E.withKind(Dealloc);
57706f32e7eSjoerg   }
57806f32e7eSjoerg 
57906f32e7eSjoerg   llvm_unreachable("Unknown ArgEffect kind");
58006f32e7eSjoerg }
58106f32e7eSjoerg 
58206f32e7eSjoerg const RetainSummary *
updateSummaryForNonZeroCallbackArg(const RetainSummary * S,AnyCall & C)58306f32e7eSjoerg RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
58406f32e7eSjoerg                                                          AnyCall &C) {
58506f32e7eSjoerg   ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
58606f32e7eSjoerg   ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
58706f32e7eSjoerg 
58806f32e7eSjoerg   ArgEffects ScratchArgs(AF.getEmptyMap());
58906f32e7eSjoerg   ArgEffects CustomArgEffects = S->getArgEffects();
59006f32e7eSjoerg   for (ArgEffects::iterator I = CustomArgEffects.begin(),
59106f32e7eSjoerg                             E = CustomArgEffects.end();
59206f32e7eSjoerg        I != E; ++I) {
59306f32e7eSjoerg     ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
59406f32e7eSjoerg     if (Translated.getKind() != DefEffect.getKind())
59506f32e7eSjoerg       ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
59606f32e7eSjoerg   }
59706f32e7eSjoerg 
59806f32e7eSjoerg   RetEffect RE = RetEffect::MakeNoRetHard();
59906f32e7eSjoerg 
60006f32e7eSjoerg   // Special cases where the callback argument CANNOT free the return value.
60106f32e7eSjoerg   // This can generally only happen if we know that the callback will only be
60206f32e7eSjoerg   // called when the return value is already being deallocated.
60306f32e7eSjoerg   if (const IdentifierInfo *Name = C.getIdentifier()) {
60406f32e7eSjoerg     // When the CGBitmapContext is deallocated, the callback here will free
60506f32e7eSjoerg     // the associated data buffer.
60606f32e7eSjoerg     // The callback in dispatch_data_create frees the buffer, but not
60706f32e7eSjoerg     // the data object.
60806f32e7eSjoerg     if (Name->isStr("CGBitmapContextCreateWithData") ||
60906f32e7eSjoerg         Name->isStr("dispatch_data_create"))
61006f32e7eSjoerg       RE = S->getRetEffect();
61106f32e7eSjoerg   }
61206f32e7eSjoerg 
61306f32e7eSjoerg   return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
61406f32e7eSjoerg }
61506f32e7eSjoerg 
updateSummaryForReceiverUnconsumedSelf(const RetainSummary * & S)61606f32e7eSjoerg void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
61706f32e7eSjoerg     const RetainSummary *&S) {
61806f32e7eSjoerg 
61906f32e7eSjoerg   RetainSummaryTemplate Template(S, *this);
62006f32e7eSjoerg 
62106f32e7eSjoerg   Template->setReceiverEffect(ArgEffect(DoNothing));
62206f32e7eSjoerg   Template->setRetEffect(RetEffect::MakeNoRet());
62306f32e7eSjoerg }
62406f32e7eSjoerg 
62506f32e7eSjoerg 
updateSummaryForArgumentTypes(const AnyCall & C,const RetainSummary * & RS)62606f32e7eSjoerg void RetainSummaryManager::updateSummaryForArgumentTypes(
62706f32e7eSjoerg   const AnyCall &C, const RetainSummary *&RS) {
62806f32e7eSjoerg   RetainSummaryTemplate Template(RS, *this);
62906f32e7eSjoerg 
63006f32e7eSjoerg   unsigned parm_idx = 0;
63106f32e7eSjoerg   for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe;
63206f32e7eSjoerg        ++pi, ++parm_idx) {
63306f32e7eSjoerg     QualType QT = (*pi)->getType();
63406f32e7eSjoerg 
63506f32e7eSjoerg     // Skip already created values.
63606f32e7eSjoerg     if (RS->getArgEffects().contains(parm_idx))
63706f32e7eSjoerg       continue;
63806f32e7eSjoerg 
63906f32e7eSjoerg     ObjKind K = ObjKind::AnyObj;
64006f32e7eSjoerg 
64106f32e7eSjoerg     if (isISLObjectRef(QT)) {
64206f32e7eSjoerg       K = ObjKind::Generalized;
64306f32e7eSjoerg     } else if (isOSObjectPtr(QT)) {
64406f32e7eSjoerg       K = ObjKind::OS;
64506f32e7eSjoerg     } else if (cocoa::isCocoaObjectRef(QT)) {
64606f32e7eSjoerg       K = ObjKind::ObjC;
64706f32e7eSjoerg     } else if (coreFoundation::isCFObjectRef(QT)) {
64806f32e7eSjoerg       K = ObjKind::CF;
64906f32e7eSjoerg     }
65006f32e7eSjoerg 
65106f32e7eSjoerg     if (K != ObjKind::AnyObj)
65206f32e7eSjoerg       Template->addArg(AF, parm_idx,
65306f32e7eSjoerg                        ArgEffect(RS->getDefaultArgEffect().getKind(), K));
65406f32e7eSjoerg   }
65506f32e7eSjoerg }
65606f32e7eSjoerg 
65706f32e7eSjoerg const RetainSummary *
getSummary(AnyCall C,bool HasNonZeroCallbackArg,bool IsReceiverUnconsumedSelf,QualType ReceiverType)65806f32e7eSjoerg RetainSummaryManager::getSummary(AnyCall C,
65906f32e7eSjoerg                                  bool HasNonZeroCallbackArg,
66006f32e7eSjoerg                                  bool IsReceiverUnconsumedSelf,
66106f32e7eSjoerg                                  QualType ReceiverType) {
66206f32e7eSjoerg   const RetainSummary *Summ;
66306f32e7eSjoerg   switch (C.getKind()) {
66406f32e7eSjoerg   case AnyCall::Function:
66506f32e7eSjoerg   case AnyCall::Constructor:
666*13fbcb42Sjoerg   case AnyCall::InheritedConstructor:
66706f32e7eSjoerg   case AnyCall::Allocator:
66806f32e7eSjoerg   case AnyCall::Deallocator:
66906f32e7eSjoerg     Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
67006f32e7eSjoerg     break;
67106f32e7eSjoerg   case AnyCall::Block:
67206f32e7eSjoerg   case AnyCall::Destructor:
67306f32e7eSjoerg     // FIXME: These calls are currently unsupported.
67406f32e7eSjoerg     return getPersistentStopSummary();
67506f32e7eSjoerg   case AnyCall::ObjCMethod: {
67606f32e7eSjoerg     const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());
67706f32e7eSjoerg     if (!ME) {
67806f32e7eSjoerg       Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));
67906f32e7eSjoerg     } else if (ME->isInstanceMessage()) {
68006f32e7eSjoerg       Summ = getInstanceMethodSummary(ME, ReceiverType);
68106f32e7eSjoerg     } else {
68206f32e7eSjoerg       Summ = getClassMethodSummary(ME);
68306f32e7eSjoerg     }
68406f32e7eSjoerg     break;
68506f32e7eSjoerg   }
68606f32e7eSjoerg   }
68706f32e7eSjoerg 
68806f32e7eSjoerg   if (HasNonZeroCallbackArg)
68906f32e7eSjoerg     Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
69006f32e7eSjoerg 
69106f32e7eSjoerg   if (IsReceiverUnconsumedSelf)
69206f32e7eSjoerg     updateSummaryForReceiverUnconsumedSelf(Summ);
69306f32e7eSjoerg 
69406f32e7eSjoerg   updateSummaryForArgumentTypes(C, Summ);
69506f32e7eSjoerg 
69606f32e7eSjoerg   assert(Summ && "Unknown call type?");
69706f32e7eSjoerg   return Summ;
69806f32e7eSjoerg }
69906f32e7eSjoerg 
70006f32e7eSjoerg 
70106f32e7eSjoerg const RetainSummary *
getCFCreateGetRuleSummary(const FunctionDecl * FD)70206f32e7eSjoerg RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
70306f32e7eSjoerg   if (coreFoundation::followsCreateRule(FD))
70406f32e7eSjoerg     return getCFSummaryCreateRule(FD);
70506f32e7eSjoerg 
70606f32e7eSjoerg   return getCFSummaryGetRule(FD);
70706f32e7eSjoerg }
70806f32e7eSjoerg 
isTrustedReferenceCountImplementation(const Decl * FD)70906f32e7eSjoerg bool RetainSummaryManager::isTrustedReferenceCountImplementation(
71006f32e7eSjoerg     const Decl *FD) {
71106f32e7eSjoerg   return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
71206f32e7eSjoerg }
71306f32e7eSjoerg 
71406f32e7eSjoerg Optional<RetainSummaryManager::BehaviorSummary>
canEval(const CallExpr * CE,const FunctionDecl * FD,bool & hasTrustedImplementationAnnotation)71506f32e7eSjoerg RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
71606f32e7eSjoerg                               bool &hasTrustedImplementationAnnotation) {
71706f32e7eSjoerg 
71806f32e7eSjoerg   IdentifierInfo *II = FD->getIdentifier();
71906f32e7eSjoerg   if (!II)
72006f32e7eSjoerg     return None;
72106f32e7eSjoerg 
72206f32e7eSjoerg   StringRef FName = II->getName();
72306f32e7eSjoerg   FName = FName.substr(FName.find_first_not_of('_'));
72406f32e7eSjoerg 
72506f32e7eSjoerg   QualType ResultTy = CE->getCallReturnType(Ctx);
72606f32e7eSjoerg   if (ResultTy->isObjCIdType()) {
72706f32e7eSjoerg     if (II->isStr("NSMakeCollectable"))
72806f32e7eSjoerg       return BehaviorSummary::Identity;
72906f32e7eSjoerg   } else if (ResultTy->isPointerType()) {
73006f32e7eSjoerg     // Handle: (CF|CG|CV)Retain
73106f32e7eSjoerg     //         CFAutorelease
73206f32e7eSjoerg     // It's okay to be a little sloppy here.
73306f32e7eSjoerg     if (FName == "CMBufferQueueDequeueAndRetain" ||
73406f32e7eSjoerg         FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
73506f32e7eSjoerg       // Part of: <rdar://problem/39390714>.
73606f32e7eSjoerg       // These are not retain. They just return something and retain it.
73706f32e7eSjoerg       return None;
73806f32e7eSjoerg     }
73906f32e7eSjoerg     if (CE->getNumArgs() == 1 &&
74006f32e7eSjoerg         (cocoa::isRefType(ResultTy, "CF", FName) ||
74106f32e7eSjoerg          cocoa::isRefType(ResultTy, "CG", FName) ||
74206f32e7eSjoerg          cocoa::isRefType(ResultTy, "CV", FName)) &&
74306f32e7eSjoerg         (isRetain(FD, FName) || isAutorelease(FD, FName) ||
74406f32e7eSjoerg          isMakeCollectable(FName)))
74506f32e7eSjoerg       return BehaviorSummary::Identity;
74606f32e7eSjoerg 
74706f32e7eSjoerg     // safeMetaCast is called by OSDynamicCast.
74806f32e7eSjoerg     // We assume that OSDynamicCast is either an identity (cast is OK,
74906f32e7eSjoerg     // the input was non-zero),
75006f32e7eSjoerg     // or that it returns zero (when the cast failed, or the input
75106f32e7eSjoerg     // was zero).
75206f32e7eSjoerg     if (TrackOSObjects) {
75306f32e7eSjoerg       if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {
75406f32e7eSjoerg         return BehaviorSummary::IdentityOrZero;
75506f32e7eSjoerg       } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {
75606f32e7eSjoerg         return BehaviorSummary::Identity;
75706f32e7eSjoerg       } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&
75806f32e7eSjoerg                  !cast<CXXMethodDecl>(FD)->isStatic()) {
75906f32e7eSjoerg         return BehaviorSummary::IdentityThis;
76006f32e7eSjoerg       }
76106f32e7eSjoerg     }
76206f32e7eSjoerg 
76306f32e7eSjoerg     const FunctionDecl* FDD = FD->getDefinition();
76406f32e7eSjoerg     if (FDD && isTrustedReferenceCountImplementation(FDD)) {
76506f32e7eSjoerg       hasTrustedImplementationAnnotation = true;
76606f32e7eSjoerg       return BehaviorSummary::Identity;
76706f32e7eSjoerg     }
76806f32e7eSjoerg   }
76906f32e7eSjoerg 
77006f32e7eSjoerg   if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
77106f32e7eSjoerg     const CXXRecordDecl *Parent = MD->getParent();
77206f32e7eSjoerg     if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))
77306f32e7eSjoerg       if (FName == "release" || FName == "retain")
77406f32e7eSjoerg         return BehaviorSummary::NoOp;
77506f32e7eSjoerg   }
77606f32e7eSjoerg 
77706f32e7eSjoerg   return None;
77806f32e7eSjoerg }
77906f32e7eSjoerg 
78006f32e7eSjoerg const RetainSummary *
getUnarySummary(const FunctionType * FT,ArgEffectKind AE)78106f32e7eSjoerg RetainSummaryManager::getUnarySummary(const FunctionType* FT,
78206f32e7eSjoerg                                       ArgEffectKind AE) {
78306f32e7eSjoerg 
78406f32e7eSjoerg   // Unary functions have no arg effects by definition.
78506f32e7eSjoerg   ArgEffects ScratchArgs(AF.getEmptyMap());
78606f32e7eSjoerg 
78706f32e7eSjoerg   // Sanity check that this is *really* a unary function.  This can
78806f32e7eSjoerg   // happen if people do weird things.
78906f32e7eSjoerg   const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
79006f32e7eSjoerg   if (!FTP || FTP->getNumParams() != 1)
79106f32e7eSjoerg     return getPersistentStopSummary();
79206f32e7eSjoerg 
79306f32e7eSjoerg   ArgEffect Effect(AE, ObjKind::CF);
79406f32e7eSjoerg 
79506f32e7eSjoerg   ScratchArgs = AF.add(ScratchArgs, 0, Effect);
79606f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeNoRet(),
79706f32e7eSjoerg                               ScratchArgs,
79806f32e7eSjoerg                               ArgEffect(DoNothing), ArgEffect(DoNothing));
79906f32e7eSjoerg }
80006f32e7eSjoerg 
80106f32e7eSjoerg const RetainSummary *
getOSSummaryRetainRule(const FunctionDecl * FD)80206f32e7eSjoerg RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
80306f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeNoRet(),
80406f32e7eSjoerg                               AF.getEmptyMap(),
80506f32e7eSjoerg                               /*ReceiverEff=*/ArgEffect(DoNothing),
80606f32e7eSjoerg                               /*DefaultEff=*/ArgEffect(DoNothing),
80706f32e7eSjoerg                               /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));
80806f32e7eSjoerg }
80906f32e7eSjoerg 
81006f32e7eSjoerg const RetainSummary *
getOSSummaryReleaseRule(const FunctionDecl * FD)81106f32e7eSjoerg RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
81206f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeNoRet(),
81306f32e7eSjoerg                               AF.getEmptyMap(),
81406f32e7eSjoerg                               /*ReceiverEff=*/ArgEffect(DoNothing),
81506f32e7eSjoerg                               /*DefaultEff=*/ArgEffect(DoNothing),
81606f32e7eSjoerg                               /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));
81706f32e7eSjoerg }
81806f32e7eSjoerg 
81906f32e7eSjoerg const RetainSummary *
getOSSummaryFreeRule(const FunctionDecl * FD)82006f32e7eSjoerg RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {
82106f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeNoRet(),
82206f32e7eSjoerg                               AF.getEmptyMap(),
82306f32e7eSjoerg                               /*ReceiverEff=*/ArgEffect(DoNothing),
82406f32e7eSjoerg                               /*DefaultEff=*/ArgEffect(DoNothing),
82506f32e7eSjoerg                               /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));
82606f32e7eSjoerg }
82706f32e7eSjoerg 
82806f32e7eSjoerg const RetainSummary *
getOSSummaryCreateRule(const FunctionDecl * FD)82906f32e7eSjoerg RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
83006f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),
83106f32e7eSjoerg                               AF.getEmptyMap());
83206f32e7eSjoerg }
83306f32e7eSjoerg 
83406f32e7eSjoerg const RetainSummary *
getOSSummaryGetRule(const FunctionDecl * FD)83506f32e7eSjoerg RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
83606f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),
83706f32e7eSjoerg                               AF.getEmptyMap());
83806f32e7eSjoerg }
83906f32e7eSjoerg 
84006f32e7eSjoerg const RetainSummary *
getCFSummaryCreateRule(const FunctionDecl * FD)84106f32e7eSjoerg RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
84206f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
84306f32e7eSjoerg                               ArgEffects(AF.getEmptyMap()));
84406f32e7eSjoerg }
84506f32e7eSjoerg 
84606f32e7eSjoerg const RetainSummary *
getCFSummaryGetRule(const FunctionDecl * FD)84706f32e7eSjoerg RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
84806f32e7eSjoerg   return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
84906f32e7eSjoerg                               ArgEffects(AF.getEmptyMap()),
85006f32e7eSjoerg                               ArgEffect(DoNothing), ArgEffect(DoNothing));
85106f32e7eSjoerg }
85206f32e7eSjoerg 
85306f32e7eSjoerg 
85406f32e7eSjoerg 
85506f32e7eSjoerg 
85606f32e7eSjoerg //===----------------------------------------------------------------------===//
85706f32e7eSjoerg // Summary creation for Selectors.
85806f32e7eSjoerg //===----------------------------------------------------------------------===//
85906f32e7eSjoerg 
86006f32e7eSjoerg Optional<RetEffect>
getRetEffectFromAnnotations(QualType RetTy,const Decl * D)86106f32e7eSjoerg RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
86206f32e7eSjoerg                                                   const Decl *D) {
86306f32e7eSjoerg   if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
86406f32e7eSjoerg     return ObjCAllocRetE;
86506f32e7eSjoerg 
86606f32e7eSjoerg   if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
86706f32e7eSjoerg                                    GeneralizedReturnsRetainedAttr>(D, RetTy))
86806f32e7eSjoerg     return RetEffect::MakeOwned(*K);
86906f32e7eSjoerg 
87006f32e7eSjoerg   if (auto K = hasAnyEnabledAttrOf<
87106f32e7eSjoerg           CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
87206f32e7eSjoerg           GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
87306f32e7eSjoerg           NSReturnsAutoreleasedAttr>(D, RetTy))
87406f32e7eSjoerg     return RetEffect::MakeNotOwned(*K);
87506f32e7eSjoerg 
87606f32e7eSjoerg   if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
87706f32e7eSjoerg     for (const auto *PD : MD->overridden_methods())
87806f32e7eSjoerg       if (auto RE = getRetEffectFromAnnotations(RetTy, PD))
87906f32e7eSjoerg         return RE;
88006f32e7eSjoerg 
88106f32e7eSjoerg   return None;
88206f32e7eSjoerg }
88306f32e7eSjoerg 
884*13fbcb42Sjoerg /// \return Whether the chain of typedefs starting from @c QT
885*13fbcb42Sjoerg /// has a typedef with a given name @c Name.
hasTypedefNamed(QualType QT,StringRef Name)88606f32e7eSjoerg static bool hasTypedefNamed(QualType QT,
88706f32e7eSjoerg                             StringRef Name) {
88806f32e7eSjoerg   while (auto *T = dyn_cast<TypedefType>(QT)) {
88906f32e7eSjoerg     const auto &Context = T->getDecl()->getASTContext();
89006f32e7eSjoerg     if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))
89106f32e7eSjoerg       return true;
89206f32e7eSjoerg     QT = T->getDecl()->getUnderlyingType();
89306f32e7eSjoerg   }
89406f32e7eSjoerg   return false;
89506f32e7eSjoerg }
89606f32e7eSjoerg 
getCallableReturnType(const NamedDecl * ND)89706f32e7eSjoerg static QualType getCallableReturnType(const NamedDecl *ND) {
89806f32e7eSjoerg   if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
89906f32e7eSjoerg     return FD->getReturnType();
90006f32e7eSjoerg   } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) {
90106f32e7eSjoerg     return MD->getReturnType();
90206f32e7eSjoerg   } else {
90306f32e7eSjoerg     llvm_unreachable("Unexpected decl");
90406f32e7eSjoerg   }
90506f32e7eSjoerg }
90606f32e7eSjoerg 
applyParamAnnotationEffect(const ParmVarDecl * pd,unsigned parm_idx,const NamedDecl * FD,RetainSummaryTemplate & Template)90706f32e7eSjoerg bool RetainSummaryManager::applyParamAnnotationEffect(
90806f32e7eSjoerg     const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD,
90906f32e7eSjoerg     RetainSummaryTemplate &Template) {
91006f32e7eSjoerg   QualType QT = pd->getType();
91106f32e7eSjoerg   if (auto K =
91206f32e7eSjoerg           hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,
91306f32e7eSjoerg                               GeneralizedConsumedAttr>(pd, QT)) {
91406f32e7eSjoerg     Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
91506f32e7eSjoerg     return true;
91606f32e7eSjoerg   } else if (auto K = hasAnyEnabledAttrOf<
91706f32e7eSjoerg                  CFReturnsRetainedAttr, OSReturnsRetainedAttr,
91806f32e7eSjoerg                  OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr,
91906f32e7eSjoerg                  GeneralizedReturnsRetainedAttr>(pd, QT)) {
92006f32e7eSjoerg 
92106f32e7eSjoerg     // For OSObjects, we try to guess whether the object is created based
92206f32e7eSjoerg     // on the return value.
92306f32e7eSjoerg     if (K == ObjKind::OS) {
92406f32e7eSjoerg       QualType QT = getCallableReturnType(FD);
92506f32e7eSjoerg 
92606f32e7eSjoerg       bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();
92706f32e7eSjoerg       bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();
92806f32e7eSjoerg 
92906f32e7eSjoerg       // The usual convention is to create an object on non-zero return, but
93006f32e7eSjoerg       // it's reverted if the typedef chain has a typedef kern_return_t,
93106f32e7eSjoerg       // because kReturnSuccess constant is defined as zero.
93206f32e7eSjoerg       // The convention can be overwritten by custom attributes.
93306f32e7eSjoerg       bool SuccessOnZero =
93406f32e7eSjoerg           HasRetainedOnZero ||
93506f32e7eSjoerg           (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero);
93606f32e7eSjoerg       bool ShouldSplit = !QT.isNull() && !QT->isVoidType();
93706f32e7eSjoerg       ArgEffectKind AK = RetainedOutParameter;
93806f32e7eSjoerg       if (ShouldSplit && SuccessOnZero) {
93906f32e7eSjoerg         AK = RetainedOutParameterOnZero;
94006f32e7eSjoerg       } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {
94106f32e7eSjoerg         AK = RetainedOutParameterOnNonZero;
94206f32e7eSjoerg       }
94306f32e7eSjoerg       Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));
94406f32e7eSjoerg     }
94506f32e7eSjoerg 
94606f32e7eSjoerg     // For others:
94706f32e7eSjoerg     // Do nothing. Retained out parameters will either point to a +1 reference
94806f32e7eSjoerg     // or NULL, but the way you check for failure differs depending on the
94906f32e7eSjoerg     // API. Consequently, we don't have a good way to track them yet.
95006f32e7eSjoerg     return true;
95106f32e7eSjoerg   } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr,
95206f32e7eSjoerg                                           OSReturnsNotRetainedAttr,
95306f32e7eSjoerg                                           GeneralizedReturnsNotRetainedAttr>(
95406f32e7eSjoerg                  pd, QT)) {
95506f32e7eSjoerg     Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
95606f32e7eSjoerg     return true;
95706f32e7eSjoerg   }
95806f32e7eSjoerg 
95906f32e7eSjoerg   if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
96006f32e7eSjoerg     for (const auto *OD : MD->overridden_methods()) {
96106f32e7eSjoerg       const ParmVarDecl *OP = OD->parameters()[parm_idx];
96206f32e7eSjoerg       if (applyParamAnnotationEffect(OP, parm_idx, OD, Template))
96306f32e7eSjoerg         return true;
96406f32e7eSjoerg     }
96506f32e7eSjoerg   }
96606f32e7eSjoerg 
96706f32e7eSjoerg   return false;
96806f32e7eSjoerg }
96906f32e7eSjoerg 
97006f32e7eSjoerg void
updateSummaryFromAnnotations(const RetainSummary * & Summ,const FunctionDecl * FD)97106f32e7eSjoerg RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
97206f32e7eSjoerg                                                    const FunctionDecl *FD) {
97306f32e7eSjoerg   if (!FD)
97406f32e7eSjoerg     return;
97506f32e7eSjoerg 
97606f32e7eSjoerg   assert(Summ && "Must have a summary to add annotations to.");
97706f32e7eSjoerg   RetainSummaryTemplate Template(Summ, *this);
97806f32e7eSjoerg 
97906f32e7eSjoerg   // Effects on the parameters.
98006f32e7eSjoerg   unsigned parm_idx = 0;
98106f32e7eSjoerg   for (auto pi = FD->param_begin(),
98206f32e7eSjoerg          pe = FD->param_end(); pi != pe; ++pi, ++parm_idx)
98306f32e7eSjoerg     applyParamAnnotationEffect(*pi, parm_idx, FD, Template);
98406f32e7eSjoerg 
98506f32e7eSjoerg   QualType RetTy = FD->getReturnType();
98606f32e7eSjoerg   if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
98706f32e7eSjoerg     Template->setRetEffect(*RetE);
98806f32e7eSjoerg 
98906f32e7eSjoerg   if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
99006f32e7eSjoerg     Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));
99106f32e7eSjoerg }
99206f32e7eSjoerg 
99306f32e7eSjoerg void
updateSummaryFromAnnotations(const RetainSummary * & Summ,const ObjCMethodDecl * MD)99406f32e7eSjoerg RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
99506f32e7eSjoerg                                                    const ObjCMethodDecl *MD) {
99606f32e7eSjoerg   if (!MD)
99706f32e7eSjoerg     return;
99806f32e7eSjoerg 
99906f32e7eSjoerg   assert(Summ && "Must have a valid summary to add annotations to");
100006f32e7eSjoerg   RetainSummaryTemplate Template(Summ, *this);
100106f32e7eSjoerg 
100206f32e7eSjoerg   // Effects on the receiver.
100306f32e7eSjoerg   if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
100406f32e7eSjoerg     Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC));
100506f32e7eSjoerg 
100606f32e7eSjoerg   // Effects on the parameters.
100706f32e7eSjoerg   unsigned parm_idx = 0;
100806f32e7eSjoerg   for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;
100906f32e7eSjoerg        ++pi, ++parm_idx)
101006f32e7eSjoerg     applyParamAnnotationEffect(*pi, parm_idx, MD, Template);
101106f32e7eSjoerg 
101206f32e7eSjoerg   QualType RetTy = MD->getReturnType();
101306f32e7eSjoerg   if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
101406f32e7eSjoerg     Template->setRetEffect(*RetE);
101506f32e7eSjoerg }
101606f32e7eSjoerg 
101706f32e7eSjoerg const RetainSummary *
getStandardMethodSummary(const ObjCMethodDecl * MD,Selector S,QualType RetTy)101806f32e7eSjoerg RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
101906f32e7eSjoerg                                                Selector S, QualType RetTy) {
102006f32e7eSjoerg   // Any special effects?
102106f32e7eSjoerg   ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC);
102206f32e7eSjoerg   RetEffect ResultEff = RetEffect::MakeNoRet();
102306f32e7eSjoerg 
102406f32e7eSjoerg   // Check the method family, and apply any default annotations.
102506f32e7eSjoerg   switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
102606f32e7eSjoerg     case OMF_None:
102706f32e7eSjoerg     case OMF_initialize:
102806f32e7eSjoerg     case OMF_performSelector:
102906f32e7eSjoerg       // Assume all Objective-C methods follow Cocoa Memory Management rules.
103006f32e7eSjoerg       // FIXME: Does the non-threaded performSelector family really belong here?
103106f32e7eSjoerg       // The selector could be, say, @selector(copy).
103206f32e7eSjoerg       if (cocoa::isCocoaObjectRef(RetTy))
103306f32e7eSjoerg         ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC);
103406f32e7eSjoerg       else if (coreFoundation::isCFObjectRef(RetTy)) {
103506f32e7eSjoerg         // ObjCMethodDecl currently doesn't consider CF objects as valid return
103606f32e7eSjoerg         // values for alloc, new, copy, or mutableCopy, so we have to
103706f32e7eSjoerg         // double-check with the selector. This is ugly, but there aren't that
103806f32e7eSjoerg         // many Objective-C methods that return CF objects, right?
103906f32e7eSjoerg         if (MD) {
104006f32e7eSjoerg           switch (S.getMethodFamily()) {
104106f32e7eSjoerg           case OMF_alloc:
104206f32e7eSjoerg           case OMF_new:
104306f32e7eSjoerg           case OMF_copy:
104406f32e7eSjoerg           case OMF_mutableCopy:
104506f32e7eSjoerg             ResultEff = RetEffect::MakeOwned(ObjKind::CF);
104606f32e7eSjoerg             break;
104706f32e7eSjoerg           default:
104806f32e7eSjoerg             ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
104906f32e7eSjoerg             break;
105006f32e7eSjoerg           }
105106f32e7eSjoerg         } else {
105206f32e7eSjoerg           ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
105306f32e7eSjoerg         }
105406f32e7eSjoerg       }
105506f32e7eSjoerg       break;
105606f32e7eSjoerg     case OMF_init:
105706f32e7eSjoerg       ResultEff = ObjCInitRetE;
105806f32e7eSjoerg       ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
105906f32e7eSjoerg       break;
106006f32e7eSjoerg     case OMF_alloc:
106106f32e7eSjoerg     case OMF_new:
106206f32e7eSjoerg     case OMF_copy:
106306f32e7eSjoerg     case OMF_mutableCopy:
106406f32e7eSjoerg       if (cocoa::isCocoaObjectRef(RetTy))
106506f32e7eSjoerg         ResultEff = ObjCAllocRetE;
106606f32e7eSjoerg       else if (coreFoundation::isCFObjectRef(RetTy))
106706f32e7eSjoerg         ResultEff = RetEffect::MakeOwned(ObjKind::CF);
106806f32e7eSjoerg       break;
106906f32e7eSjoerg     case OMF_autorelease:
107006f32e7eSjoerg       ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);
107106f32e7eSjoerg       break;
107206f32e7eSjoerg     case OMF_retain:
107306f32e7eSjoerg       ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC);
107406f32e7eSjoerg       break;
107506f32e7eSjoerg     case OMF_release:
107606f32e7eSjoerg       ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
107706f32e7eSjoerg       break;
107806f32e7eSjoerg     case OMF_dealloc:
107906f32e7eSjoerg       ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);
108006f32e7eSjoerg       break;
108106f32e7eSjoerg     case OMF_self:
108206f32e7eSjoerg       // -self is handled specially by the ExprEngine to propagate the receiver.
108306f32e7eSjoerg       break;
108406f32e7eSjoerg     case OMF_retainCount:
108506f32e7eSjoerg     case OMF_finalize:
108606f32e7eSjoerg       // These methods don't return objects.
108706f32e7eSjoerg       break;
108806f32e7eSjoerg   }
108906f32e7eSjoerg 
109006f32e7eSjoerg   // If one of the arguments in the selector has the keyword 'delegate' we
109106f32e7eSjoerg   // should stop tracking the reference count for the receiver.  This is
109206f32e7eSjoerg   // because the reference count is quite possibly handled by a delegate
109306f32e7eSjoerg   // method.
109406f32e7eSjoerg   if (S.isKeywordSelector()) {
109506f32e7eSjoerg     for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {
109606f32e7eSjoerg       StringRef Slot = S.getNameForSlot(i);
109706f32e7eSjoerg       if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) {
109806f32e7eSjoerg         if (ResultEff == ObjCInitRetE)
109906f32e7eSjoerg           ResultEff = RetEffect::MakeNoRetHard();
110006f32e7eSjoerg         else
110106f32e7eSjoerg           ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC);
110206f32e7eSjoerg       }
110306f32e7eSjoerg     }
110406f32e7eSjoerg   }
110506f32e7eSjoerg 
110606f32e7eSjoerg   if (ReceiverEff.getKind() == DoNothing &&
110706f32e7eSjoerg       ResultEff.getKind() == RetEffect::NoRet)
110806f32e7eSjoerg     return getDefaultSummary();
110906f32e7eSjoerg 
111006f32e7eSjoerg   return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
111106f32e7eSjoerg                               ArgEffect(ReceiverEff), ArgEffect(MayEscape));
111206f32e7eSjoerg }
111306f32e7eSjoerg 
111406f32e7eSjoerg const RetainSummary *
getClassMethodSummary(const ObjCMessageExpr * ME)111506f32e7eSjoerg RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
111606f32e7eSjoerg   assert(!ME->isInstanceMessage());
111706f32e7eSjoerg   const ObjCInterfaceDecl *Class = ME->getReceiverInterface();
111806f32e7eSjoerg 
111906f32e7eSjoerg   return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
112006f32e7eSjoerg                           ME->getType(), ObjCClassMethodSummaries);
112106f32e7eSjoerg }
112206f32e7eSjoerg 
getInstanceMethodSummary(const ObjCMessageExpr * ME,QualType ReceiverType)112306f32e7eSjoerg const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
112406f32e7eSjoerg     const ObjCMessageExpr *ME,
112506f32e7eSjoerg     QualType ReceiverType) {
112606f32e7eSjoerg   const ObjCInterfaceDecl *ReceiverClass = nullptr;
112706f32e7eSjoerg 
112806f32e7eSjoerg   // We do better tracking of the type of the object than the core ExprEngine.
112906f32e7eSjoerg   // See if we have its type in our private state.
113006f32e7eSjoerg   if (!ReceiverType.isNull())
113106f32e7eSjoerg     if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
113206f32e7eSjoerg       ReceiverClass = PT->getInterfaceDecl();
113306f32e7eSjoerg 
113406f32e7eSjoerg   // If we don't know what kind of object this is, fall back to its static type.
113506f32e7eSjoerg   if (!ReceiverClass)
113606f32e7eSjoerg     ReceiverClass = ME->getReceiverInterface();
113706f32e7eSjoerg 
113806f32e7eSjoerg   // FIXME: The receiver could be a reference to a class, meaning that
113906f32e7eSjoerg   //  we should use the class method.
114006f32e7eSjoerg   // id x = [NSObject class];
114106f32e7eSjoerg   // [x performSelector:... withObject:... afterDelay:...];
114206f32e7eSjoerg   Selector S = ME->getSelector();
114306f32e7eSjoerg   const ObjCMethodDecl *Method = ME->getMethodDecl();
114406f32e7eSjoerg   if (!Method && ReceiverClass)
114506f32e7eSjoerg     Method = ReceiverClass->getInstanceMethod(S);
114606f32e7eSjoerg 
114706f32e7eSjoerg   return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
114806f32e7eSjoerg                           ObjCMethodSummaries);
114906f32e7eSjoerg }
115006f32e7eSjoerg 
115106f32e7eSjoerg const RetainSummary *
getMethodSummary(Selector S,const ObjCInterfaceDecl * ID,const ObjCMethodDecl * MD,QualType RetTy,ObjCMethodSummariesTy & CachedSummaries)115206f32e7eSjoerg RetainSummaryManager::getMethodSummary(Selector S,
115306f32e7eSjoerg                                        const ObjCInterfaceDecl *ID,
115406f32e7eSjoerg                                        const ObjCMethodDecl *MD, QualType RetTy,
115506f32e7eSjoerg                                        ObjCMethodSummariesTy &CachedSummaries) {
115606f32e7eSjoerg 
115706f32e7eSjoerg   // Objective-C method summaries are only applicable to ObjC and CF objects.
115806f32e7eSjoerg   if (!TrackObjCAndCFObjects)
115906f32e7eSjoerg     return getDefaultSummary();
116006f32e7eSjoerg 
116106f32e7eSjoerg   // Look up a summary in our summary cache.
116206f32e7eSjoerg   const RetainSummary *Summ = CachedSummaries.find(ID, S);
116306f32e7eSjoerg 
116406f32e7eSjoerg   if (!Summ) {
116506f32e7eSjoerg     Summ = getStandardMethodSummary(MD, S, RetTy);
116606f32e7eSjoerg 
116706f32e7eSjoerg     // Annotations override defaults.
116806f32e7eSjoerg     updateSummaryFromAnnotations(Summ, MD);
116906f32e7eSjoerg 
117006f32e7eSjoerg     // Memoize the summary.
117106f32e7eSjoerg     CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
117206f32e7eSjoerg   }
117306f32e7eSjoerg 
117406f32e7eSjoerg   return Summ;
117506f32e7eSjoerg }
117606f32e7eSjoerg 
InitializeClassMethodSummaries()117706f32e7eSjoerg void RetainSummaryManager::InitializeClassMethodSummaries() {
117806f32e7eSjoerg   ArgEffects ScratchArgs = AF.getEmptyMap();
117906f32e7eSjoerg 
118006f32e7eSjoerg   // Create the [NSAssertionHandler currentHander] summary.
118106f32e7eSjoerg   addClassMethSummary("NSAssertionHandler", "currentHandler",
118206f32e7eSjoerg                 getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),
118306f32e7eSjoerg                                      ScratchArgs));
118406f32e7eSjoerg 
118506f32e7eSjoerg   // Create the [NSAutoreleasePool addObject:] summary.
118606f32e7eSjoerg   ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
118706f32e7eSjoerg   addClassMethSummary("NSAutoreleasePool", "addObject",
118806f32e7eSjoerg                       getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
118906f32e7eSjoerg                                            ArgEffect(DoNothing),
119006f32e7eSjoerg                                            ArgEffect(Autorelease)));
119106f32e7eSjoerg }
119206f32e7eSjoerg 
InitializeMethodSummaries()119306f32e7eSjoerg void RetainSummaryManager::InitializeMethodSummaries() {
119406f32e7eSjoerg 
119506f32e7eSjoerg   ArgEffects ScratchArgs = AF.getEmptyMap();
119606f32e7eSjoerg   // Create the "init" selector.  It just acts as a pass-through for the
119706f32e7eSjoerg   // receiver.
119806f32e7eSjoerg   const RetainSummary *InitSumm = getPersistentSummary(
119906f32e7eSjoerg       ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC));
120006f32e7eSjoerg   addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
120106f32e7eSjoerg 
120206f32e7eSjoerg   // awakeAfterUsingCoder: behaves basically like an 'init' method.  It
120306f32e7eSjoerg   // claims the receiver and returns a retained object.
120406f32e7eSjoerg   addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
120506f32e7eSjoerg                          InitSumm);
120606f32e7eSjoerg 
120706f32e7eSjoerg   // The next methods are allocators.
120806f32e7eSjoerg   const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE,
120906f32e7eSjoerg                                                         ScratchArgs);
121006f32e7eSjoerg   const RetainSummary *CFAllocSumm =
121106f32e7eSjoerg     getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs);
121206f32e7eSjoerg 
121306f32e7eSjoerg   // Create the "retain" selector.
121406f32e7eSjoerg   RetEffect NoRet = RetEffect::MakeNoRet();
121506f32e7eSjoerg   const RetainSummary *Summ = getPersistentSummary(
121606f32e7eSjoerg       NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));
121706f32e7eSjoerg   addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
121806f32e7eSjoerg 
121906f32e7eSjoerg   // Create the "release" selector.
122006f32e7eSjoerg   Summ = getPersistentSummary(NoRet, ScratchArgs,
122106f32e7eSjoerg                               ArgEffect(DecRef, ObjKind::ObjC));
122206f32e7eSjoerg   addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
122306f32e7eSjoerg 
122406f32e7eSjoerg   // Create the -dealloc summary.
122506f32e7eSjoerg   Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,
122606f32e7eSjoerg                                                             ObjKind::ObjC));
122706f32e7eSjoerg   addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
122806f32e7eSjoerg 
122906f32e7eSjoerg   // Create the "autorelease" selector.
123006f32e7eSjoerg   Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,
123106f32e7eSjoerg                                                             ObjKind::ObjC));
123206f32e7eSjoerg   addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
123306f32e7eSjoerg 
123406f32e7eSjoerg   // For NSWindow, allocated objects are (initially) self-owned.
123506f32e7eSjoerg   // FIXME: For now we opt for false negatives with NSWindow, as these objects
123606f32e7eSjoerg   //  self-own themselves.  However, they only do this once they are displayed.
123706f32e7eSjoerg   //  Thus, we need to track an NSWindow's display status.
123806f32e7eSjoerg   //  This is tracked in <rdar://problem/6062711>.
123906f32e7eSjoerg   //  See also http://llvm.org/bugs/show_bug.cgi?id=3714.
124006f32e7eSjoerg   const RetainSummary *NoTrackYet =
124106f32e7eSjoerg       getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
124206f32e7eSjoerg                            ArgEffect(StopTracking), ArgEffect(StopTracking));
124306f32e7eSjoerg 
124406f32e7eSjoerg   addClassMethSummary("NSWindow", "alloc", NoTrackYet);
124506f32e7eSjoerg 
124606f32e7eSjoerg   // For NSPanel (which subclasses NSWindow), allocated objects are not
124706f32e7eSjoerg   //  self-owned.
124806f32e7eSjoerg   // FIXME: For now we don't track NSPanels. object for the same reason
124906f32e7eSjoerg   //   as for NSWindow objects.
125006f32e7eSjoerg   addClassMethSummary("NSPanel", "alloc", NoTrackYet);
125106f32e7eSjoerg 
125206f32e7eSjoerg   // For NSNull, objects returned by +null are singletons that ignore
125306f32e7eSjoerg   // retain/release semantics.  Just don't track them.
125406f32e7eSjoerg   // <rdar://problem/12858915>
125506f32e7eSjoerg   addClassMethSummary("NSNull", "null", NoTrackYet);
125606f32e7eSjoerg 
125706f32e7eSjoerg   // Don't track allocated autorelease pools, as it is okay to prematurely
125806f32e7eSjoerg   // exit a method.
125906f32e7eSjoerg   addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
126006f32e7eSjoerg   addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
126106f32e7eSjoerg   addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
126206f32e7eSjoerg 
126306f32e7eSjoerg   // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
126406f32e7eSjoerg   addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
126506f32e7eSjoerg   addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
126606f32e7eSjoerg 
126706f32e7eSjoerg   // Create summaries for CIContext, 'createCGImage' and
126806f32e7eSjoerg   // 'createCGLayerWithSize'.  These objects are CF objects, and are not
126906f32e7eSjoerg   // automatically garbage collected.
127006f32e7eSjoerg   addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
127106f32e7eSjoerg   addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
127206f32e7eSjoerg                      "format", "colorSpace");
127306f32e7eSjoerg   addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
127406f32e7eSjoerg }
127506f32e7eSjoerg 
127606f32e7eSjoerg const RetainSummary *
getMethodSummary(const ObjCMethodDecl * MD)127706f32e7eSjoerg RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
127806f32e7eSjoerg   const ObjCInterfaceDecl *ID = MD->getClassInterface();
127906f32e7eSjoerg   Selector S = MD->getSelector();
128006f32e7eSjoerg   QualType ResultTy = MD->getReturnType();
128106f32e7eSjoerg 
128206f32e7eSjoerg   ObjCMethodSummariesTy *CachedSummaries;
128306f32e7eSjoerg   if (MD->isInstanceMethod())
128406f32e7eSjoerg     CachedSummaries = &ObjCMethodSummaries;
128506f32e7eSjoerg   else
128606f32e7eSjoerg     CachedSummaries = &ObjCClassMethodSummaries;
128706f32e7eSjoerg 
128806f32e7eSjoerg   return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
128906f32e7eSjoerg }
1290