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