From: Fariborz Jahanian Date: Tue, 27 Aug 2013 22:42:30 +0000 (+0000) Subject: ObjectiveC migrator: Do not add explicit cf annotation for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a7f6a94c1bae840c51351cd37cc247ae75f8e649;p=clang ObjectiveC migrator: Do not add explicit cf annotation for cf functions which are CF_IMPLICIT_BRIDGING_ENABLED. Add cf annotation to those not CF_IMPLICIT_BRIDGING_ENABLED to reduce bridge casts. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189409 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index eed3805c65..4fa4b1e660 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -36,6 +36,12 @@ using namespace ento::objc_retain; namespace { class ObjCMigrateASTConsumer : public ASTConsumer { + enum CF_BRIDGING_KIND { + CF_BRIDGING_NONE, + CF_BRIDGING_ENABLE, + CF_BRIDGING_MAY_INCLUDE + }; + void migrateDecl(Decl *D); void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCInterfaceDecl *D); void migrateProtocolConformance(ASTContext &Ctx, @@ -50,16 +56,20 @@ class ObjCMigrateASTConsumer : public ASTConsumer { ObjCInstanceTypeFamily OIT_Family = OIT_None); void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); + void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + const FunctionDecl *FuncDecl); + void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + const ObjCMethodDecl *MethodDecl); void AnnotateImplicitBridging(ASTContext &Ctx); - bool migrateAddFunctionAnnotation(ASTContext &Ctx, - const FunctionDecl *FuncDecl); + CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx, + const FunctionDecl *FuncDecl); void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl); - bool migrateAddMethodAnnotation(ASTContext &Ctx, - const ObjCMethodDecl *MethodDecl); + CF_BRIDGING_KIND migrateAddMethodAnnotation(ASTContext &Ctx, + const ObjCMethodDecl *MethodDecl); public: std::string MigrateDir; bool MigrateLiterals; @@ -778,10 +788,8 @@ static bool IsVoidStarType(QualType Ty) { /// AuditedType - This routine audits the type AT and returns false if it is one of known /// CF object types or of the "void *" variety. It returns true if we don't care about the type /// such as a non-pointer or pointers which have no ownership issues (such as "int *"). -static bool -AuditedType (QualType AT, bool &IsPoniter) { - IsPoniter = (AT->isAnyPointerType() || AT->isBlockPointerType()); - if (!IsPoniter) +static bool AuditedType (QualType AT) { + if (!AT->isAnyPointerType() && !AT->isBlockPointerType()) return true; // FIXME. There isn't much we can say about CF pointer type; or is there? if (ento::coreFoundation::isCFObjectRef(AT) || @@ -837,36 +845,33 @@ void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *De } // Finction must be annotated first. - bool Audited; + CF_BRIDGING_KIND AuditKind; if (const FunctionDecl *FuncDecl = dyn_cast(Decl)) - Audited = migrateAddFunctionAnnotation(Ctx, FuncDecl); + AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl); else - Audited = migrateAddMethodAnnotation(Ctx, cast(Decl)); - if (Audited) { + AuditKind = migrateAddMethodAnnotation(Ctx, cast(Decl)); + if (AuditKind == CF_BRIDGING_ENABLE) { CFFunctionIBCandidates.push_back(Decl); if (!FileId) FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue(); } + else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) { + if (!CFFunctionIBCandidates.empty()) { + CFFunctionIBCandidates.push_back(Decl); + if (!FileId) + FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue(); + } + } else AnnotateImplicitBridging(Ctx); } -bool ObjCMigrateASTConsumer::migrateAddFunctionAnnotation( - ASTContext &Ctx, - const FunctionDecl *FuncDecl) { - if (FuncDecl->hasBody()) - return false; - - CallEffects CE = CallEffects::getEffect(FuncDecl); - bool FuncIsReturnAnnotated = (FuncDecl->getAttr() || - FuncDecl->getAttr()); - - // Trivial case of when funciton is annotated and has no argument. - if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0) - return false; - - bool HasAtLeastOnePointer = FuncIsReturnAnnotated; - if (!FuncIsReturnAnnotated) { +void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, + const CallEffects &CE, + const FunctionDecl *FuncDecl) { + // Annotate function. + if (!FuncDecl->getAttr() && + !FuncDecl->getAttr()) { RetEffect Ret = CE.getReturnValue(); const char *AnnotationString = 0; if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) { @@ -881,44 +886,76 @@ bool ObjCMigrateASTConsumer::migrateAddFunctionAnnotation( edit::Commit commit(*Editor); commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString); Editor->commit(commit); - HasAtLeastOnePointer = true; } - else if (!AuditedType(FuncDecl->getResultType(), HasAtLeastOnePointer)) - return false; + } + llvm::ArrayRef AEArgs = CE.getArgs(); + unsigned i = 0; + for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), + pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { + const ParmVarDecl *pd = *pi; + ArgEffect AE = AEArgs[i]; + if (AE == DecRef && !pd->getAttr() && + Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { + edit::Commit commit(*Editor); + commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); + Editor->commit(commit); + } + } +} + + +ObjCMigrateASTConsumer::CF_BRIDGING_KIND + ObjCMigrateASTConsumer::migrateAddFunctionAnnotation( + ASTContext &Ctx, + const FunctionDecl *FuncDecl) { + if (FuncDecl->hasBody()) + return CF_BRIDGING_NONE; + + CallEffects CE = CallEffects::getEffect(FuncDecl); + bool FuncIsReturnAnnotated = (FuncDecl->getAttr() || + FuncDecl->getAttr()); + + // Trivial case of when funciton is annotated and has no argument. + if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0) + return CF_BRIDGING_NONE; + + bool ReturnCFAudited = false; + if (!FuncIsReturnAnnotated) { + RetEffect Ret = CE.getReturnValue(); + if (Ret.getObjKind() == RetEffect::CF && + (Ret.isOwned() || !Ret.isOwned())) + ReturnCFAudited = true; + else if (!AuditedType(FuncDecl->getResultType())) + return CF_BRIDGING_NONE; } - // At this point result type is either annotated or audited. + // At this point result type is audited for potential inclusion. // Now, how about argument types. llvm::ArrayRef AEArgs = CE.getArgs(); unsigned i = 0; + bool ArgCFAudited = false; for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; ArgEffect AE = AEArgs[i]; - if (AE == DecRef /*CFConsumed annotated*/ || - AE == IncRef) { - if (AE == DecRef && !pd->getAttr() && - Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { - edit::Commit commit(*Editor); - commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); - Editor->commit(commit); - HasAtLeastOnePointer = true; + if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) { + if (AE == DecRef && !pd->getAttr()) + ArgCFAudited = true; + else if (AE == IncRef) + ArgCFAudited = true; + } + else { + QualType AT = pd->getType(); + if (!AuditedType(AT)) { + AddCFAnnotations(Ctx, CE, FuncDecl); + return CF_BRIDGING_NONE; } - // When AE == IncRef, there is no attribute to annotate with. - // It is assumed that compiler will extract the info. from function - // API name. - HasAtLeastOnePointer = true; - continue; } - - QualType AT = pd->getType(); - bool IsPointer; - if (!AuditedType(AT, IsPointer)) - return false; - else if (IsPointer) - HasAtLeastOnePointer = true; } - return HasAtLeastOnePointer; + if (ReturnCFAudited || ArgCFAudited) + return CF_BRIDGING_ENABLE; + + return CF_BRIDGING_MAY_INCLUDE; } void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, @@ -935,22 +972,12 @@ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, } } -bool ObjCMigrateASTConsumer::migrateAddMethodAnnotation(ASTContext &Ctx, - const ObjCMethodDecl *MethodDecl) { - if (MethodDecl->hasBody()) - return false; - - CallEffects CE = CallEffects::getEffect(MethodDecl); - bool MethodIsReturnAnnotated = (MethodDecl->getAttr() || - MethodDecl->getAttr()); - - // Trivial case of when funciton is annotated and has no argument. - if (MethodIsReturnAnnotated && - (MethodDecl->param_begin() == MethodDecl->param_end())) - return false; - - bool HasAtLeastOnePointer = MethodIsReturnAnnotated; - if (!MethodIsReturnAnnotated) { +void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, + const CallEffects &CE, + const ObjCMethodDecl *MethodDecl) { + // Annotate function. + if (!MethodDecl->getAttr() && + !MethodDecl->getAttr()) { RetEffect Ret = CE.getReturnValue(); const char *AnnotationString = 0; if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) { @@ -965,44 +992,75 @@ bool ObjCMigrateASTConsumer::migrateAddMethodAnnotation(ASTContext &Ctx, edit::Commit commit(*Editor); commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString); Editor->commit(commit); - HasAtLeastOnePointer = true; } - else if (!AuditedType(MethodDecl->getResultType(), HasAtLeastOnePointer)) - return false; + } + llvm::ArrayRef AEArgs = CE.getArgs(); + unsigned i = 0; + for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), + pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { + const ParmVarDecl *pd = *pi; + ArgEffect AE = AEArgs[i]; + if (AE == DecRef && !pd->getAttr() && + Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { + edit::Commit commit(*Editor); + commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); + Editor->commit(commit); + } + } +} + +ObjCMigrateASTConsumer::CF_BRIDGING_KIND + ObjCMigrateASTConsumer::migrateAddMethodAnnotation( + ASTContext &Ctx, + const ObjCMethodDecl *MethodDecl) { + if (MethodDecl->hasBody()) + return CF_BRIDGING_NONE; + + CallEffects CE = CallEffects::getEffect(MethodDecl); + bool MethodIsReturnAnnotated = (MethodDecl->getAttr() || + MethodDecl->getAttr()); + + // Trivial case of when funciton is annotated and has no argument. + if (MethodIsReturnAnnotated && + (MethodDecl->param_begin() == MethodDecl->param_end())) + return CF_BRIDGING_NONE; + + bool ReturnCFAudited = false; + if (!MethodIsReturnAnnotated) { + RetEffect Ret = CE.getReturnValue(); + if (Ret.getObjKind() == RetEffect::CF && (Ret.isOwned() || !Ret.isOwned())) + ReturnCFAudited = true; + else if (!AuditedType(MethodDecl->getResultType())) + return CF_BRIDGING_NONE; } // At this point result type is either annotated or audited. // Now, how about argument types. llvm::ArrayRef AEArgs = CE.getArgs(); unsigned i = 0; + bool ArgCFAudited = false; for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; ArgEffect AE = AEArgs[i]; - if (AE == DecRef /*CFConsumed annotated*/ || - AE == IncRef) { - if (AE == DecRef && !pd->getAttr() && - Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { - edit::Commit commit(*Editor); - commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); - Editor->commit(commit); - HasAtLeastOnePointer = true; + if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) { + if (AE == DecRef && !pd->getAttr()) + ArgCFAudited = true; + else if (AE == IncRef) + ArgCFAudited = true; + } + else { + QualType AT = pd->getType(); + if (!AuditedType(AT)) { + AddCFAnnotations(Ctx, CE, MethodDecl); + return CF_BRIDGING_NONE; } - // When AE == IncRef, there is no attribute to annotate with. - // It is assumed that compiler will extract the info. from function - // API name. - HasAtLeastOnePointer = true; - continue; } - - QualType AT = pd->getType(); - bool IsPointer; - if (!AuditedType(AT, IsPointer)) - return false; - else if (IsPointer) - HasAtLeastOnePointer = true; } - return HasAtLeastOnePointer; + if (ReturnCFAudited || ArgCFAudited) + return CF_BRIDGING_ENABLE; + + return CF_BRIDGING_MAY_INCLUDE; } namespace { diff --git a/test/ARCMT/objcmt-arc-cf-annotations.m.result b/test/ARCMT/objcmt-arc-cf-annotations.m.result index 7a31f5110c..cd152cd230 100644 --- a/test/ARCMT/objcmt-arc-cf-annotations.m.result +++ b/test/ARCMT/objcmt-arc-cf-annotations.m.result @@ -82,7 +82,7 @@ extern CFTypeRef CFRetain(CFTypeRef cf); CF_IMPLICIT_BRIDGING_ENABLED -extern void CFRelease(CFTypeRef CF_CONSUMED cf); +extern void CFRelease(CFTypeRef cf); CF_IMPLICIT_BRIDGING_DISABLED @@ -197,13 +197,7 @@ typedef double NSTimeInterval; @interface NSString : NSObject - (NSUInteger)length; - (NSString *)stringByAppendingString:(NSString *)aString; - -CF_IMPLICIT_BRIDGING_ENABLED - - ( const char *)UTF8String; - -CF_IMPLICIT_BRIDGING_DISABLED - - (instancetype)initWithUTF8String:(const char *)nullTerminatedCString; + (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString; @end @class NSString, NSURL, NSError; @@ -235,9 +229,9 @@ typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterat CF_IMPLICIT_BRIDGING_ENABLED -io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef CF_CONSUMED matching ); -kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef CF_CONSUMED matching, io_iterator_t * existing ); -kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef CF_CONSUMED matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); +io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching ); +kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing ); +kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated)); CF_IMPLICIT_BRIDGING_DISABLED // expected-note {{'IOServiceAddNotification' declared here}} @@ -245,11 +239,11 @@ kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPor CF_IMPLICIT_BRIDGING_ENABLED -CFMutableDictionaryRef IOServiceMatching( const char * name ) CF_RETURNS_RETAINED; -CFMutableDictionaryRef IOServiceNameMatching( const char * name ) CF_RETURNS_RETAINED; -CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ) CF_RETURNS_RETAINED; -CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ) CF_RETURNS_RETAINED; -CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ) CF_RETURNS_RETAINED; +CFMutableDictionaryRef IOServiceMatching( const char * name ); +CFMutableDictionaryRef IOServiceNameMatching( const char * name ); +CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ); +CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ); +CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ); CF_IMPLICIT_BRIDGING_DISABLED @@ -338,7 +332,7 @@ extern CGGradientRef CGGradientRetain(CGGradientRef gradient); CF_IMPLICIT_BRIDGING_ENABLED -extern void CGGradientRelease(CGGradientRef CF_CONSUMED gradient); +extern void CGGradientRelease(CGGradientRef gradient); CF_IMPLICIT_BRIDGING_DISABLED @@ -349,7 +343,7 @@ extern void CGContextDrawLinearGradient(CGContextRef context, CF_IMPLICIT_BRIDGING_ENABLED -extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void) CF_RETURNS_RETAINED; +extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void); CF_IMPLICIT_BRIDGING_DISABLED @@ -450,7 +444,7 @@ CFDateRef f7() { CF_IMPLICIT_BRIDGING_ENABLED -CFDateRef MyDateCreate() CF_RETURNS_RETAINED; +CFDateRef MyDateCreate(); CF_IMPLICIT_BRIDGING_DISABLED @@ -524,7 +518,7 @@ typedef CFTypeRef CREATEFUN(); CF_IMPLICIT_BRIDGING_ENABLED -CFTypeRef MyCreateFun() CF_RETURNS_RETAINED; +CFTypeRef MyCreateFun(); CF_IMPLICIT_BRIDGING_DISABLED @@ -828,8 +822,8 @@ typedef CFTypeRef OtherRef; CF_IMPLICIT_BRIDGING_ENABLED -- (CFTypeRef)_copyCFTypeRef CF_RETURNS_RETAINED; -- (OtherRef)_copyOtherRef CF_RETURNS_RETAINED; +- (CFTypeRef)_copyCFTypeRef; +- (OtherRef)_copyOtherRef; CF_IMPLICIT_BRIDGING_DISABLED @@ -966,13 +960,7 @@ static void PR4230_new(void) typedef struct s6893565* TD6893565; @interface RDar6893565 {} - -CF_IMPLICIT_BRIDGING_ENABLED - -(TD6893565)newThing; - -CF_IMPLICIT_BRIDGING_DISABLED - @end @implementation RDar6893565 @@ -1391,13 +1379,7 @@ typedef NSString* MyStringTy; - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} - (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED; + (void) consume:(id) NS_CONSUMED x; - -CF_IMPLICIT_BRIDGING_ENABLED - + (void) consume2:(id) CF_CONSUMED x; - -CF_IMPLICIT_BRIDGING_DISABLED - @end static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}} @@ -1443,14 +1425,8 @@ void testattr3() { } void consume_ns(id NS_CONSUMED x); - -CF_IMPLICIT_BRIDGING_ENABLED - void consume_cf(id CF_CONSUMED x); -CF_IMPLICIT_BRIDGING_DISABLED - - void testattr4() { TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // no-warning consume_ns(x); @@ -1475,7 +1451,7 @@ void testattr4() { CF_IMPLICIT_BRIDGING_ENABLED -- (CFDateRef) newCFRetainedAsCFNoAttr CF_RETURNS_RETAINED; +- (CFDateRef) newCFRetainedAsCFNoAttr; CF_IMPLICIT_BRIDGING_DISABLED @@ -1483,7 +1459,7 @@ CF_IMPLICIT_BRIDGING_DISABLED CF_IMPLICIT_BRIDGING_ENABLED -- (CFDateRef) alsoReturnsRetainedAsCF CF_RETURNS_NOT_RETAINED; +- (CFDateRef) alsoReturnsRetainedAsCF; CF_IMPLICIT_BRIDGING_DISABLED @@ -1665,7 +1641,7 @@ static void rdar_8724287(CFErrorRef error) CF_IMPLICIT_BRIDGING_ENABLED -extern void *CFStringCreate(void) CF_RETURNS_RETAINED; +extern void *CFStringCreate(void); CF_IMPLICIT_BRIDGING_DISABLED @@ -2009,14 +1985,8 @@ id makeCollectableNonLeak() { void consumeAndStopTracking(id NS_CONSUMED obj, void (^callback)(void)); - -CF_IMPLICIT_BRIDGING_ENABLED - void CFConsumeAndStopTracking(CFTypeRef CF_CONSUMED obj, void (^callback)(void)); -CF_IMPLICIT_BRIDGING_DISABLED - - void testConsumeAndStopTracking() { id retained = [@[] retain]; // +1 consumeAndStopTracking(retained, ^{}); // no-warning @@ -2133,14 +2103,8 @@ void rdar13783514(xpc_connection_t connection) { xpc_connection_set_finalizer_f(connection, releaseAfterXPC); } // no-warning - -CF_IMPLICIT_BRIDGING_ENABLED - CFAttributedStringRef CFAttributedCreate(void *CFObj CF_CONSUMED) CF_RETURNS_RETAINED; -CF_IMPLICIT_BRIDGING_DISABLED - - @interface Action @property(nonatomic) SEL action;