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 eed3805..4fa4b1e 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -36,6 +36,12 @@
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 @@
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 @@
/// 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 @@
}
// Finction must be annotated first.
- bool Audited;
+ CF_BRIDGING_KIND AuditKind;
if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl))
- Audited = migrateAddFunctionAnnotation(Ctx, FuncDecl);
+ AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
else
- Audited = migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
- if (Audited) {
+ AuditKind = migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(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<CFReturnsRetainedAttr>() ||
- FuncDecl->getAttr<CFReturnsNotRetainedAttr>());
-
- // 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<CFReturnsRetainedAttr>() &&
+ !FuncDecl->getAttr<CFReturnsNotRetainedAttr>()) {
RetEffect Ret = CE.getReturnValue();
const char *AnnotationString = 0;
if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
@@ -881,44 +886,76 @@
edit::Commit commit(*Editor);
commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString);
Editor->commit(commit);
- HasAtLeastOnePointer = true;
}
- else if (!AuditedType(FuncDecl->getResultType(), HasAtLeastOnePointer))
- return false;
}
-
- // At this point result type is either annotated or audited.
- // Now, how about argument types.
llvm::ArrayRef<ArgEffect> 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 /*CFConsumed annotated*/ ||
- AE == IncRef) {
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
- Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
- edit::Commit commit(*Editor);
- commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
- Editor->commit(commit);
- HasAtLeastOnePointer = true;
- }
- // 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;
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
+ Editor->commit(commit);
}
-
- QualType AT = pd->getType();
- bool IsPointer;
- if (!AuditedType(AT, IsPointer))
- return false;
- else if (IsPointer)
- HasAtLeastOnePointer = true;
}
- return HasAtLeastOnePointer;
+}
+
+
+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<CFReturnsRetainedAttr>() ||
+ FuncDecl->getAttr<CFReturnsNotRetainedAttr>());
+
+ // 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 audited for potential inclusion.
+ // Now, how about argument types.
+ llvm::ArrayRef<ArgEffect> 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<CFConsumedAttr>())
+ ArgCFAudited = true;
+ else if (AE == IncRef)
+ ArgCFAudited = true;
+ }
+ else {
+ QualType AT = pd->getType();
+ if (!AuditedType(AT)) {
+ AddCFAnnotations(Ctx, CE, FuncDecl);
+ return CF_BRIDGING_NONE;
+ }
+ }
+ }
+ if (ReturnCFAudited || ArgCFAudited)
+ return CF_BRIDGING_ENABLE;
+
+ return CF_BRIDGING_MAY_INCLUDE;
}
void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
@@ -935,22 +972,12 @@
}
}
-bool ObjCMigrateASTConsumer::migrateAddMethodAnnotation(ASTContext &Ctx,
- const ObjCMethodDecl *MethodDecl) {
- if (MethodDecl->hasBody())
- return false;
-
- CallEffects CE = CallEffects::getEffect(MethodDecl);
- bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
- MethodDecl->getAttr<CFReturnsNotRetainedAttr>());
-
- // 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<CFReturnsRetainedAttr>() &&
+ !MethodDecl->getAttr<CFReturnsNotRetainedAttr>()) {
RetEffect Ret = CE.getReturnValue();
const char *AnnotationString = 0;
if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
@@ -965,44 +992,75 @@
edit::Commit commit(*Editor);
commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
Editor->commit(commit);
- HasAtLeastOnePointer = true;
}
- else if (!AuditedType(MethodDecl->getResultType(), HasAtLeastOnePointer))
- return false;
}
-
- // At this point result type is either annotated or audited.
- // Now, how about argument types.
llvm::ArrayRef<ArgEffect> 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 /*CFConsumed annotated*/ ||
- AE == IncRef) {
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
- Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
- edit::Commit commit(*Editor);
- commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
- Editor->commit(commit);
- HasAtLeastOnePointer = true;
- }
- // 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;
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
+ Editor->commit(commit);
}
-
- QualType AT = pd->getType();
- bool IsPointer;
- if (!AuditedType(AT, IsPointer))
- return false;
- else if (IsPointer)
- HasAtLeastOnePointer = true;
}
- return HasAtLeastOnePointer;
+}
+
+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<CFReturnsRetainedAttr>() ||
+ MethodDecl->getAttr<CFReturnsNotRetainedAttr>());
+
+ // 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<ArgEffect> 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<CFConsumedAttr>())
+ ArgCFAudited = true;
+ else if (AE == IncRef)
+ ArgCFAudited = true;
+ }
+ else {
+ QualType AT = pd->getType();
+ if (!AuditedType(AT)) {
+ AddCFAnnotations(Ctx, CE, MethodDecl);
+ return CF_BRIDGING_NONE;
+ }
+ }
+ }
+ 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 7a31f51..cd152cd 100644
--- a/test/ARCMT/objcmt-arc-cf-annotations.m.result
+++ b/test/ARCMT/objcmt-arc-cf-annotations.m.result
@@ -82,7 +82,7 @@
CF_IMPLICIT_BRIDGING_ENABLED
-extern void CFRelease(CFTypeRef CF_CONSUMED cf);
+extern void CFRelease(CFTypeRef cf);
CF_IMPLICIT_BRIDGING_DISABLED
@@ -197,13 +197,7 @@
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
- (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 @@
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 @@
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 @@
CF_IMPLICIT_BRIDGING_ENABLED
-extern void CGGradientRelease(CGGradientRef CF_CONSUMED gradient);
+extern void CGGradientRelease(CGGradientRef gradient);
CF_IMPLICIT_BRIDGING_DISABLED
@@ -349,7 +343,7 @@
CF_IMPLICIT_BRIDGING_ENABLED
-extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void) CF_RETURNS_RETAINED;
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
CF_IMPLICIT_BRIDGING_DISABLED
@@ -450,7 +444,7 @@
CF_IMPLICIT_BRIDGING_ENABLED
-CFDateRef MyDateCreate() CF_RETURNS_RETAINED;
+CFDateRef MyDateCreate();
CF_IMPLICIT_BRIDGING_DISABLED
@@ -524,7 +518,7 @@
CF_IMPLICIT_BRIDGING_ENABLED
-CFTypeRef MyCreateFun() CF_RETURNS_RETAINED;
+CFTypeRef MyCreateFun();
CF_IMPLICIT_BRIDGING_DISABLED
@@ -828,8 +822,8 @@
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 @@
typedef struct s6893565* TD6893565;
@interface RDar6893565 {}
-
-CF_IMPLICIT_BRIDGING_ENABLED
-
-(TD6893565)newThing;
-
-CF_IMPLICIT_BRIDGING_DISABLED
-
@end
@implementation RDar6893565
@@ -1391,13 +1379,7 @@
- (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 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 @@
CF_IMPLICIT_BRIDGING_ENABLED
-- (CFDateRef) newCFRetainedAsCFNoAttr CF_RETURNS_RETAINED;
+- (CFDateRef) newCFRetainedAsCFNoAttr;
CF_IMPLICIT_BRIDGING_DISABLED
@@ -1483,7 +1459,7 @@
CF_IMPLICIT_BRIDGING_ENABLED
-- (CFDateRef) alsoReturnsRetainedAsCF CF_RETURNS_NOT_RETAINED;
+- (CFDateRef) alsoReturnsRetainedAsCF;
CF_IMPLICIT_BRIDGING_DISABLED
@@ -1665,7 +1641,7 @@
CF_IMPLICIT_BRIDGING_ENABLED
-extern void *CFStringCreate(void) CF_RETURNS_RETAINED;
+extern void *CFStringCreate(void);
CF_IMPLICIT_BRIDGING_DISABLED
@@ -2009,14 +1985,8 @@
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 @@
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;