Skip to content

Commit d173d78

Browse files
author
Fariborz Jahanian
committed
ObjectiveC migrator: Provide ARC annotations for
CF methods too. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189041 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 544ae5b commit d173d78

File tree

2 files changed

+172
-30
lines changed

2 files changed

+172
-30
lines changed

lib/ARCMigrate/ObjCMT.cpp

+129-23
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,13 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
5757
bool migrateAddFunctionAnnotation(ASTContext &Ctx,
5858
const FunctionDecl *FuncDecl);
5959

60-
void migrateObjCMethodDeclAnnotation(ASTContext &Ctx,
61-
const ObjCMethodDecl *MethodDecl);
60+
void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
61+
62+
bool migrateAddMethodAnnotation(ASTContext &Ctx,
63+
const ObjCMethodDecl *MethodDecl);
64+
65+
void migrateMethodForCFAnnotation(ASTContext &Ctx,
66+
const ObjCMethodDecl *MethodDecl);
6267
public:
6368
std::string MigrateDir;
6469
bool MigrateLiterals;
@@ -73,7 +78,7 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
7378
Preprocessor &PP;
7479
bool IsOutputFile;
7580
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
76-
llvm::SmallVector<const FunctionDecl *, 8> CFFunctionIBCandidates;
81+
llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
7782

7883
ObjCMigrateASTConsumer(StringRef migrateDir,
7984
bool migrateLiterals,
@@ -794,27 +799,33 @@ AuditedType (QualType AT, bool &IsPoniter) {
794799
}
795800

796801
void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
802+
if (CFFunctionIBCandidates.empty())
803+
return;
797804
if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
798805
CFFunctionIBCandidates.clear();
799806
FileId = 0;
800807
return;
801808
}
802809
// Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
803-
const FunctionDecl *FirstFD = CFFunctionIBCandidates[0];
804-
const FunctionDecl *LastFD =
805-
CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
810+
const Decl *FirstFD = CFFunctionIBCandidates[0];
811+
const Decl *LastFD =
812+
CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
806813
const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
807814
edit::Commit commit(*Editor);
808815
commit.insertBefore(FirstFD->getLocStart(), PragmaString);
809816
PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
810817
SourceLocation EndLoc = LastFD->getLocEnd();
811818
// get location just past end of function location.
812819
EndLoc = PP.getLocForEndOfToken(EndLoc);
813-
Token Tok;
814-
// get locaiton of token that comes after end of function.
815-
bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
816-
if (!Failed)
817-
EndLoc = Tok.getLocation();
820+
if (isa<FunctionDecl>(LastFD)) {
821+
// For Methods, EndLoc points to the ending semcolon. So,
822+
// not of these extra work is needed.
823+
Token Tok;
824+
// get locaiton of token that comes after end of function.
825+
bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
826+
if (!Failed)
827+
EndLoc = Tok.getLocation();
828+
}
818829
commit.insertAfterToken(EndLoc, PragmaString);
819830
Editor->commit(commit);
820831
FileId = 0;
@@ -838,7 +849,7 @@ void ObjCMigrateASTConsumer::migrateCFFunctions(
838849
if (!FileId)
839850
FileId = PP.getSourceManager().getFileID(FuncDecl->getLocation()).getHashValue();
840851
}
841-
else if (!CFFunctionIBCandidates.empty())
852+
else
842853
AnnotateImplicitBridging(Ctx);
843854
}
844855

@@ -912,14 +923,109 @@ bool ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
912923
return HasAtLeastOnePointer;
913924
}
914925

915-
void ObjCMigrateASTConsumer::migrateObjCMethodDeclAnnotation(
926+
void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
927+
ObjCContainerDecl *CDecl) {
928+
if (!isa<ObjCInterfaceDecl>(CDecl))
929+
return;
930+
931+
// migrate methods which can have instancetype as their result type.
932+
for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
933+
MEnd = CDecl->meth_end();
934+
M != MEnd; ++M) {
935+
ObjCMethodDecl *Method = (*M);
936+
migrateMethodForCFAnnotation(Ctx, Method);
937+
}
938+
}
939+
940+
void ObjCMigrateASTConsumer::migrateMethodForCFAnnotation(
916941
ASTContext &Ctx,
917942
const ObjCMethodDecl *MethodDecl) {
918-
if (MethodDecl->hasAttr<CFAuditedTransferAttr>() ||
919-
MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
920-
MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
921-
MethodDecl->hasBody())
943+
if (MethodDecl->hasAttr<CFAuditedTransferAttr>()) {
944+
assert(CFFunctionIBCandidates.empty() &&
945+
"Cannot have audited method inside user "
946+
"provided CF_IMPLICIT_BRIDGING_ENABLE");
922947
return;
948+
}
949+
950+
// Method must be annotated first.
951+
bool Audited = migrateAddMethodAnnotation(Ctx, MethodDecl);
952+
if (Audited) {
953+
CFFunctionIBCandidates.push_back(MethodDecl);
954+
if (!FileId)
955+
FileId = PP.getSourceManager().getFileID(MethodDecl->getLocation()).getHashValue();
956+
}
957+
else
958+
AnnotateImplicitBridging(Ctx);
959+
}
960+
961+
bool ObjCMigrateASTConsumer::migrateAddMethodAnnotation(ASTContext &Ctx,
962+
const ObjCMethodDecl *MethodDecl) {
963+
if (MethodDecl->hasBody())
964+
return false;
965+
966+
CallEffects CE = CallEffects::getEffect(MethodDecl);
967+
bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
968+
MethodDecl->getAttr<CFReturnsNotRetainedAttr>());
969+
970+
// Trivial case of when funciton is annotated and has no argument.
971+
if (MethodIsReturnAnnotated &&
972+
(MethodDecl->param_begin() == MethodDecl->param_end()))
973+
return false;
974+
975+
bool HasAtLeastOnePointer = MethodIsReturnAnnotated;
976+
if (!MethodIsReturnAnnotated) {
977+
RetEffect Ret = CE.getReturnValue();
978+
const char *AnnotationString = 0;
979+
if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
980+
if (Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
981+
AnnotationString = " CF_RETURNS_RETAINED";
982+
}
983+
else if (Ret.getObjKind() == RetEffect::CF && !Ret.isOwned()) {
984+
if (Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
985+
AnnotationString = " CF_RETURNS_NOT_RETAINED";
986+
}
987+
if (AnnotationString) {
988+
edit::Commit commit(*Editor);
989+
commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
990+
Editor->commit(commit);
991+
HasAtLeastOnePointer = true;
992+
}
993+
else if (!AuditedType(MethodDecl->getResultType(), HasAtLeastOnePointer))
994+
return false;
995+
}
996+
997+
// At this point result type is either annotated or audited.
998+
// Now, how about argument types.
999+
llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1000+
unsigned i = 0;
1001+
for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1002+
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1003+
const ParmVarDecl *pd = *pi;
1004+
ArgEffect AE = AEArgs[i];
1005+
if (AE == DecRef /*CFConsumed annotated*/ ||
1006+
AE == IncRef) {
1007+
if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
1008+
Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
1009+
edit::Commit commit(*Editor);
1010+
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1011+
Editor->commit(commit);
1012+
HasAtLeastOnePointer = true;
1013+
}
1014+
// When AE == IncRef, there is no attribute to annotate with.
1015+
// It is assumed that compiler will extract the info. from function
1016+
// API name.
1017+
HasAtLeastOnePointer = true;
1018+
continue;
1019+
}
1020+
1021+
QualType AT = pd->getType();
1022+
bool IsPointer;
1023+
if (!AuditedType(AT, IsPointer))
1024+
return false;
1025+
else if (IsPointer)
1026+
HasAtLeastOnePointer = true;
1027+
}
1028+
return HasAtLeastOnePointer;
9231029
}
9241030

9251031
namespace {
@@ -969,15 +1075,15 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
9691075
}
9701076
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D))
9711077
migrateCFFunctions(Ctx, FD);
972-
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*D))
973-
migrateObjCMethodDeclAnnotation(Ctx, MD);
9741078

975-
// migrate methods which can have instancetype as their result type.
976-
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D))
1079+
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1080+
// migrate methods which can have instancetype as their result type.
9771081
migrateInstanceType(Ctx, CDecl);
1082+
// annotate methods with CF annotations.
1083+
migrateARCSafeAnnotation(Ctx, CDecl);
1084+
}
9781085
}
979-
if (!CFFunctionIBCandidates.empty())
980-
AnnotateImplicitBridging(Ctx);
1086+
AnnotateImplicitBridging(Ctx);
9811087
}
9821088

9831089
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());

test/ARCMT/objcmt-arc-cf-annotations.m.result

+43-7
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,13 @@ typedef double NSTimeInterval;
197197
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
198198
- (NSUInteger)length;
199199
- (NSString *)stringByAppendingString:(NSString *)aString;
200+
201+
CF_IMPLICIT_BRIDGING_ENABLED
202+
200203
- ( const char *)UTF8String;
204+
205+
CF_IMPLICIT_BRIDGING_DISABLED
206+
201207
- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
202208
+ (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString;
203209
@end @class NSString, NSURL, NSError;
@@ -292,9 +298,9 @@ typedef const struct __DADissenter * DADissenterRef;
292298
extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ) CF_RETURNS_RETAINED;
293299
@interface CIContext: NSObject {
294300
}
295-
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
296-
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
297-
- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
301+
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r CF_RETURNS_RETAINED;
302+
- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs CF_RETURNS_RETAINED;
303+
- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d CF_RETURNS_RETAINED;
298304
@end extern NSString* const QCRendererEventKey;
299305
@protocol QCCompositionRenderer - (NSDictionary*) attributes;
300306
@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
@@ -819,8 +825,14 @@ void rdar_6866843() {
819825
typedef CFTypeRef OtherRef;
820826

821827
@interface RDar6877235 : NSObject {}
822-
- (CFTypeRef)_copyCFTypeRef;
823-
- (OtherRef)_copyOtherRef;
828+
829+
CF_IMPLICIT_BRIDGING_ENABLED
830+
831+
- (CFTypeRef)_copyCFTypeRef CF_RETURNS_RETAINED;
832+
- (OtherRef)_copyOtherRef CF_RETURNS_RETAINED;
833+
834+
CF_IMPLICIT_BRIDGING_DISABLED
835+
824836
@end
825837

826838
@implementation RDar6877235
@@ -954,7 +966,13 @@ static void PR4230_new(void)
954966
typedef struct s6893565* TD6893565;
955967

956968
@interface RDar6893565 {}
969+
970+
CF_IMPLICIT_BRIDGING_ENABLED
971+
957972
-(TD6893565)newThing;
973+
974+
CF_IMPLICIT_BRIDGING_DISABLED
975+
958976
@end
959977

960978
@implementation RDar6893565
@@ -1373,7 +1391,13 @@ typedef NSString* MyStringTy;
13731391
- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
13741392
- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED;
13751393
+ (void) consume:(id) NS_CONSUMED x;
1394+
1395+
CF_IMPLICIT_BRIDGING_ENABLED
1396+
13761397
+ (void) consume2:(id) CF_CONSUMED x;
1398+
1399+
CF_IMPLICIT_BRIDGING_DISABLED
1400+
13771401
@end
13781402

13791403
static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}}
@@ -1448,9 +1472,21 @@ void testattr4() {
14481472
- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
14491473
- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
14501474
- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED;
1451-
- (CFDateRef) newCFRetainedAsCFNoAttr;
1475+
1476+
CF_IMPLICIT_BRIDGING_ENABLED
1477+
1478+
- (CFDateRef) newCFRetainedAsCFNoAttr CF_RETURNS_RETAINED;
1479+
1480+
CF_IMPLICIT_BRIDGING_DISABLED
1481+
14521482
- (NSDate*) alsoReturnsRetained;
1453-
- (CFDateRef) alsoReturnsRetainedAsCF;
1483+
1484+
CF_IMPLICIT_BRIDGING_ENABLED
1485+
1486+
- (CFDateRef) alsoReturnsRetainedAsCF CF_RETURNS_NOT_RETAINED;
1487+
1488+
CF_IMPLICIT_BRIDGING_DISABLED
1489+
14541490
- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
14551491
@end
14561492

0 commit comments

Comments
 (0)