r189041 - ObjectiveC migrator: Provide ARC annotations for
Fariborz Jahanian
fjahanian at apple.com
Thu Aug 22 11:35:27 PDT 2013
Author: fjahanian
Date: Thu Aug 22 13:35:27 2013
New Revision: 189041
URL: http://llvm.org/viewvc/llvm-project?rev=189041&view=rev
Log:
ObjectiveC migrator: Provide ARC annotations for
CF methods too.
Modified:
cfe/trunk/lib/ARCMigrate/ObjCMT.cpp
cfe/trunk/test/ARCMT/objcmt-arc-cf-annotations.m.result
Modified: cfe/trunk/lib/ARCMigrate/ObjCMT.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/ObjCMT.cpp?rev=189041&r1=189040&r2=189041&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/ObjCMT.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/ObjCMT.cpp Thu Aug 22 13:35:27 2013
@@ -57,8 +57,13 @@ class ObjCMigrateASTConsumer : public AS
bool migrateAddFunctionAnnotation(ASTContext &Ctx,
const FunctionDecl *FuncDecl);
- void migrateObjCMethodDeclAnnotation(ASTContext &Ctx,
- const ObjCMethodDecl *MethodDecl);
+ void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
+
+ bool migrateAddMethodAnnotation(ASTContext &Ctx,
+ const ObjCMethodDecl *MethodDecl);
+
+ void migrateMethodForCFAnnotation(ASTContext &Ctx,
+ const ObjCMethodDecl *MethodDecl);
public:
std::string MigrateDir;
bool MigrateLiterals;
@@ -73,7 +78,7 @@ public:
Preprocessor &PP;
bool IsOutputFile;
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
- llvm::SmallVector<const FunctionDecl *, 8> CFFunctionIBCandidates;
+ llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
ObjCMigrateASTConsumer(StringRef migrateDir,
bool migrateLiterals,
@@ -794,15 +799,17 @@ AuditedType (QualType AT, bool &IsPonite
}
void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
+ if (CFFunctionIBCandidates.empty())
+ return;
if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
CFFunctionIBCandidates.clear();
FileId = 0;
return;
}
// Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
- const FunctionDecl *FirstFD = CFFunctionIBCandidates[0];
- const FunctionDecl *LastFD =
- CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
+ const Decl *FirstFD = CFFunctionIBCandidates[0];
+ const Decl *LastFD =
+ CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
edit::Commit commit(*Editor);
commit.insertBefore(FirstFD->getLocStart(), PragmaString);
@@ -810,11 +817,15 @@ void ObjCMigrateASTConsumer::AnnotateImp
SourceLocation EndLoc = LastFD->getLocEnd();
// get location just past end of function location.
EndLoc = PP.getLocForEndOfToken(EndLoc);
- Token Tok;
- // get locaiton of token that comes after end of function.
- bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
- if (!Failed)
- EndLoc = Tok.getLocation();
+ if (isa<FunctionDecl>(LastFD)) {
+ // For Methods, EndLoc points to the ending semcolon. So,
+ // not of these extra work is needed.
+ Token Tok;
+ // get locaiton of token that comes after end of function.
+ bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
+ if (!Failed)
+ EndLoc = Tok.getLocation();
+ }
commit.insertAfterToken(EndLoc, PragmaString);
Editor->commit(commit);
FileId = 0;
@@ -838,7 +849,7 @@ void ObjCMigrateASTConsumer::migrateCFFu
if (!FileId)
FileId = PP.getSourceManager().getFileID(FuncDecl->getLocation()).getHashValue();
}
- else if (!CFFunctionIBCandidates.empty())
+ else
AnnotateImplicitBridging(Ctx);
}
@@ -912,14 +923,109 @@ bool ObjCMigrateASTConsumer::migrateAddF
return HasAtLeastOnePointer;
}
-void ObjCMigrateASTConsumer::migrateObjCMethodDeclAnnotation(
+void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl) {
+ if (!isa<ObjCInterfaceDecl>(CDecl))
+ return;
+
+ // migrate methods which can have instancetype as their result type.
+ for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
+ MEnd = CDecl->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ migrateMethodForCFAnnotation(Ctx, Method);
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateMethodForCFAnnotation(
ASTContext &Ctx,
const ObjCMethodDecl *MethodDecl) {
- if (MethodDecl->hasAttr<CFAuditedTransferAttr>() ||
- MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
- MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
- MethodDecl->hasBody())
+ if (MethodDecl->hasAttr<CFAuditedTransferAttr>()) {
+ assert(CFFunctionIBCandidates.empty() &&
+ "Cannot have audited method inside user "
+ "provided CF_IMPLICIT_BRIDGING_ENABLE");
return;
+ }
+
+ // Method must be annotated first.
+ bool Audited = migrateAddMethodAnnotation(Ctx, MethodDecl);
+ if (Audited) {
+ CFFunctionIBCandidates.push_back(MethodDecl);
+ if (!FileId)
+ FileId = PP.getSourceManager().getFileID(MethodDecl->getLocation()).getHashValue();
+ }
+ else
+ AnnotateImplicitBridging(Ctx);
+}
+
+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) {
+ RetEffect Ret = CE.getReturnValue();
+ const char *AnnotationString = 0;
+ if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
+ if (Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_RETAINED";
+ }
+ else if (Ret.getObjKind() == RetEffect::CF && !Ret.isOwned()) {
+ if (Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_NOT_RETAINED";
+ }
+ if (AnnotationString) {
+ 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;
+ }
+
+ QualType AT = pd->getType();
+ bool IsPointer;
+ if (!AuditedType(AT, IsPointer))
+ return false;
+ else if (IsPointer)
+ HasAtLeastOnePointer = true;
+ }
+ return HasAtLeastOnePointer;
}
namespace {
@@ -969,15 +1075,15 @@ void ObjCMigrateASTConsumer::HandleTrans
}
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D))
migrateCFFunctions(Ctx, FD);
- else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*D))
- migrateObjCMethodDeclAnnotation(Ctx, MD);
- // migrate methods which can have instancetype as their result type.
- if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D))
+ if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
+ // migrate methods which can have instancetype as their result type.
migrateInstanceType(Ctx, CDecl);
+ // annotate methods with CF annotations.
+ migrateARCSafeAnnotation(Ctx, CDecl);
+ }
}
- if (!CFFunctionIBCandidates.empty())
- AnnotateImplicitBridging(Ctx);
+ AnnotateImplicitBridging(Ctx);
}
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
Modified: cfe/trunk/test/ARCMT/objcmt-arc-cf-annotations.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/objcmt-arc-cf-annotations.m.result?rev=189041&r1=189040&r2=189041&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/objcmt-arc-cf-annotations.m.result (original)
+++ cfe/trunk/test/ARCMT/objcmt-arc-cf-annotations.m.result Thu Aug 22 13:35:27 2013
@@ -197,7 +197,13 @@ typedef double NSTimeInterval;
@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;
@@ -292,9 +298,9 @@ typedef const struct __DADissenter * DAD
extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ) CF_RETURNS_RETAINED;
@interface CIContext: NSObject {
}
-- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
-- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
-- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r CF_RETURNS_RETAINED;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs CF_RETURNS_RETAINED;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d CF_RETURNS_RETAINED;
@end extern NSString* const QCRendererEventKey;
@protocol QCCompositionRenderer - (NSDictionary*) attributes;
@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
@@ -819,8 +825,14 @@ void rdar_6866843() {
typedef CFTypeRef OtherRef;
@interface RDar6877235 : NSObject {}
-- (CFTypeRef)_copyCFTypeRef;
-- (OtherRef)_copyOtherRef;
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+- (CFTypeRef)_copyCFTypeRef CF_RETURNS_RETAINED;
+- (OtherRef)_copyOtherRef CF_RETURNS_RETAINED;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
@end
@implementation RDar6877235
@@ -954,7 +966,13 @@ static void PR4230_new(void)
typedef struct s6893565* TD6893565;
@interface RDar6893565 {}
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
-(TD6893565)newThing;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
@end
@implementation RDar6893565
@@ -1373,7 +1391,13 @@ 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}}
@@ -1448,9 +1472,21 @@ void testattr4() {
- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
- (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED;
-- (CFDateRef) newCFRetainedAsCFNoAttr;
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+- (CFDateRef) newCFRetainedAsCFNoAttr CF_RETURNS_RETAINED;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
- (NSDate*) alsoReturnsRetained;
-- (CFDateRef) alsoReturnsRetainedAsCF;
+
+CF_IMPLICIT_BRIDGING_ENABLED
+
+- (CFDateRef) alsoReturnsRetainedAsCF CF_RETURNS_NOT_RETAINED;
+
+CF_IMPLICIT_BRIDGING_DISABLED
+
- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
@end
More information about the cfe-commits
mailing list