10b57cec5SDimitry Andric //== RetainSummaryManager.cpp - Summaries for reference counting --*- C++ -*--//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines summaries implementation for retain counting, which
100b57cec5SDimitry Andric // implements a reference count checker for Core Foundation, Cocoa
110b57cec5SDimitry Andric // and OSObject (on Mac OS X).
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
160b57cec5SDimitry Andric #include "clang/Analysis/RetainSummaryManager.h"
170b57cec5SDimitry Andric #include "clang/AST/Attr.h"
180b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
190b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h"
200b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
210b57cec5SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
22bdd1243dSDimitry Andric #include <optional>
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric using namespace clang;
250b57cec5SDimitry Andric using namespace ento;
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric template <class T>
isOneOf()280b57cec5SDimitry Andric constexpr static bool isOneOf() {
290b57cec5SDimitry Andric return false;
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric /// Helper function to check whether the class is one of the
330b57cec5SDimitry Andric /// rest of varargs.
340b57cec5SDimitry Andric template <class T, class P, class... ToCompare>
isOneOf()350b57cec5SDimitry Andric constexpr static bool isOneOf() {
36bdd1243dSDimitry Andric return std::is_same_v<T, P> || isOneOf<T, ToCompare...>();
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric namespace {
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric /// Fake attribute class for RC* attributes.
420b57cec5SDimitry Andric struct GeneralizedReturnsRetainedAttr {
classof__anon8b1706cb0111::GeneralizedReturnsRetainedAttr430b57cec5SDimitry Andric static bool classof(const Attr *A) {
440b57cec5SDimitry Andric if (auto AA = dyn_cast<AnnotateAttr>(A))
450b57cec5SDimitry Andric return AA->getAnnotation() == "rc_ownership_returns_retained";
460b57cec5SDimitry Andric return false;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric };
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric struct GeneralizedReturnsNotRetainedAttr {
classof__anon8b1706cb0111::GeneralizedReturnsNotRetainedAttr510b57cec5SDimitry Andric static bool classof(const Attr *A) {
520b57cec5SDimitry Andric if (auto AA = dyn_cast<AnnotateAttr>(A))
530b57cec5SDimitry Andric return AA->getAnnotation() == "rc_ownership_returns_not_retained";
540b57cec5SDimitry Andric return false;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric struct GeneralizedConsumedAttr {
classof__anon8b1706cb0111::GeneralizedConsumedAttr590b57cec5SDimitry Andric static bool classof(const Attr *A) {
600b57cec5SDimitry Andric if (auto AA = dyn_cast<AnnotateAttr>(A))
610b57cec5SDimitry Andric return AA->getAnnotation() == "rc_ownership_consumed";
620b57cec5SDimitry Andric return false;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric };
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric template <class T>
hasAnyEnabledAttrOf(const Decl * D,QualType QT)69bdd1243dSDimitry Andric std::optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
700b57cec5SDimitry Andric QualType QT) {
710b57cec5SDimitry Andric ObjKind K;
720b57cec5SDimitry Andric if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,
730b57cec5SDimitry Andric CFReturnsNotRetainedAttr>()) {
740b57cec5SDimitry Andric if (!TrackObjCAndCFObjects)
75bdd1243dSDimitry Andric return std::nullopt;
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric K = ObjKind::CF;
780b57cec5SDimitry Andric } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
790b57cec5SDimitry Andric NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
800b57cec5SDimitry Andric NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric if (!TrackObjCAndCFObjects)
83bdd1243dSDimitry Andric return std::nullopt;
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
860b57cec5SDimitry Andric NSReturnsNotRetainedAttr>() &&
870b57cec5SDimitry Andric !cocoa::isCocoaObjectRef(QT))
88bdd1243dSDimitry Andric return std::nullopt;
890b57cec5SDimitry Andric K = ObjKind::ObjC;
900b57cec5SDimitry Andric } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,
910b57cec5SDimitry Andric OSReturnsNotRetainedAttr, OSReturnsRetainedAttr,
920b57cec5SDimitry Andric OSReturnsRetainedOnZeroAttr,
930b57cec5SDimitry Andric OSReturnsRetainedOnNonZeroAttr>()) {
940b57cec5SDimitry Andric if (!TrackOSObjects)
95bdd1243dSDimitry Andric return std::nullopt;
960b57cec5SDimitry Andric K = ObjKind::OS;
970b57cec5SDimitry Andric } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,
980b57cec5SDimitry Andric GeneralizedReturnsRetainedAttr,
990b57cec5SDimitry Andric GeneralizedConsumedAttr>()) {
1000b57cec5SDimitry Andric K = ObjKind::Generalized;
1010b57cec5SDimitry Andric } else {
1020b57cec5SDimitry Andric llvm_unreachable("Unexpected attribute");
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric if (D->hasAttr<T>())
1050b57cec5SDimitry Andric return K;
106bdd1243dSDimitry Andric return std::nullopt;
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric template <class T1, class T2, class... Others>
hasAnyEnabledAttrOf(const Decl * D,QualType QT)110bdd1243dSDimitry Andric std::optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
1110b57cec5SDimitry Andric QualType QT) {
1120b57cec5SDimitry Andric if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))
1130b57cec5SDimitry Andric return Out;
1140b57cec5SDimitry Andric return hasAnyEnabledAttrOf<T2, Others...>(D, QT);
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric const RetainSummary *
getPersistentSummary(const RetainSummary & OldSumm)1180b57cec5SDimitry Andric RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
1190b57cec5SDimitry Andric // Unique "simple" summaries -- those without ArgEffects.
1200b57cec5SDimitry Andric if (OldSumm.isSimple()) {
1210b57cec5SDimitry Andric ::llvm::FoldingSetNodeID ID;
1220b57cec5SDimitry Andric OldSumm.Profile(ID);
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric void *Pos;
1250b57cec5SDimitry Andric CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric if (!N) {
1280b57cec5SDimitry Andric N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
1290b57cec5SDimitry Andric new (N) CachedSummaryNode(OldSumm);
1300b57cec5SDimitry Andric SimpleSummaries.InsertNode(N, Pos);
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric
1330b57cec5SDimitry Andric return &N->getValue();
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
1370b57cec5SDimitry Andric new (Summ) RetainSummary(OldSumm);
1380b57cec5SDimitry Andric return Summ;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
isSubclass(const Decl * D,StringRef ClassName)1410b57cec5SDimitry Andric static bool isSubclass(const Decl *D,
1420b57cec5SDimitry Andric StringRef ClassName) {
1430b57cec5SDimitry Andric using namespace ast_matchers;
1445ffd83dbSDimitry Andric DeclarationMatcher SubclassM =
1455ffd83dbSDimitry Andric cxxRecordDecl(isSameOrDerivedFrom(std::string(ClassName)));
1460b57cec5SDimitry Andric return !(match(SubclassM, *D, D->getASTContext()).empty());
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
isExactClass(const Decl * D,StringRef ClassName)149fe6060f1SDimitry Andric static bool isExactClass(const Decl *D, StringRef ClassName) {
150fe6060f1SDimitry Andric using namespace ast_matchers;
151fe6060f1SDimitry Andric DeclarationMatcher sameClassM =
152fe6060f1SDimitry Andric cxxRecordDecl(hasName(std::string(ClassName)));
153fe6060f1SDimitry Andric return !(match(sameClassM, *D, D->getASTContext()).empty());
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric
isOSObjectSubclass(const Decl * D)156fe6060f1SDimitry Andric static bool isOSObjectSubclass(const Decl *D) {
157fe6060f1SDimitry Andric return D && isSubclass(D, "OSMetaClassBase") &&
158fe6060f1SDimitry Andric !isExactClass(D, "OSMetaClass");
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric
isOSObjectDynamicCast(StringRef S)161fe6060f1SDimitry Andric static bool isOSObjectDynamicCast(StringRef S) { return S == "safeMetaCast"; }
162fe6060f1SDimitry Andric
isOSObjectRequiredCast(StringRef S)1630b57cec5SDimitry Andric static bool isOSObjectRequiredCast(StringRef S) {
1640b57cec5SDimitry Andric return S == "requiredMetaCast";
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric
isOSObjectThisCast(StringRef S)1670b57cec5SDimitry Andric static bool isOSObjectThisCast(StringRef S) {
1680b57cec5SDimitry Andric return S == "metaCast";
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric
isOSObjectPtr(QualType QT)1720b57cec5SDimitry Andric static bool isOSObjectPtr(QualType QT) {
1730b57cec5SDimitry Andric return isOSObjectSubclass(QT->getPointeeCXXRecordDecl());
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
isISLObjectRef(QualType Ty)1760b57cec5SDimitry Andric static bool isISLObjectRef(QualType Ty) {
1775f757f3fSDimitry Andric return StringRef(Ty.getAsString()).starts_with("isl_");
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
isOSIteratorSubclass(const Decl * D)1800b57cec5SDimitry Andric static bool isOSIteratorSubclass(const Decl *D) {
1810b57cec5SDimitry Andric return isSubclass(D, "OSIterator");
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric
hasRCAnnotation(const Decl * D,StringRef rcAnnotation)1840b57cec5SDimitry Andric static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
1850b57cec5SDimitry Andric for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
1860b57cec5SDimitry Andric if (Ann->getAnnotation() == rcAnnotation)
1870b57cec5SDimitry Andric return true;
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric return false;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric
isRetain(const FunctionDecl * FD,StringRef FName)1920b57cec5SDimitry Andric static bool isRetain(const FunctionDecl *FD, StringRef FName) {
19306c3fb27SDimitry Andric return FName.starts_with_insensitive("retain") ||
19406c3fb27SDimitry Andric FName.ends_with_insensitive("retain");
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
isRelease(const FunctionDecl * FD,StringRef FName)1970b57cec5SDimitry Andric static bool isRelease(const FunctionDecl *FD, StringRef FName) {
19806c3fb27SDimitry Andric return FName.starts_with_insensitive("release") ||
19906c3fb27SDimitry Andric FName.ends_with_insensitive("release");
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric
isAutorelease(const FunctionDecl * FD,StringRef FName)2020b57cec5SDimitry Andric static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
20306c3fb27SDimitry Andric return FName.starts_with_insensitive("autorelease") ||
20406c3fb27SDimitry Andric FName.ends_with_insensitive("autorelease");
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric
isMakeCollectable(StringRef FName)2070b57cec5SDimitry Andric static bool isMakeCollectable(StringRef FName) {
208fe6060f1SDimitry Andric return FName.contains_insensitive("MakeCollectable");
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric /// A function is OSObject related if it is declared on a subclass
2120b57cec5SDimitry Andric /// of OSObject, or any of the parameters is a subclass of an OSObject.
isOSObjectRelated(const CXXMethodDecl * MD)2130b57cec5SDimitry Andric static bool isOSObjectRelated(const CXXMethodDecl *MD) {
2140b57cec5SDimitry Andric if (isOSObjectSubclass(MD->getParent()))
2150b57cec5SDimitry Andric return true;
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric for (ParmVarDecl *Param : MD->parameters()) {
2180b57cec5SDimitry Andric QualType PT = Param->getType()->getPointeeType();
2190b57cec5SDimitry Andric if (!PT.isNull())
2200b57cec5SDimitry Andric if (CXXRecordDecl *RD = PT->getAsCXXRecordDecl())
2210b57cec5SDimitry Andric if (isOSObjectSubclass(RD))
2220b57cec5SDimitry Andric return true;
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric
2250b57cec5SDimitry Andric return false;
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric bool
isKnownSmartPointer(QualType QT)2290b57cec5SDimitry Andric RetainSummaryManager::isKnownSmartPointer(QualType QT) {
2300b57cec5SDimitry Andric QT = QT.getCanonicalType();
2310b57cec5SDimitry Andric const auto *RD = QT->getAsCXXRecordDecl();
2320b57cec5SDimitry Andric if (!RD)
2330b57cec5SDimitry Andric return false;
2340b57cec5SDimitry Andric const IdentifierInfo *II = RD->getIdentifier();
2350b57cec5SDimitry Andric if (II && II->getName() == "smart_ptr")
2360b57cec5SDimitry Andric if (const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()))
2370b57cec5SDimitry Andric if (ND->getNameAsString() == "os")
2380b57cec5SDimitry Andric return true;
2390b57cec5SDimitry Andric return false;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric const RetainSummary *
getSummaryForOSObject(const FunctionDecl * FD,StringRef FName,QualType RetTy)2430b57cec5SDimitry Andric RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD,
2440b57cec5SDimitry Andric StringRef FName, QualType RetTy) {
2450b57cec5SDimitry Andric assert(TrackOSObjects &&
2460b57cec5SDimitry Andric "Requesting a summary for an OSObject but OSObjects are not tracked");
2470b57cec5SDimitry Andric
2480b57cec5SDimitry Andric if (RetTy->isPointerType()) {
2490b57cec5SDimitry Andric const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl();
2500b57cec5SDimitry Andric if (PD && isOSObjectSubclass(PD)) {
2510b57cec5SDimitry Andric if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) ||
2520b57cec5SDimitry Andric isOSObjectThisCast(FName))
2530b57cec5SDimitry Andric return getDefaultSummary();
2540b57cec5SDimitry Andric
2550b57cec5SDimitry Andric // TODO: Add support for the slightly common *Matching(table) idiom.
2560b57cec5SDimitry Andric // Cf. IOService::nameMatching() etc. - these function have an unusual
2570b57cec5SDimitry Andric // contract of returning at +0 or +1 depending on their last argument.
2585f757f3fSDimitry Andric if (FName.ends_with("Matching")) {
2590b57cec5SDimitry Andric return getPersistentStopSummary();
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric // All objects returned with functions *not* starting with 'get',
2630b57cec5SDimitry Andric // or iterators, are returned at +1.
2645f757f3fSDimitry Andric if ((!FName.starts_with("get") && !FName.starts_with("Get")) ||
2650b57cec5SDimitry Andric isOSIteratorSubclass(PD)) {
2660b57cec5SDimitry Andric return getOSSummaryCreateRule(FD);
2670b57cec5SDimitry Andric } else {
2680b57cec5SDimitry Andric return getOSSummaryGetRule(FD);
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric
2730b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
2740b57cec5SDimitry Andric const CXXRecordDecl *Parent = MD->getParent();
2750b57cec5SDimitry Andric if (Parent && isOSObjectSubclass(Parent)) {
2760b57cec5SDimitry Andric if (FName == "release" || FName == "taggedRelease")
2770b57cec5SDimitry Andric return getOSSummaryReleaseRule(FD);
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric if (FName == "retain" || FName == "taggedRetain")
2800b57cec5SDimitry Andric return getOSSummaryRetainRule(FD);
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric if (FName == "free")
2830b57cec5SDimitry Andric return getOSSummaryFreeRule(FD);
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric if (MD->getOverloadedOperator() == OO_New)
2860b57cec5SDimitry Andric return getOSSummaryCreateRule(MD);
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric return nullptr;
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric
getSummaryForObjCOrCFObject(const FunctionDecl * FD,StringRef FName,QualType RetTy,const FunctionType * FT,bool & AllowAnnotations)2930b57cec5SDimitry Andric const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
2940b57cec5SDimitry Andric const FunctionDecl *FD,
2950b57cec5SDimitry Andric StringRef FName,
2960b57cec5SDimitry Andric QualType RetTy,
2970b57cec5SDimitry Andric const FunctionType *FT,
2980b57cec5SDimitry Andric bool &AllowAnnotations) {
2990b57cec5SDimitry Andric
3000b57cec5SDimitry Andric ArgEffects ScratchArgs(AF.getEmptyMap());
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric std::string RetTyName = RetTy.getAsString();
3030b57cec5SDimitry Andric if (FName == "pthread_create" || FName == "pthread_setspecific") {
3045f757f3fSDimitry Andric // It's not uncommon to pass a tracked object into the thread
3055f757f3fSDimitry Andric // as 'void *arg', and then release it inside the thread.
3065f757f3fSDimitry Andric // FIXME: We could build a much more precise model for these functions.
3070b57cec5SDimitry Andric return getPersistentStopSummary();
3080b57cec5SDimitry Andric } else if(FName == "NSMakeCollectable") {
3090b57cec5SDimitry Andric // Handle: id NSMakeCollectable(CFTypeRef)
3100b57cec5SDimitry Andric AllowAnnotations = false;
3110b57cec5SDimitry Andric return RetTy->isObjCIdType() ? getUnarySummary(FT, DoNothing)
3120b57cec5SDimitry Andric : getPersistentStopSummary();
3130b57cec5SDimitry Andric } else if (FName == "CMBufferQueueDequeueAndRetain" ||
3140b57cec5SDimitry Andric FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
3155f757f3fSDimitry Andric // These API functions are known to NOT act as a CFRetain wrapper.
3165f757f3fSDimitry Andric // They simply make a new object owned by the caller.
3170b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
3180b57cec5SDimitry Andric ScratchArgs,
3190b57cec5SDimitry Andric ArgEffect(DoNothing),
3200b57cec5SDimitry Andric ArgEffect(DoNothing));
3210b57cec5SDimitry Andric } else if (FName == "CFPlugInInstanceCreate") {
3220b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);
3230b57cec5SDimitry Andric } else if (FName == "IORegistryEntrySearchCFProperty" ||
3240b57cec5SDimitry Andric (RetTyName == "CFMutableDictionaryRef" &&
3250b57cec5SDimitry Andric (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" ||
3260b57cec5SDimitry Andric FName == "IOServiceNameMatching" ||
3270b57cec5SDimitry Andric FName == "IORegistryEntryIDMatching" ||
3280b57cec5SDimitry Andric FName == "IOOpenFirmwarePathMatching"))) {
3295f757f3fSDimitry Andric // Yes, these IOKit functions return CF objects.
3305f757f3fSDimitry Andric // They also violate the CF naming convention.
3310b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
3320b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3330b57cec5SDimitry Andric } else if (FName == "IOServiceGetMatchingService" ||
3340b57cec5SDimitry Andric FName == "IOServiceGetMatchingServices") {
3355f757f3fSDimitry Andric // These IOKit functions accept CF objects as arguments.
3365f757f3fSDimitry Andric // They also consume them without an appropriate annotation.
3370b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));
3380b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
3390b57cec5SDimitry Andric ScratchArgs,
3400b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3410b57cec5SDimitry Andric } else if (FName == "IOServiceAddNotification" ||
3420b57cec5SDimitry Andric FName == "IOServiceAddMatchingNotification") {
3435f757f3fSDimitry Andric // More IOKit functions suddenly accepting (and even more suddenly,
3445f757f3fSDimitry Andric // consuming) CF objects.
3450b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));
3460b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
3470b57cec5SDimitry Andric ScratchArgs,
3480b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3490b57cec5SDimitry Andric } else if (FName == "CVPixelBufferCreateWithBytes") {
3500b57cec5SDimitry Andric // Eventually this can be improved by recognizing that the pixel
3510b57cec5SDimitry Andric // buffer passed to CVPixelBufferCreateWithBytes is released via
3520b57cec5SDimitry Andric // a callback and doing full IPA to make sure this is done correctly.
3535f757f3fSDimitry Andric // Note that it's passed as a 'void *', so it's hard to annotate.
3545f757f3fSDimitry Andric // FIXME: This function also has an out parameter that returns an
3550b57cec5SDimitry Andric // allocated object.
3560b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));
3570b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
3580b57cec5SDimitry Andric ScratchArgs,
3590b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3600b57cec5SDimitry Andric } else if (FName == "CGBitmapContextCreateWithData") {
3615f757f3fSDimitry Andric // This is similar to the CVPixelBufferCreateWithBytes situation above.
3620b57cec5SDimitry Andric // Eventually this can be improved by recognizing that 'releaseInfo'
3630b57cec5SDimitry Andric // passed to CGBitmapContextCreateWithData is released via
3640b57cec5SDimitry Andric // a callback and doing full IPA to make sure this is done correctly.
3650b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));
3660b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
3670b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3680b57cec5SDimitry Andric } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
3695f757f3fSDimitry Andric // Same as CVPixelBufferCreateWithBytes, just more arguments.
3700b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));
3710b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
3720b57cec5SDimitry Andric ScratchArgs,
3730b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3745f757f3fSDimitry Andric } else if (FName == "VTCompressionSessionEncodeFrame" ||
3755f757f3fSDimitry Andric FName == "VTCompressionSessionEncodeMultiImageFrame") {
3765f757f3fSDimitry Andric // The context argument passed to VTCompressionSessionEncodeFrame() et.al.
3770b57cec5SDimitry Andric // is passed to the callback specified when creating the session
3780b57cec5SDimitry Andric // (e.g. with VTCompressionSessionCreate()) which can release it.
3790b57cec5SDimitry Andric // To account for this possibility, conservatively stop tracking
3800b57cec5SDimitry Andric // the context.
3810b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));
3820b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
3830b57cec5SDimitry Andric ScratchArgs,
3840b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3850b57cec5SDimitry Andric } else if (FName == "dispatch_set_context" ||
3860b57cec5SDimitry Andric FName == "xpc_connection_set_context") {
3875f757f3fSDimitry Andric // The analyzer currently doesn't have a good way to reason about
3885f757f3fSDimitry Andric // dispatch_set_finalizer_f() which typically cleans up the context.
3890b57cec5SDimitry Andric // If we pass a context object that is memory managed, stop tracking it.
3905f757f3fSDimitry Andric // Same with xpc_connection_set_finalizer_f().
3910b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
3920b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
3930b57cec5SDimitry Andric ScratchArgs,
3940b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
3955f757f3fSDimitry Andric } else if (FName.starts_with("NSLog")) {
3960b57cec5SDimitry Andric return getDoNothingSummary();
3975f757f3fSDimitry Andric } else if (FName.starts_with("NS") && FName.contains("Insert")) {
39881ad6265SDimitry Andric // Allowlist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
3995f757f3fSDimitry Andric // be deallocated by NSMapRemove.
4000b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
4010b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));
4020b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
4030b57cec5SDimitry Andric ScratchArgs, ArgEffect(DoNothing),
4040b57cec5SDimitry Andric ArgEffect(DoNothing));
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric
4070b57cec5SDimitry Andric if (RetTy->isPointerType()) {
4080b57cec5SDimitry Andric
4090b57cec5SDimitry Andric // For CoreFoundation ('CF') types.
4100b57cec5SDimitry Andric if (cocoa::isRefType(RetTy, "CF", FName)) {
4110b57cec5SDimitry Andric if (isRetain(FD, FName)) {
4120b57cec5SDimitry Andric // CFRetain isn't supposed to be annotated. However, this may as
4130b57cec5SDimitry Andric // well be a user-made "safe" CFRetain function that is incorrectly
4140b57cec5SDimitry Andric // annotated as cf_returns_retained due to lack of better options.
4150b57cec5SDimitry Andric // We want to ignore such annotation.
4160b57cec5SDimitry Andric AllowAnnotations = false;
4170b57cec5SDimitry Andric
4180b57cec5SDimitry Andric return getUnarySummary(FT, IncRef);
4190b57cec5SDimitry Andric } else if (isAutorelease(FD, FName)) {
4200b57cec5SDimitry Andric // The headers use cf_consumed, but we can fully model CFAutorelease
4210b57cec5SDimitry Andric // ourselves.
4220b57cec5SDimitry Andric AllowAnnotations = false;
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric return getUnarySummary(FT, Autorelease);
4250b57cec5SDimitry Andric } else if (isMakeCollectable(FName)) {
4260b57cec5SDimitry Andric AllowAnnotations = false;
4270b57cec5SDimitry Andric return getUnarySummary(FT, DoNothing);
4280b57cec5SDimitry Andric } else {
4290b57cec5SDimitry Andric return getCFCreateGetRuleSummary(FD);
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric
4330b57cec5SDimitry Andric // For CoreGraphics ('CG') and CoreVideo ('CV') types.
4340b57cec5SDimitry Andric if (cocoa::isRefType(RetTy, "CG", FName) ||
4350b57cec5SDimitry Andric cocoa::isRefType(RetTy, "CV", FName)) {
4360b57cec5SDimitry Andric if (isRetain(FD, FName))
4370b57cec5SDimitry Andric return getUnarySummary(FT, IncRef);
4380b57cec5SDimitry Andric else
4390b57cec5SDimitry Andric return getCFCreateGetRuleSummary(FD);
4400b57cec5SDimitry Andric }
4410b57cec5SDimitry Andric
4420b57cec5SDimitry Andric // For all other CF-style types, use the Create/Get
4430b57cec5SDimitry Andric // rule for summaries but don't support Retain functions
4440b57cec5SDimitry Andric // with framework-specific prefixes.
4450b57cec5SDimitry Andric if (coreFoundation::isCFObjectRef(RetTy)) {
4460b57cec5SDimitry Andric return getCFCreateGetRuleSummary(FD);
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andric if (FD->hasAttr<CFAuditedTransferAttr>()) {
4500b57cec5SDimitry Andric return getCFCreateGetRuleSummary(FD);
4510b57cec5SDimitry Andric }
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric
4540b57cec5SDimitry Andric // Check for release functions, the only kind of functions that we care
4550b57cec5SDimitry Andric // about that don't return a pointer type.
4565f757f3fSDimitry Andric if (FName.starts_with("CG") || FName.starts_with("CF")) {
4570b57cec5SDimitry Andric // Test for 'CGCF'.
4585f757f3fSDimitry Andric FName = FName.substr(FName.starts_with("CGCF") ? 4 : 2);
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric if (isRelease(FD, FName))
4610b57cec5SDimitry Andric return getUnarySummary(FT, DecRef);
4620b57cec5SDimitry Andric else {
4630b57cec5SDimitry Andric assert(ScratchArgs.isEmpty());
4640b57cec5SDimitry Andric // Remaining CoreFoundation and CoreGraphics functions.
4650b57cec5SDimitry Andric // We use to assume that they all strictly followed the ownership idiom
4660b57cec5SDimitry Andric // and that ownership cannot be transferred. While this is technically
4670b57cec5SDimitry Andric // correct, many methods allow a tracked object to escape. For example:
4680b57cec5SDimitry Andric //
4690b57cec5SDimitry Andric // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
4700b57cec5SDimitry Andric // CFDictionaryAddValue(y, key, x);
4710b57cec5SDimitry Andric // CFRelease(x);
4720b57cec5SDimitry Andric // ... it is okay to use 'x' since 'y' has a reference to it
4730b57cec5SDimitry Andric //
4740b57cec5SDimitry Andric // We handle this and similar cases with the follow heuristic. If the
4750b57cec5SDimitry Andric // function name contains "InsertValue", "SetValue", "AddValue",
4760b57cec5SDimitry Andric // "AppendValue", or "SetAttribute", then we assume that arguments may
4770b57cec5SDimitry Andric // "escape." This means that something else holds on to the object,
4780b57cec5SDimitry Andric // allowing it be used even after its local retain count drops to 0.
4790b57cec5SDimitry Andric ArgEffectKind E =
4800b57cec5SDimitry Andric (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
4810b57cec5SDimitry Andric StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
4820b57cec5SDimitry Andric StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
4830b57cec5SDimitry Andric StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
4840b57cec5SDimitry Andric StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
4850b57cec5SDimitry Andric ? MayEscape
4860b57cec5SDimitry Andric : DoNothing;
4870b57cec5SDimitry Andric
4880b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
4890b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF));
4900b57cec5SDimitry Andric }
4910b57cec5SDimitry Andric }
4920b57cec5SDimitry Andric
4930b57cec5SDimitry Andric return nullptr;
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric
4960b57cec5SDimitry Andric const RetainSummary *
generateSummary(const FunctionDecl * FD,bool & AllowAnnotations)4970b57cec5SDimitry Andric RetainSummaryManager::generateSummary(const FunctionDecl *FD,
4980b57cec5SDimitry Andric bool &AllowAnnotations) {
4990b57cec5SDimitry Andric // We generate "stop" summaries for implicitly defined functions.
5000b57cec5SDimitry Andric if (FD->isImplicit())
5010b57cec5SDimitry Andric return getPersistentStopSummary();
5020b57cec5SDimitry Andric
5030b57cec5SDimitry Andric const IdentifierInfo *II = FD->getIdentifier();
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric StringRef FName = II ? II->getName() : "";
5060b57cec5SDimitry Andric
5070b57cec5SDimitry Andric // Strip away preceding '_'. Doing this here will effect all the checks
5080b57cec5SDimitry Andric // down below.
5090b57cec5SDimitry Andric FName = FName.substr(FName.find_first_not_of('_'));
5100b57cec5SDimitry Andric
5110b57cec5SDimitry Andric // Inspect the result type. Strip away any typedefs.
512a7dea167SDimitry Andric const auto *FT = FD->getType()->castAs<FunctionType>();
5130b57cec5SDimitry Andric QualType RetTy = FT->getReturnType();
5140b57cec5SDimitry Andric
5150b57cec5SDimitry Andric if (TrackOSObjects)
5160b57cec5SDimitry Andric if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy))
5170b57cec5SDimitry Andric return S;
5180b57cec5SDimitry Andric
5190b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
5200b57cec5SDimitry Andric if (!isOSObjectRelated(MD))
5210b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
5220b57cec5SDimitry Andric ArgEffects(AF.getEmptyMap()),
5230b57cec5SDimitry Andric ArgEffect(DoNothing),
5240b57cec5SDimitry Andric ArgEffect(StopTracking),
5250b57cec5SDimitry Andric ArgEffect(DoNothing));
5260b57cec5SDimitry Andric
5270b57cec5SDimitry Andric if (TrackObjCAndCFObjects)
5280b57cec5SDimitry Andric if (const RetainSummary *S =
5290b57cec5SDimitry Andric getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations))
5300b57cec5SDimitry Andric return S;
5310b57cec5SDimitry Andric
5320b57cec5SDimitry Andric return getDefaultSummary();
5330b57cec5SDimitry Andric }
5340b57cec5SDimitry Andric
5350b57cec5SDimitry Andric const RetainSummary *
getFunctionSummary(const FunctionDecl * FD)5360b57cec5SDimitry Andric RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
5370b57cec5SDimitry Andric // If we don't know what function we're calling, use our default summary.
5380b57cec5SDimitry Andric if (!FD)
5390b57cec5SDimitry Andric return getDefaultSummary();
5400b57cec5SDimitry Andric
5410b57cec5SDimitry Andric // Look up a summary in our cache of FunctionDecls -> Summaries.
5420b57cec5SDimitry Andric FuncSummariesTy::iterator I = FuncSummaries.find(FD);
5430b57cec5SDimitry Andric if (I != FuncSummaries.end())
5440b57cec5SDimitry Andric return I->second;
5450b57cec5SDimitry Andric
5460b57cec5SDimitry Andric // No summary? Generate one.
5470b57cec5SDimitry Andric bool AllowAnnotations = true;
5480b57cec5SDimitry Andric const RetainSummary *S = generateSummary(FD, AllowAnnotations);
5490b57cec5SDimitry Andric
5500b57cec5SDimitry Andric // Annotations override defaults.
5510b57cec5SDimitry Andric if (AllowAnnotations)
5520b57cec5SDimitry Andric updateSummaryFromAnnotations(S, FD);
5530b57cec5SDimitry Andric
5540b57cec5SDimitry Andric FuncSummaries[FD] = S;
5550b57cec5SDimitry Andric return S;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric
5580b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5590b57cec5SDimitry Andric // Summary creation for functions (largely uses of Core Foundation).
5600b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5610b57cec5SDimitry Andric
getStopTrackingHardEquivalent(ArgEffect E)5620b57cec5SDimitry Andric static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
5630b57cec5SDimitry Andric switch (E.getKind()) {
5640b57cec5SDimitry Andric case DoNothing:
5650b57cec5SDimitry Andric case Autorelease:
5660b57cec5SDimitry Andric case DecRefBridgedTransferred:
5670b57cec5SDimitry Andric case IncRef:
5680b57cec5SDimitry Andric case UnretainedOutParameter:
5690b57cec5SDimitry Andric case RetainedOutParameter:
5700b57cec5SDimitry Andric case RetainedOutParameterOnZero:
5710b57cec5SDimitry Andric case RetainedOutParameterOnNonZero:
5720b57cec5SDimitry Andric case MayEscape:
5730b57cec5SDimitry Andric case StopTracking:
5740b57cec5SDimitry Andric case StopTrackingHard:
5750b57cec5SDimitry Andric return E.withKind(StopTrackingHard);
5760b57cec5SDimitry Andric case DecRef:
5770b57cec5SDimitry Andric case DecRefAndStopTrackingHard:
5780b57cec5SDimitry Andric return E.withKind(DecRefAndStopTrackingHard);
5790b57cec5SDimitry Andric case Dealloc:
5800b57cec5SDimitry Andric return E.withKind(Dealloc);
5810b57cec5SDimitry Andric }
5820b57cec5SDimitry Andric
5830b57cec5SDimitry Andric llvm_unreachable("Unknown ArgEffect kind");
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric
5860b57cec5SDimitry Andric const RetainSummary *
updateSummaryForNonZeroCallbackArg(const RetainSummary * S,AnyCall & C)5870b57cec5SDimitry Andric RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
5880b57cec5SDimitry Andric AnyCall &C) {
5890b57cec5SDimitry Andric ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
5900b57cec5SDimitry Andric ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
5910b57cec5SDimitry Andric
5920b57cec5SDimitry Andric ArgEffects ScratchArgs(AF.getEmptyMap());
5930b57cec5SDimitry Andric ArgEffects CustomArgEffects = S->getArgEffects();
5940b57cec5SDimitry Andric for (ArgEffects::iterator I = CustomArgEffects.begin(),
5950b57cec5SDimitry Andric E = CustomArgEffects.end();
5960b57cec5SDimitry Andric I != E; ++I) {
5970b57cec5SDimitry Andric ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
5980b57cec5SDimitry Andric if (Translated.getKind() != DefEffect.getKind())
5990b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric RetEffect RE = RetEffect::MakeNoRetHard();
6030b57cec5SDimitry Andric
6040b57cec5SDimitry Andric // Special cases where the callback argument CANNOT free the return value.
6050b57cec5SDimitry Andric // This can generally only happen if we know that the callback will only be
6060b57cec5SDimitry Andric // called when the return value is already being deallocated.
6070b57cec5SDimitry Andric if (const IdentifierInfo *Name = C.getIdentifier()) {
6080b57cec5SDimitry Andric // When the CGBitmapContext is deallocated, the callback here will free
6090b57cec5SDimitry Andric // the associated data buffer.
6100b57cec5SDimitry Andric // The callback in dispatch_data_create frees the buffer, but not
6110b57cec5SDimitry Andric // the data object.
6120b57cec5SDimitry Andric if (Name->isStr("CGBitmapContextCreateWithData") ||
6130b57cec5SDimitry Andric Name->isStr("dispatch_data_create"))
6140b57cec5SDimitry Andric RE = S->getRetEffect();
6150b57cec5SDimitry Andric }
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric
updateSummaryForReceiverUnconsumedSelf(const RetainSummary * & S)6200b57cec5SDimitry Andric void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
6210b57cec5SDimitry Andric const RetainSummary *&S) {
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric RetainSummaryTemplate Template(S, *this);
6240b57cec5SDimitry Andric
6250b57cec5SDimitry Andric Template->setReceiverEffect(ArgEffect(DoNothing));
6260b57cec5SDimitry Andric Template->setRetEffect(RetEffect::MakeNoRet());
6270b57cec5SDimitry Andric }
6280b57cec5SDimitry Andric
6290b57cec5SDimitry Andric
updateSummaryForArgumentTypes(const AnyCall & C,const RetainSummary * & RS)6300b57cec5SDimitry Andric void RetainSummaryManager::updateSummaryForArgumentTypes(
6310b57cec5SDimitry Andric const AnyCall &C, const RetainSummary *&RS) {
6320b57cec5SDimitry Andric RetainSummaryTemplate Template(RS, *this);
6330b57cec5SDimitry Andric
6340b57cec5SDimitry Andric unsigned parm_idx = 0;
6350b57cec5SDimitry Andric for (auto pi = C.param_begin(), pe = C.param_end(); pi != pe;
6360b57cec5SDimitry Andric ++pi, ++parm_idx) {
6370b57cec5SDimitry Andric QualType QT = (*pi)->getType();
6380b57cec5SDimitry Andric
6390b57cec5SDimitry Andric // Skip already created values.
6400b57cec5SDimitry Andric if (RS->getArgEffects().contains(parm_idx))
6410b57cec5SDimitry Andric continue;
6420b57cec5SDimitry Andric
6430b57cec5SDimitry Andric ObjKind K = ObjKind::AnyObj;
6440b57cec5SDimitry Andric
6450b57cec5SDimitry Andric if (isISLObjectRef(QT)) {
6460b57cec5SDimitry Andric K = ObjKind::Generalized;
6470b57cec5SDimitry Andric } else if (isOSObjectPtr(QT)) {
6480b57cec5SDimitry Andric K = ObjKind::OS;
6490b57cec5SDimitry Andric } else if (cocoa::isCocoaObjectRef(QT)) {
6500b57cec5SDimitry Andric K = ObjKind::ObjC;
6510b57cec5SDimitry Andric } else if (coreFoundation::isCFObjectRef(QT)) {
6520b57cec5SDimitry Andric K = ObjKind::CF;
6530b57cec5SDimitry Andric }
6540b57cec5SDimitry Andric
6550b57cec5SDimitry Andric if (K != ObjKind::AnyObj)
6560b57cec5SDimitry Andric Template->addArg(AF, parm_idx,
6570b57cec5SDimitry Andric ArgEffect(RS->getDefaultArgEffect().getKind(), K));
6580b57cec5SDimitry Andric }
6590b57cec5SDimitry Andric }
6600b57cec5SDimitry Andric
6610b57cec5SDimitry Andric const RetainSummary *
getSummary(AnyCall C,bool HasNonZeroCallbackArg,bool IsReceiverUnconsumedSelf,QualType ReceiverType)6620b57cec5SDimitry Andric RetainSummaryManager::getSummary(AnyCall C,
6630b57cec5SDimitry Andric bool HasNonZeroCallbackArg,
6640b57cec5SDimitry Andric bool IsReceiverUnconsumedSelf,
6650b57cec5SDimitry Andric QualType ReceiverType) {
6660b57cec5SDimitry Andric const RetainSummary *Summ;
6670b57cec5SDimitry Andric switch (C.getKind()) {
6680b57cec5SDimitry Andric case AnyCall::Function:
6690b57cec5SDimitry Andric case AnyCall::Constructor:
6705ffd83dbSDimitry Andric case AnyCall::InheritedConstructor:
6710b57cec5SDimitry Andric case AnyCall::Allocator:
6720b57cec5SDimitry Andric case AnyCall::Deallocator:
6730b57cec5SDimitry Andric Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
6740b57cec5SDimitry Andric break;
6750b57cec5SDimitry Andric case AnyCall::Block:
6760b57cec5SDimitry Andric case AnyCall::Destructor:
6770b57cec5SDimitry Andric // FIXME: These calls are currently unsupported.
6780b57cec5SDimitry Andric return getPersistentStopSummary();
6790b57cec5SDimitry Andric case AnyCall::ObjCMethod: {
6800b57cec5SDimitry Andric const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());
6810b57cec5SDimitry Andric if (!ME) {
6820b57cec5SDimitry Andric Summ = getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));
6830b57cec5SDimitry Andric } else if (ME->isInstanceMessage()) {
6840b57cec5SDimitry Andric Summ = getInstanceMethodSummary(ME, ReceiverType);
6850b57cec5SDimitry Andric } else {
6860b57cec5SDimitry Andric Summ = getClassMethodSummary(ME);
6870b57cec5SDimitry Andric }
6880b57cec5SDimitry Andric break;
6890b57cec5SDimitry Andric }
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric
6920b57cec5SDimitry Andric if (HasNonZeroCallbackArg)
6930b57cec5SDimitry Andric Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
6940b57cec5SDimitry Andric
6950b57cec5SDimitry Andric if (IsReceiverUnconsumedSelf)
6960b57cec5SDimitry Andric updateSummaryForReceiverUnconsumedSelf(Summ);
6970b57cec5SDimitry Andric
6980b57cec5SDimitry Andric updateSummaryForArgumentTypes(C, Summ);
6990b57cec5SDimitry Andric
7000b57cec5SDimitry Andric assert(Summ && "Unknown call type?");
7010b57cec5SDimitry Andric return Summ;
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric
7040b57cec5SDimitry Andric
7050b57cec5SDimitry Andric const RetainSummary *
getCFCreateGetRuleSummary(const FunctionDecl * FD)7060b57cec5SDimitry Andric RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
7070b57cec5SDimitry Andric if (coreFoundation::followsCreateRule(FD))
7080b57cec5SDimitry Andric return getCFSummaryCreateRule(FD);
7090b57cec5SDimitry Andric
7100b57cec5SDimitry Andric return getCFSummaryGetRule(FD);
7110b57cec5SDimitry Andric }
7120b57cec5SDimitry Andric
isTrustedReferenceCountImplementation(const Decl * FD)7130b57cec5SDimitry Andric bool RetainSummaryManager::isTrustedReferenceCountImplementation(
7140b57cec5SDimitry Andric const Decl *FD) {
7150b57cec5SDimitry Andric return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric
718bdd1243dSDimitry Andric std::optional<RetainSummaryManager::BehaviorSummary>
canEval(const CallExpr * CE,const FunctionDecl * FD,bool & hasTrustedImplementationAnnotation)7190b57cec5SDimitry Andric RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
7200b57cec5SDimitry Andric bool &hasTrustedImplementationAnnotation) {
7210b57cec5SDimitry Andric
7220b57cec5SDimitry Andric IdentifierInfo *II = FD->getIdentifier();
7230b57cec5SDimitry Andric if (!II)
724bdd1243dSDimitry Andric return std::nullopt;
7250b57cec5SDimitry Andric
7260b57cec5SDimitry Andric StringRef FName = II->getName();
7270b57cec5SDimitry Andric FName = FName.substr(FName.find_first_not_of('_'));
7280b57cec5SDimitry Andric
7290b57cec5SDimitry Andric QualType ResultTy = CE->getCallReturnType(Ctx);
7300b57cec5SDimitry Andric if (ResultTy->isObjCIdType()) {
7310b57cec5SDimitry Andric if (II->isStr("NSMakeCollectable"))
7320b57cec5SDimitry Andric return BehaviorSummary::Identity;
7330b57cec5SDimitry Andric } else if (ResultTy->isPointerType()) {
7340b57cec5SDimitry Andric // Handle: (CF|CG|CV)Retain
7350b57cec5SDimitry Andric // CFAutorelease
7360b57cec5SDimitry Andric // It's okay to be a little sloppy here.
7370b57cec5SDimitry Andric if (FName == "CMBufferQueueDequeueAndRetain" ||
7380b57cec5SDimitry Andric FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
7395f757f3fSDimitry Andric // These API functions are known to NOT act as a CFRetain wrapper.
7405f757f3fSDimitry Andric // They simply make a new object owned by the caller.
741bdd1243dSDimitry Andric return std::nullopt;
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric if (CE->getNumArgs() == 1 &&
7440b57cec5SDimitry Andric (cocoa::isRefType(ResultTy, "CF", FName) ||
7450b57cec5SDimitry Andric cocoa::isRefType(ResultTy, "CG", FName) ||
7460b57cec5SDimitry Andric cocoa::isRefType(ResultTy, "CV", FName)) &&
7470b57cec5SDimitry Andric (isRetain(FD, FName) || isAutorelease(FD, FName) ||
7480b57cec5SDimitry Andric isMakeCollectable(FName)))
7490b57cec5SDimitry Andric return BehaviorSummary::Identity;
7500b57cec5SDimitry Andric
7510b57cec5SDimitry Andric // safeMetaCast is called by OSDynamicCast.
7520b57cec5SDimitry Andric // We assume that OSDynamicCast is either an identity (cast is OK,
7530b57cec5SDimitry Andric // the input was non-zero),
7540b57cec5SDimitry Andric // or that it returns zero (when the cast failed, or the input
7550b57cec5SDimitry Andric // was zero).
7560b57cec5SDimitry Andric if (TrackOSObjects) {
7570b57cec5SDimitry Andric if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) {
7580b57cec5SDimitry Andric return BehaviorSummary::IdentityOrZero;
7590b57cec5SDimitry Andric } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) {
7600b57cec5SDimitry Andric return BehaviorSummary::Identity;
7610b57cec5SDimitry Andric } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) &&
7620b57cec5SDimitry Andric !cast<CXXMethodDecl>(FD)->isStatic()) {
7630b57cec5SDimitry Andric return BehaviorSummary::IdentityThis;
7640b57cec5SDimitry Andric }
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric
7670b57cec5SDimitry Andric const FunctionDecl* FDD = FD->getDefinition();
7680b57cec5SDimitry Andric if (FDD && isTrustedReferenceCountImplementation(FDD)) {
7690b57cec5SDimitry Andric hasTrustedImplementationAnnotation = true;
7700b57cec5SDimitry Andric return BehaviorSummary::Identity;
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric }
7730b57cec5SDimitry Andric
7740b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
7750b57cec5SDimitry Andric const CXXRecordDecl *Parent = MD->getParent();
7760b57cec5SDimitry Andric if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))
7770b57cec5SDimitry Andric if (FName == "release" || FName == "retain")
7780b57cec5SDimitry Andric return BehaviorSummary::NoOp;
7790b57cec5SDimitry Andric }
7800b57cec5SDimitry Andric
781bdd1243dSDimitry Andric return std::nullopt;
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric
7840b57cec5SDimitry Andric const RetainSummary *
getUnarySummary(const FunctionType * FT,ArgEffectKind AE)7850b57cec5SDimitry Andric RetainSummaryManager::getUnarySummary(const FunctionType* FT,
7860b57cec5SDimitry Andric ArgEffectKind AE) {
7870b57cec5SDimitry Andric
7880b57cec5SDimitry Andric // Unary functions have no arg effects by definition.
7890b57cec5SDimitry Andric ArgEffects ScratchArgs(AF.getEmptyMap());
7900b57cec5SDimitry Andric
7915e801ac6SDimitry Andric // Verify that this is *really* a unary function. This can
7920b57cec5SDimitry Andric // happen if people do weird things.
7930b57cec5SDimitry Andric const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
7940b57cec5SDimitry Andric if (!FTP || FTP->getNumParams() != 1)
7950b57cec5SDimitry Andric return getPersistentStopSummary();
7960b57cec5SDimitry Andric
7970b57cec5SDimitry Andric ArgEffect Effect(AE, ObjKind::CF);
7980b57cec5SDimitry Andric
7990b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 0, Effect);
8000b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
8010b57cec5SDimitry Andric ScratchArgs,
8020b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
8030b57cec5SDimitry Andric }
8040b57cec5SDimitry Andric
8050b57cec5SDimitry Andric const RetainSummary *
getOSSummaryRetainRule(const FunctionDecl * FD)8060b57cec5SDimitry Andric RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
8070b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
8080b57cec5SDimitry Andric AF.getEmptyMap(),
8090b57cec5SDimitry Andric /*ReceiverEff=*/ArgEffect(DoNothing),
8100b57cec5SDimitry Andric /*DefaultEff=*/ArgEffect(DoNothing),
8110b57cec5SDimitry Andric /*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));
8120b57cec5SDimitry Andric }
8130b57cec5SDimitry Andric
8140b57cec5SDimitry Andric const RetainSummary *
getOSSummaryReleaseRule(const FunctionDecl * FD)8150b57cec5SDimitry Andric RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
8160b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
8170b57cec5SDimitry Andric AF.getEmptyMap(),
8180b57cec5SDimitry Andric /*ReceiverEff=*/ArgEffect(DoNothing),
8190b57cec5SDimitry Andric /*DefaultEff=*/ArgEffect(DoNothing),
8200b57cec5SDimitry Andric /*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric
8230b57cec5SDimitry Andric const RetainSummary *
getOSSummaryFreeRule(const FunctionDecl * FD)8240b57cec5SDimitry Andric RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {
8250b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNoRet(),
8260b57cec5SDimitry Andric AF.getEmptyMap(),
8270b57cec5SDimitry Andric /*ReceiverEff=*/ArgEffect(DoNothing),
8280b57cec5SDimitry Andric /*DefaultEff=*/ArgEffect(DoNothing),
8290b57cec5SDimitry Andric /*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric
8320b57cec5SDimitry Andric const RetainSummary *
getOSSummaryCreateRule(const FunctionDecl * FD)8330b57cec5SDimitry Andric RetainSummaryManager::getOSSummaryCreateRule(const FunctionDecl *FD) {
8340b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeOwned(ObjKind::OS),
8350b57cec5SDimitry Andric AF.getEmptyMap());
8360b57cec5SDimitry Andric }
8370b57cec5SDimitry Andric
8380b57cec5SDimitry Andric const RetainSummary *
getOSSummaryGetRule(const FunctionDecl * FD)8390b57cec5SDimitry Andric RetainSummaryManager::getOSSummaryGetRule(const FunctionDecl *FD) {
8400b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::OS),
8410b57cec5SDimitry Andric AF.getEmptyMap());
8420b57cec5SDimitry Andric }
8430b57cec5SDimitry Andric
8440b57cec5SDimitry Andric const RetainSummary *
getCFSummaryCreateRule(const FunctionDecl * FD)8450b57cec5SDimitry Andric RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
8460b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
8470b57cec5SDimitry Andric ArgEffects(AF.getEmptyMap()));
8480b57cec5SDimitry Andric }
8490b57cec5SDimitry Andric
8500b57cec5SDimitry Andric const RetainSummary *
getCFSummaryGetRule(const FunctionDecl * FD)8510b57cec5SDimitry Andric RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
8520b57cec5SDimitry Andric return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
8530b57cec5SDimitry Andric ArgEffects(AF.getEmptyMap()),
8540b57cec5SDimitry Andric ArgEffect(DoNothing), ArgEffect(DoNothing));
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric
8570b57cec5SDimitry Andric
8580b57cec5SDimitry Andric
8590b57cec5SDimitry Andric
8600b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8610b57cec5SDimitry Andric // Summary creation for Selectors.
8620b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8630b57cec5SDimitry Andric
864bdd1243dSDimitry Andric std::optional<RetEffect>
getRetEffectFromAnnotations(QualType RetTy,const Decl * D)8650b57cec5SDimitry Andric RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
8660b57cec5SDimitry Andric const Decl *D) {
8670b57cec5SDimitry Andric if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
8680b57cec5SDimitry Andric return ObjCAllocRetE;
8690b57cec5SDimitry Andric
8700b57cec5SDimitry Andric if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
8710b57cec5SDimitry Andric GeneralizedReturnsRetainedAttr>(D, RetTy))
8720b57cec5SDimitry Andric return RetEffect::MakeOwned(*K);
8730b57cec5SDimitry Andric
8740b57cec5SDimitry Andric if (auto K = hasAnyEnabledAttrOf<
8750b57cec5SDimitry Andric CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
8760b57cec5SDimitry Andric GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
8770b57cec5SDimitry Andric NSReturnsAutoreleasedAttr>(D, RetTy))
8780b57cec5SDimitry Andric return RetEffect::MakeNotOwned(*K);
8790b57cec5SDimitry Andric
8800b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
8810b57cec5SDimitry Andric for (const auto *PD : MD->overridden_methods())
8820b57cec5SDimitry Andric if (auto RE = getRetEffectFromAnnotations(RetTy, PD))
8830b57cec5SDimitry Andric return RE;
8840b57cec5SDimitry Andric
885bdd1243dSDimitry Andric return std::nullopt;
8860b57cec5SDimitry Andric }
8870b57cec5SDimitry Andric
888fe6060f1SDimitry Andric /// \return Whether the chain of typedefs starting from @c QT
889fe6060f1SDimitry Andric /// has a typedef with a given name @c Name.
hasTypedefNamed(QualType QT,StringRef Name)8900b57cec5SDimitry Andric static bool hasTypedefNamed(QualType QT,
8910b57cec5SDimitry Andric StringRef Name) {
892bdd1243dSDimitry Andric while (auto *T = QT->getAs<TypedefType>()) {
8930b57cec5SDimitry Andric const auto &Context = T->getDecl()->getASTContext();
8940b57cec5SDimitry Andric if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))
8950b57cec5SDimitry Andric return true;
8960b57cec5SDimitry Andric QT = T->getDecl()->getUnderlyingType();
8970b57cec5SDimitry Andric }
8980b57cec5SDimitry Andric return false;
8990b57cec5SDimitry Andric }
9000b57cec5SDimitry Andric
getCallableReturnType(const NamedDecl * ND)9010b57cec5SDimitry Andric static QualType getCallableReturnType(const NamedDecl *ND) {
9020b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
9030b57cec5SDimitry Andric return FD->getReturnType();
9040b57cec5SDimitry Andric } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(ND)) {
9050b57cec5SDimitry Andric return MD->getReturnType();
9060b57cec5SDimitry Andric } else {
9070b57cec5SDimitry Andric llvm_unreachable("Unexpected decl");
9080b57cec5SDimitry Andric }
9090b57cec5SDimitry Andric }
9100b57cec5SDimitry Andric
applyParamAnnotationEffect(const ParmVarDecl * pd,unsigned parm_idx,const NamedDecl * FD,RetainSummaryTemplate & Template)9110b57cec5SDimitry Andric bool RetainSummaryManager::applyParamAnnotationEffect(
9120b57cec5SDimitry Andric const ParmVarDecl *pd, unsigned parm_idx, const NamedDecl *FD,
9130b57cec5SDimitry Andric RetainSummaryTemplate &Template) {
9140b57cec5SDimitry Andric QualType QT = pd->getType();
9150b57cec5SDimitry Andric if (auto K =
9160b57cec5SDimitry Andric hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,
9170b57cec5SDimitry Andric GeneralizedConsumedAttr>(pd, QT)) {
9180b57cec5SDimitry Andric Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
9190b57cec5SDimitry Andric return true;
9200b57cec5SDimitry Andric } else if (auto K = hasAnyEnabledAttrOf<
9210b57cec5SDimitry Andric CFReturnsRetainedAttr, OSReturnsRetainedAttr,
9220b57cec5SDimitry Andric OSReturnsRetainedOnNonZeroAttr, OSReturnsRetainedOnZeroAttr,
9230b57cec5SDimitry Andric GeneralizedReturnsRetainedAttr>(pd, QT)) {
9240b57cec5SDimitry Andric
9250b57cec5SDimitry Andric // For OSObjects, we try to guess whether the object is created based
9260b57cec5SDimitry Andric // on the return value.
9270b57cec5SDimitry Andric if (K == ObjKind::OS) {
9280b57cec5SDimitry Andric QualType QT = getCallableReturnType(FD);
9290b57cec5SDimitry Andric
9300b57cec5SDimitry Andric bool HasRetainedOnZero = pd->hasAttr<OSReturnsRetainedOnZeroAttr>();
9310b57cec5SDimitry Andric bool HasRetainedOnNonZero = pd->hasAttr<OSReturnsRetainedOnNonZeroAttr>();
9320b57cec5SDimitry Andric
9330b57cec5SDimitry Andric // The usual convention is to create an object on non-zero return, but
9340b57cec5SDimitry Andric // it's reverted if the typedef chain has a typedef kern_return_t,
9350b57cec5SDimitry Andric // because kReturnSuccess constant is defined as zero.
9360b57cec5SDimitry Andric // The convention can be overwritten by custom attributes.
9370b57cec5SDimitry Andric bool SuccessOnZero =
9380b57cec5SDimitry Andric HasRetainedOnZero ||
9390b57cec5SDimitry Andric (hasTypedefNamed(QT, "kern_return_t") && !HasRetainedOnNonZero);
9400b57cec5SDimitry Andric bool ShouldSplit = !QT.isNull() && !QT->isVoidType();
9410b57cec5SDimitry Andric ArgEffectKind AK = RetainedOutParameter;
9420b57cec5SDimitry Andric if (ShouldSplit && SuccessOnZero) {
9430b57cec5SDimitry Andric AK = RetainedOutParameterOnZero;
9440b57cec5SDimitry Andric } else if (ShouldSplit && (!SuccessOnZero || HasRetainedOnNonZero)) {
9450b57cec5SDimitry Andric AK = RetainedOutParameterOnNonZero;
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric Template->addArg(AF, parm_idx, ArgEffect(AK, ObjKind::OS));
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric
9500b57cec5SDimitry Andric // For others:
9510b57cec5SDimitry Andric // Do nothing. Retained out parameters will either point to a +1 reference
9520b57cec5SDimitry Andric // or NULL, but the way you check for failure differs depending on the
9530b57cec5SDimitry Andric // API. Consequently, we don't have a good way to track them yet.
9540b57cec5SDimitry Andric return true;
9550b57cec5SDimitry Andric } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr,
9560b57cec5SDimitry Andric OSReturnsNotRetainedAttr,
9570b57cec5SDimitry Andric GeneralizedReturnsNotRetainedAttr>(
9580b57cec5SDimitry Andric pd, QT)) {
9590b57cec5SDimitry Andric Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
9600b57cec5SDimitry Andric return true;
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric
9630b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
9640b57cec5SDimitry Andric for (const auto *OD : MD->overridden_methods()) {
9650b57cec5SDimitry Andric const ParmVarDecl *OP = OD->parameters()[parm_idx];
9660b57cec5SDimitry Andric if (applyParamAnnotationEffect(OP, parm_idx, OD, Template))
9670b57cec5SDimitry Andric return true;
9680b57cec5SDimitry Andric }
9690b57cec5SDimitry Andric }
9700b57cec5SDimitry Andric
9710b57cec5SDimitry Andric return false;
9720b57cec5SDimitry Andric }
9730b57cec5SDimitry Andric
9740b57cec5SDimitry Andric void
updateSummaryFromAnnotations(const RetainSummary * & Summ,const FunctionDecl * FD)9750b57cec5SDimitry Andric RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
9760b57cec5SDimitry Andric const FunctionDecl *FD) {
9770b57cec5SDimitry Andric if (!FD)
9780b57cec5SDimitry Andric return;
9790b57cec5SDimitry Andric
9800b57cec5SDimitry Andric assert(Summ && "Must have a summary to add annotations to.");
9810b57cec5SDimitry Andric RetainSummaryTemplate Template(Summ, *this);
9820b57cec5SDimitry Andric
9830b57cec5SDimitry Andric // Effects on the parameters.
9840b57cec5SDimitry Andric unsigned parm_idx = 0;
9850b57cec5SDimitry Andric for (auto pi = FD->param_begin(),
9860b57cec5SDimitry Andric pe = FD->param_end(); pi != pe; ++pi, ++parm_idx)
9870b57cec5SDimitry Andric applyParamAnnotationEffect(*pi, parm_idx, FD, Template);
9880b57cec5SDimitry Andric
9890b57cec5SDimitry Andric QualType RetTy = FD->getReturnType();
990bdd1243dSDimitry Andric if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
9910b57cec5SDimitry Andric Template->setRetEffect(*RetE);
9920b57cec5SDimitry Andric
9930b57cec5SDimitry Andric if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
9940b57cec5SDimitry Andric Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric
9970b57cec5SDimitry Andric void
updateSummaryFromAnnotations(const RetainSummary * & Summ,const ObjCMethodDecl * MD)9980b57cec5SDimitry Andric RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
9990b57cec5SDimitry Andric const ObjCMethodDecl *MD) {
10000b57cec5SDimitry Andric if (!MD)
10010b57cec5SDimitry Andric return;
10020b57cec5SDimitry Andric
10030b57cec5SDimitry Andric assert(Summ && "Must have a valid summary to add annotations to");
10040b57cec5SDimitry Andric RetainSummaryTemplate Template(Summ, *this);
10050b57cec5SDimitry Andric
10060b57cec5SDimitry Andric // Effects on the receiver.
10070b57cec5SDimitry Andric if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
10080b57cec5SDimitry Andric Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC));
10090b57cec5SDimitry Andric
10100b57cec5SDimitry Andric // Effects on the parameters.
10110b57cec5SDimitry Andric unsigned parm_idx = 0;
10120b57cec5SDimitry Andric for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;
10130b57cec5SDimitry Andric ++pi, ++parm_idx)
10140b57cec5SDimitry Andric applyParamAnnotationEffect(*pi, parm_idx, MD, Template);
10150b57cec5SDimitry Andric
10160b57cec5SDimitry Andric QualType RetTy = MD->getReturnType();
1017bdd1243dSDimitry Andric if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
10180b57cec5SDimitry Andric Template->setRetEffect(*RetE);
10190b57cec5SDimitry Andric }
10200b57cec5SDimitry Andric
10210b57cec5SDimitry Andric const RetainSummary *
getStandardMethodSummary(const ObjCMethodDecl * MD,Selector S,QualType RetTy)10220b57cec5SDimitry Andric RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
10230b57cec5SDimitry Andric Selector S, QualType RetTy) {
10240b57cec5SDimitry Andric // Any special effects?
10250b57cec5SDimitry Andric ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC);
10260b57cec5SDimitry Andric RetEffect ResultEff = RetEffect::MakeNoRet();
10270b57cec5SDimitry Andric
10280b57cec5SDimitry Andric // Check the method family, and apply any default annotations.
10290b57cec5SDimitry Andric switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
10300b57cec5SDimitry Andric case OMF_None:
10310b57cec5SDimitry Andric case OMF_initialize:
10320b57cec5SDimitry Andric case OMF_performSelector:
10330b57cec5SDimitry Andric // Assume all Objective-C methods follow Cocoa Memory Management rules.
10340b57cec5SDimitry Andric // FIXME: Does the non-threaded performSelector family really belong here?
10350b57cec5SDimitry Andric // The selector could be, say, @selector(copy).
10360b57cec5SDimitry Andric if (cocoa::isCocoaObjectRef(RetTy))
10370b57cec5SDimitry Andric ResultEff = RetEffect::MakeNotOwned(ObjKind::ObjC);
10380b57cec5SDimitry Andric else if (coreFoundation::isCFObjectRef(RetTy)) {
10390b57cec5SDimitry Andric // ObjCMethodDecl currently doesn't consider CF objects as valid return
10400b57cec5SDimitry Andric // values for alloc, new, copy, or mutableCopy, so we have to
10410b57cec5SDimitry Andric // double-check with the selector. This is ugly, but there aren't that
10420b57cec5SDimitry Andric // many Objective-C methods that return CF objects, right?
10430b57cec5SDimitry Andric if (MD) {
10440b57cec5SDimitry Andric switch (S.getMethodFamily()) {
10450b57cec5SDimitry Andric case OMF_alloc:
10460b57cec5SDimitry Andric case OMF_new:
10470b57cec5SDimitry Andric case OMF_copy:
10480b57cec5SDimitry Andric case OMF_mutableCopy:
10490b57cec5SDimitry Andric ResultEff = RetEffect::MakeOwned(ObjKind::CF);
10500b57cec5SDimitry Andric break;
10510b57cec5SDimitry Andric default:
10520b57cec5SDimitry Andric ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
10530b57cec5SDimitry Andric break;
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric } else {
10560b57cec5SDimitry Andric ResultEff = RetEffect::MakeNotOwned(ObjKind::CF);
10570b57cec5SDimitry Andric }
10580b57cec5SDimitry Andric }
10590b57cec5SDimitry Andric break;
10600b57cec5SDimitry Andric case OMF_init:
10610b57cec5SDimitry Andric ResultEff = ObjCInitRetE;
10620b57cec5SDimitry Andric ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
10630b57cec5SDimitry Andric break;
10640b57cec5SDimitry Andric case OMF_alloc:
10650b57cec5SDimitry Andric case OMF_new:
10660b57cec5SDimitry Andric case OMF_copy:
10670b57cec5SDimitry Andric case OMF_mutableCopy:
10680b57cec5SDimitry Andric if (cocoa::isCocoaObjectRef(RetTy))
10690b57cec5SDimitry Andric ResultEff = ObjCAllocRetE;
10700b57cec5SDimitry Andric else if (coreFoundation::isCFObjectRef(RetTy))
10710b57cec5SDimitry Andric ResultEff = RetEffect::MakeOwned(ObjKind::CF);
10720b57cec5SDimitry Andric break;
10730b57cec5SDimitry Andric case OMF_autorelease:
10740b57cec5SDimitry Andric ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);
10750b57cec5SDimitry Andric break;
10760b57cec5SDimitry Andric case OMF_retain:
10770b57cec5SDimitry Andric ReceiverEff = ArgEffect(IncRef, ObjKind::ObjC);
10780b57cec5SDimitry Andric break;
10790b57cec5SDimitry Andric case OMF_release:
10800b57cec5SDimitry Andric ReceiverEff = ArgEffect(DecRef, ObjKind::ObjC);
10810b57cec5SDimitry Andric break;
10820b57cec5SDimitry Andric case OMF_dealloc:
10830b57cec5SDimitry Andric ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);
10840b57cec5SDimitry Andric break;
10850b57cec5SDimitry Andric case OMF_self:
10860b57cec5SDimitry Andric // -self is handled specially by the ExprEngine to propagate the receiver.
10870b57cec5SDimitry Andric break;
10880b57cec5SDimitry Andric case OMF_retainCount:
10890b57cec5SDimitry Andric case OMF_finalize:
10900b57cec5SDimitry Andric // These methods don't return objects.
10910b57cec5SDimitry Andric break;
10920b57cec5SDimitry Andric }
10930b57cec5SDimitry Andric
10940b57cec5SDimitry Andric // If one of the arguments in the selector has the keyword 'delegate' we
10950b57cec5SDimitry Andric // should stop tracking the reference count for the receiver. This is
10960b57cec5SDimitry Andric // because the reference count is quite possibly handled by a delegate
10970b57cec5SDimitry Andric // method.
10980b57cec5SDimitry Andric if (S.isKeywordSelector()) {
10990b57cec5SDimitry Andric for (unsigned i = 0, e = S.getNumArgs(); i != e; ++i) {
11000b57cec5SDimitry Andric StringRef Slot = S.getNameForSlot(i);
1101*7a6dacacSDimitry Andric if (Slot.ends_with_insensitive("delegate")) {
11020b57cec5SDimitry Andric if (ResultEff == ObjCInitRetE)
11030b57cec5SDimitry Andric ResultEff = RetEffect::MakeNoRetHard();
11040b57cec5SDimitry Andric else
11050b57cec5SDimitry Andric ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC);
11060b57cec5SDimitry Andric }
11070b57cec5SDimitry Andric }
11080b57cec5SDimitry Andric }
11090b57cec5SDimitry Andric
11100b57cec5SDimitry Andric if (ReceiverEff.getKind() == DoNothing &&
11110b57cec5SDimitry Andric ResultEff.getKind() == RetEffect::NoRet)
11120b57cec5SDimitry Andric return getDefaultSummary();
11130b57cec5SDimitry Andric
11140b57cec5SDimitry Andric return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
11150b57cec5SDimitry Andric ArgEffect(ReceiverEff), ArgEffect(MayEscape));
11160b57cec5SDimitry Andric }
11170b57cec5SDimitry Andric
11180b57cec5SDimitry Andric const RetainSummary *
getClassMethodSummary(const ObjCMessageExpr * ME)11190b57cec5SDimitry Andric RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
11200b57cec5SDimitry Andric assert(!ME->isInstanceMessage());
11210b57cec5SDimitry Andric const ObjCInterfaceDecl *Class = ME->getReceiverInterface();
11220b57cec5SDimitry Andric
11230b57cec5SDimitry Andric return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
11240b57cec5SDimitry Andric ME->getType(), ObjCClassMethodSummaries);
11250b57cec5SDimitry Andric }
11260b57cec5SDimitry Andric
getInstanceMethodSummary(const ObjCMessageExpr * ME,QualType ReceiverType)11270b57cec5SDimitry Andric const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
11280b57cec5SDimitry Andric const ObjCMessageExpr *ME,
11290b57cec5SDimitry Andric QualType ReceiverType) {
11300b57cec5SDimitry Andric const ObjCInterfaceDecl *ReceiverClass = nullptr;
11310b57cec5SDimitry Andric
11320b57cec5SDimitry Andric // We do better tracking of the type of the object than the core ExprEngine.
11330b57cec5SDimitry Andric // See if we have its type in our private state.
11340b57cec5SDimitry Andric if (!ReceiverType.isNull())
11350b57cec5SDimitry Andric if (const auto *PT = ReceiverType->getAs<ObjCObjectPointerType>())
11360b57cec5SDimitry Andric ReceiverClass = PT->getInterfaceDecl();
11370b57cec5SDimitry Andric
11380b57cec5SDimitry Andric // If we don't know what kind of object this is, fall back to its static type.
11390b57cec5SDimitry Andric if (!ReceiverClass)
11400b57cec5SDimitry Andric ReceiverClass = ME->getReceiverInterface();
11410b57cec5SDimitry Andric
11420b57cec5SDimitry Andric // FIXME: The receiver could be a reference to a class, meaning that
11430b57cec5SDimitry Andric // we should use the class method.
11440b57cec5SDimitry Andric // id x = [NSObject class];
11450b57cec5SDimitry Andric // [x performSelector:... withObject:... afterDelay:...];
11460b57cec5SDimitry Andric Selector S = ME->getSelector();
11470b57cec5SDimitry Andric const ObjCMethodDecl *Method = ME->getMethodDecl();
11480b57cec5SDimitry Andric if (!Method && ReceiverClass)
11490b57cec5SDimitry Andric Method = ReceiverClass->getInstanceMethod(S);
11500b57cec5SDimitry Andric
11510b57cec5SDimitry Andric return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
11520b57cec5SDimitry Andric ObjCMethodSummaries);
11530b57cec5SDimitry Andric }
11540b57cec5SDimitry Andric
11550b57cec5SDimitry Andric const RetainSummary *
getMethodSummary(Selector S,const ObjCInterfaceDecl * ID,const ObjCMethodDecl * MD,QualType RetTy,ObjCMethodSummariesTy & CachedSummaries)11560b57cec5SDimitry Andric RetainSummaryManager::getMethodSummary(Selector S,
11570b57cec5SDimitry Andric const ObjCInterfaceDecl *ID,
11580b57cec5SDimitry Andric const ObjCMethodDecl *MD, QualType RetTy,
11590b57cec5SDimitry Andric ObjCMethodSummariesTy &CachedSummaries) {
11600b57cec5SDimitry Andric
11610b57cec5SDimitry Andric // Objective-C method summaries are only applicable to ObjC and CF objects.
11620b57cec5SDimitry Andric if (!TrackObjCAndCFObjects)
11630b57cec5SDimitry Andric return getDefaultSummary();
11640b57cec5SDimitry Andric
11650b57cec5SDimitry Andric // Look up a summary in our summary cache.
11660b57cec5SDimitry Andric const RetainSummary *Summ = CachedSummaries.find(ID, S);
11670b57cec5SDimitry Andric
11680b57cec5SDimitry Andric if (!Summ) {
11690b57cec5SDimitry Andric Summ = getStandardMethodSummary(MD, S, RetTy);
11700b57cec5SDimitry Andric
11710b57cec5SDimitry Andric // Annotations override defaults.
11720b57cec5SDimitry Andric updateSummaryFromAnnotations(Summ, MD);
11730b57cec5SDimitry Andric
11740b57cec5SDimitry Andric // Memoize the summary.
11750b57cec5SDimitry Andric CachedSummaries[ObjCSummaryKey(ID, S)] = Summ;
11760b57cec5SDimitry Andric }
11770b57cec5SDimitry Andric
11780b57cec5SDimitry Andric return Summ;
11790b57cec5SDimitry Andric }
11800b57cec5SDimitry Andric
InitializeClassMethodSummaries()11810b57cec5SDimitry Andric void RetainSummaryManager::InitializeClassMethodSummaries() {
11820b57cec5SDimitry Andric ArgEffects ScratchArgs = AF.getEmptyMap();
11830b57cec5SDimitry Andric
11840b57cec5SDimitry Andric // Create the [NSAssertionHandler currentHander] summary.
11850b57cec5SDimitry Andric addClassMethSummary("NSAssertionHandler", "currentHandler",
11860b57cec5SDimitry Andric getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::ObjC),
11870b57cec5SDimitry Andric ScratchArgs));
11880b57cec5SDimitry Andric
11890b57cec5SDimitry Andric // Create the [NSAutoreleasePool addObject:] summary.
11900b57cec5SDimitry Andric ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
11910b57cec5SDimitry Andric addClassMethSummary("NSAutoreleasePool", "addObject",
11920b57cec5SDimitry Andric getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
11930b57cec5SDimitry Andric ArgEffect(DoNothing),
11940b57cec5SDimitry Andric ArgEffect(Autorelease)));
11950b57cec5SDimitry Andric }
11960b57cec5SDimitry Andric
InitializeMethodSummaries()11970b57cec5SDimitry Andric void RetainSummaryManager::InitializeMethodSummaries() {
11980b57cec5SDimitry Andric
11990b57cec5SDimitry Andric ArgEffects ScratchArgs = AF.getEmptyMap();
12000b57cec5SDimitry Andric // Create the "init" selector. It just acts as a pass-through for the
12010b57cec5SDimitry Andric // receiver.
12020b57cec5SDimitry Andric const RetainSummary *InitSumm = getPersistentSummary(
12030b57cec5SDimitry Andric ObjCInitRetE, ScratchArgs, ArgEffect(DecRef, ObjKind::ObjC));
12040b57cec5SDimitry Andric addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
12050b57cec5SDimitry Andric
12060b57cec5SDimitry Andric // awakeAfterUsingCoder: behaves basically like an 'init' method. It
12070b57cec5SDimitry Andric // claims the receiver and returns a retained object.
12080b57cec5SDimitry Andric addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
12090b57cec5SDimitry Andric InitSumm);
12100b57cec5SDimitry Andric
12110b57cec5SDimitry Andric // The next methods are allocators.
12120b57cec5SDimitry Andric const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE,
12130b57cec5SDimitry Andric ScratchArgs);
12140b57cec5SDimitry Andric const RetainSummary *CFAllocSumm =
12150b57cec5SDimitry Andric getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs);
12160b57cec5SDimitry Andric
12170b57cec5SDimitry Andric // Create the "retain" selector.
12180b57cec5SDimitry Andric RetEffect NoRet = RetEffect::MakeNoRet();
12190b57cec5SDimitry Andric const RetainSummary *Summ = getPersistentSummary(
12200b57cec5SDimitry Andric NoRet, ScratchArgs, ArgEffect(IncRef, ObjKind::ObjC));
12210b57cec5SDimitry Andric addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
12220b57cec5SDimitry Andric
12230b57cec5SDimitry Andric // Create the "release" selector.
12240b57cec5SDimitry Andric Summ = getPersistentSummary(NoRet, ScratchArgs,
12250b57cec5SDimitry Andric ArgEffect(DecRef, ObjKind::ObjC));
12260b57cec5SDimitry Andric addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
12270b57cec5SDimitry Andric
12280b57cec5SDimitry Andric // Create the -dealloc summary.
12290b57cec5SDimitry Andric Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc,
12300b57cec5SDimitry Andric ObjKind::ObjC));
12310b57cec5SDimitry Andric addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
12320b57cec5SDimitry Andric
12330b57cec5SDimitry Andric // Create the "autorelease" selector.
12340b57cec5SDimitry Andric Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease,
12350b57cec5SDimitry Andric ObjKind::ObjC));
12360b57cec5SDimitry Andric addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
12370b57cec5SDimitry Andric
12380b57cec5SDimitry Andric // For NSWindow, allocated objects are (initially) self-owned.
12390b57cec5SDimitry Andric // FIXME: For now we opt for false negatives with NSWindow, as these objects
12400b57cec5SDimitry Andric // self-own themselves. However, they only do this once they are displayed.
12410b57cec5SDimitry Andric // Thus, we need to track an NSWindow's display status.
12420b57cec5SDimitry Andric const RetainSummary *NoTrackYet =
12430b57cec5SDimitry Andric getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
12440b57cec5SDimitry Andric ArgEffect(StopTracking), ArgEffect(StopTracking));
12450b57cec5SDimitry Andric
12460b57cec5SDimitry Andric addClassMethSummary("NSWindow", "alloc", NoTrackYet);
12470b57cec5SDimitry Andric
12480b57cec5SDimitry Andric // For NSPanel (which subclasses NSWindow), allocated objects are not
12490b57cec5SDimitry Andric // self-owned.
12500b57cec5SDimitry Andric // FIXME: For now we don't track NSPanels. object for the same reason
12510b57cec5SDimitry Andric // as for NSWindow objects.
12520b57cec5SDimitry Andric addClassMethSummary("NSPanel", "alloc", NoTrackYet);
12530b57cec5SDimitry Andric
12540b57cec5SDimitry Andric // For NSNull, objects returned by +null are singletons that ignore
12550b57cec5SDimitry Andric // retain/release semantics. Just don't track them.
12560b57cec5SDimitry Andric addClassMethSummary("NSNull", "null", NoTrackYet);
12570b57cec5SDimitry Andric
12580b57cec5SDimitry Andric // Don't track allocated autorelease pools, as it is okay to prematurely
12590b57cec5SDimitry Andric // exit a method.
12600b57cec5SDimitry Andric addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
12610b57cec5SDimitry Andric addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
12620b57cec5SDimitry Andric addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
12630b57cec5SDimitry Andric
12640b57cec5SDimitry Andric // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
12650b57cec5SDimitry Andric addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
12660b57cec5SDimitry Andric addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
12670b57cec5SDimitry Andric
12680b57cec5SDimitry Andric // Create summaries for CIContext, 'createCGImage' and
12690b57cec5SDimitry Andric // 'createCGLayerWithSize'. These objects are CF objects, and are not
12700b57cec5SDimitry Andric // automatically garbage collected.
12710b57cec5SDimitry Andric addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
12720b57cec5SDimitry Andric addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
12730b57cec5SDimitry Andric "format", "colorSpace");
12740b57cec5SDimitry Andric addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
12750b57cec5SDimitry Andric }
12760b57cec5SDimitry Andric
12770b57cec5SDimitry Andric const RetainSummary *
getMethodSummary(const ObjCMethodDecl * MD)12780b57cec5SDimitry Andric RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
12790b57cec5SDimitry Andric const ObjCInterfaceDecl *ID = MD->getClassInterface();
12800b57cec5SDimitry Andric Selector S = MD->getSelector();
12810b57cec5SDimitry Andric QualType ResultTy = MD->getReturnType();
12820b57cec5SDimitry Andric
12830b57cec5SDimitry Andric ObjCMethodSummariesTy *CachedSummaries;
12840b57cec5SDimitry Andric if (MD->isInstanceMethod())
12850b57cec5SDimitry Andric CachedSummaries = &ObjCMethodSummaries;
12860b57cec5SDimitry Andric else
12870b57cec5SDimitry Andric CachedSummaries = &ObjCClassMethodSummaries;
12880b57cec5SDimitry Andric
12890b57cec5SDimitry Andric return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
12900b57cec5SDimitry Andric }
1291