[cfe-commits] r136208 - in /cfe/trunk: include/clang/AST/ lib/ARCMigrate/ lib/AST/ test/ARCMT/

Argyrios Kyrtzidis akyrtzi at gmail.com
Tue Jul 26 22:28:18 PDT 2011


Author: akirtzidis
Date: Wed Jul 27 00:28:18 2011
New Revision: 136208

URL: http://llvm.org/viewvc/llvm-project?rev=136208&view=rev
Log:
[arcmt] More automatic transformations and safety improvements; rdar://9615812 :

- Replace calling -zone with 'nil'. -zone is obsolete in ARC.
- Allow removing retain/release on a static global var.
- Fix assertion hit when scanning for name references outside a NSAutoreleasePool scope.
- Automatically add bridged casts for results of objc method calls and when calling CFRetain, for example:

NSString *s;
CFStringRef ref = [s string];   -> CFStringRef ref = (__bridge CFStringRef)([s string]);
ref = s.string;                 -> ref = (__bridge CFStringRef)(s.string);
ref = [NSString new];           -> ref = (__bridge_retained CFStringRef)([NSString new]);
ref = [s newString];            -> ref = (__bridge_retained CFStringRef)([s newString]);
ref = [[NSString alloc] init];  -> ref = (__bridge_retained CFStringRef)([[NSString alloc] init]);
ref = [[s string] retain];      -> ref = (__bridge_retained CFStringRef)([s string]);
ref = CFRetain(s);              -> ref = (__bridge_retained CFTypeRef)(s);
ref = [s retain];               -> ref = (__bridge_retained CFStringRef)(s);

- Emit migrator error when trying to cast to CF type the result of autorelease/release:
  for

CFStringRef f3() {
  return (CFStringRef)[[[NSString alloc] init] autorelease];
}

emits:

t.m:12:10: error: [rewriter] it is not safe to cast to 'CFStringRef' the result of 'autorelease' message; a __bridge cast may result in a pointer to a destroyed object and a __bridge_retained may leak the object
  return (CFStringRef)[[[NSString alloc] init] autorelease];
         ^            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.m:12:3: note: [rewriter] remove the cast and change return type of function to 'NSString *' to have the object automatically autoreleased
  return (CFStringRef)[[[NSString alloc] init] autorelease];
  ^

- Before changing attributes to weak/unsafe_unretained, check if the backing ivar
  is set to a +1 object, in which case use 'strong' instead.

Added:
    cfe/trunk/test/ARCMT/api.m
    cfe/trunk/test/ARCMT/api.m.result
Modified:
    cfe/trunk/include/clang/AST/ParentMap.h
    cfe/trunk/lib/ARCMigrate/TransAPIUses.cpp
    cfe/trunk/lib/ARCMigrate/TransAutoreleasePool.cpp
    cfe/trunk/lib/ARCMigrate/TransProperties.cpp
    cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
    cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp
    cfe/trunk/lib/ARCMigrate/Transforms.cpp
    cfe/trunk/lib/ARCMigrate/Transforms.h
    cfe/trunk/lib/AST/ParentMap.cpp
    cfe/trunk/test/ARCMT/Common.h
    cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m
    cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result
    cfe/trunk/test/ARCMT/atautorelease.m
    cfe/trunk/test/ARCMT/atautorelease.m.result
    cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m
    cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m
    cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result
    cfe/trunk/test/ARCMT/releases.m
    cfe/trunk/test/ARCMT/releases.m.result

Modified: cfe/trunk/include/clang/AST/ParentMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ParentMap.h?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ParentMap.h (original)
+++ cfe/trunk/include/clang/AST/ParentMap.h Wed Jul 27 00:28:18 2011
@@ -32,6 +32,7 @@
   Stmt *getParent(Stmt*) const;
   Stmt *getParentIgnoreParens(Stmt *) const;
   Stmt *getParentIgnoreParenCasts(Stmt *) const;
+  Stmt *getParentIgnoreParenImpCasts(Stmt *) const;
   Stmt *getOuterParenParent(Stmt *) const;
 
   const Stmt *getParent(const Stmt* S) const {

Modified: cfe/trunk/lib/ARCMigrate/TransAPIUses.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransAPIUses.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransAPIUses.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransAPIUses.cpp Wed Jul 27 00:28:18 2011
@@ -9,17 +9,19 @@
 //
 // checkAPIUses:
 //
-// Emits error with some API uses that are not safe in ARC mode:
+// Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
 //
 // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
 //   with __unsafe_unretained objects.
 // - When a NSData's 'bytes' family of methods are used on a local var,
 //   add __attribute__((objc_precise_lifetime)) to make it safer.
+// - Calling -zone gets replaced with 'nil'.
 //
 //===----------------------------------------------------------------------===//
 
 #include "Transforms.h"
 #include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
 
 using namespace clang;
 using namespace arcmt;
@@ -35,6 +37,8 @@
 
   Selector bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel;
 
+  Selector zoneSel;
+
   llvm::DenseSet<VarDecl *> ChangedNSDataVars;
 public:
   APIChecker(MigrationPass &pass) : Pass(pass) {
@@ -57,9 +61,12 @@
     getBytesLengthSel = sels.getSelector(2, selIds);
     selIds[1] = &ids.get("range");
     getBytesRangeSel = sels.getSelector(2, selIds);
+
+    zoneSel = sels.getNullarySelector(&ids.get("zone"));
   }
 
   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+    // NSInvocation.
     if (E->isInstanceMessage() &&
         E->getReceiverInterface() &&
         E->getReceiverInterface()->getName() == "NSInvocation") {
@@ -91,6 +98,7 @@
       return true;
     }
 
+    // NSData.
     if (E->isInstanceMessage() &&
         E->getReceiverInterface() &&
         E->getReceiverInterface()->getName() == "NSData" &&
@@ -111,6 +119,20 @@
           }
     }
 
+    // -zone.
+    if (E->isInstanceMessage() &&
+        E->getInstanceReceiver() &&
+        E->getSelector() == zoneSel &&
+        Pass.TA.hasDiagnostic(diag::err_unavailable,
+                              diag::err_unavailable_message,
+                              E->getInstanceReceiver()->getExprLoc())) {
+      // Calling -zone is meaningless in ARC, change it to nil.
+      Transaction Trans(Pass.TA);
+      Pass.TA.clearDiagnostic(diag::err_unavailable,
+                              diag::err_unavailable_message,
+                              E->getInstanceReceiver()->getExprLoc());
+      Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx));
+    }
     return true;
   }
 };

Modified: cfe/trunk/lib/ARCMigrate/TransAutoreleasePool.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransAutoreleasePool.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransAutoreleasePool.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransAutoreleasePool.cpp Wed Jul 27 00:28:18 2011
@@ -286,6 +286,9 @@
     }
 
     bool isInScope(SourceLocation loc) {
+      if (loc.isInvalid())
+        return false;
+
       SourceManager &SM = Ctx.getSourceManager();
       if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
         return false;

Modified: cfe/trunk/lib/ARCMigrate/TransProperties.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransProperties.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransProperties.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransProperties.cpp Wed Jul 27 00:28:18 2011
@@ -45,6 +45,7 @@
 
 class PropertiesRewriter {
   MigrationPass &Pass;
+  ObjCImplementationDecl *CurImplD;
 
   struct PropData {
     ObjCPropertyDecl *PropD;
@@ -62,6 +63,7 @@
   PropertiesRewriter(MigrationPass &pass) : Pass(pass) { }
 
   void doTransform(ObjCImplementationDecl *D) {
+    CurImplD = D;
     ObjCInterfaceDecl *iface = D->getClassInterface();
     if (!iface)
       return;
@@ -134,8 +136,16 @@
       return;
     }
 
-    if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign)
+    if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
+      if (hasIvarAssignedAPlusOneObject(props)) {
+        rewriteAttribute("assign", "strong", atLoc);
+        return;
+      }
       return rewriteAssign(props, atLoc);
+    }
+
+    if (hasIvarAssignedAPlusOneObject(props))
+      return maybeAddStrongAttr(props, atLoc);
 
     return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
   }
@@ -162,15 +172,15 @@
   void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
                                           SourceLocation atLoc) const {
     ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
-    if ((propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) &&
-        hasNoBackingIvars(props))
-      return;
 
     bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
-    bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
-                                  atLoc);
-    if (!addedAttr)
-      canUseWeak = false;
+    if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
+        !hasAllIvarsBacked(props)) {
+      bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
+                                    atLoc);
+      if (!addedAttr)
+        canUseWeak = false;
+    }
 
     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
       if (isUserDeclared(I->IvarD))
@@ -186,6 +196,25 @@
     }
   }
 
+  void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const {
+    ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
+
+    if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
+        !hasAllIvarsBacked(props)) {
+      addAttribute("strong", atLoc);
+    }
+
+    for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
+      if (I->ImplD) {
+        Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
+                                I->ImplD->getLocation());
+        Pass.TA.clearDiagnostic(
+                           diag::err_arc_objc_property_default_assign_on_object,
+                           I->ImplD->getLocation());
+      }
+    }
+  }
+
   bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
                         SourceLocation atLoc) const {
     if (atLoc.isMacroID())
@@ -290,6 +319,40 @@
     return true;
   }
 
+  class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
+    ObjCIvarDecl *Ivar;
+  public:
+    PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
+
+    bool VisitBinAssign(BinaryOperator *E) {
+      Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
+      if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
+        if (RE->getDecl() != Ivar)
+          return true;
+
+      ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
+      while (implCE && implCE->getCastKind() ==  CK_BitCast)
+        implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
+
+      if (implCE && implCE->getCastKind() == CK_ObjCConsumeObject)
+        return false;
+      }
+
+      return true;
+    }
+  };
+
+  bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
+    for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
+      PlusOneAssign oneAssign(I->IvarD);
+      bool notFound = oneAssign.TraverseDecl(CurImplD);
+      if (!notFound)
+        return true;
+    }
+
+    return false;
+  }
+
   bool hasIvarWithExplicitOwnership(PropsTy &props) const {
     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
       if (isUserDeclared(I->IvarD)) {
@@ -304,9 +367,9 @@
     return false;    
   }
 
-  bool hasNoBackingIvars(PropsTy &props) const {
+  bool hasAllIvarsBacked(PropsTy &props) const {
     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
-      if (I->IvarD)
+      if (!isUserDeclared(I->IvarD))
         return false;
 
     return true;

Modified: cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp Wed Jul 27 00:28:18 2011
@@ -129,10 +129,9 @@
       // Change the -release to "receiver = nil" in a finally to avoid a leak
       // when an exception is thrown.
       Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
-      if (Pass.Ctx.Idents.get("nil").hasMacroDefinition())
-        Pass.TA.insertAfterToken(rec->getLocEnd(), " = nil");
-      else
-        Pass.TA.insertAfterToken(rec->getLocEnd(), " = 0");
+      std::string str = " = ";
+      str += getNilString(Pass.Ctx);
+      Pass.TA.insertAfterToken(rec->getLocEnd(), str);
       return true;
     }
 

Modified: cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp Wed Jul 27 00:28:18 2011
@@ -36,6 +36,7 @@
 #include "Internals.h"
 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
 #include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ParentMap.h"
 #include "clang/Basic/SourceManager.h"
 
 using namespace clang;
@@ -47,11 +48,18 @@
 class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
   MigrationPass &Pass;
   IdentifierInfo *SelfII;
+  llvm::OwningPtr<ParentMap> StmtMap;
+
 public:
   UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
     SelfII = &Pass.Ctx.Idents.get("self");
   }
 
+  void transformBody(Stmt *body) {
+    StmtMap.reset(new ParentMap(body));
+    TraverseStmt(body);
+  }
+
   bool VisitCastExpr(CastExpr *E) {
     if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
         && E->getCastKind() != CK_BitCast)
@@ -138,13 +146,21 @@
   }
 
   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
+    Transaction Trans(Pass.TA);
+    rewriteToBridgedCast(E, Kind, Trans);
+  }
+
+  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
+                            Transaction &Trans) {
     TransformActions &TA = Pass.TA;
 
     // We will remove the compiler diagnostic.
     if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
                           diag::err_arc_cast_requires_bridge,
-                          E->getLocStart()))
+                          E->getLocStart())) {
+      Trans.abort();
       return;
+    }
 
     StringRef bridge;
     switch(Kind) {
@@ -156,7 +172,6 @@
       bridge = "__bridge_retained "; break;
     }
 
-    Transaction Trans(TA);
     TA.clearDiagnostic(diag::err_arc_mismatched_cast,
                        diag::err_arc_cast_requires_bridge,
                        E->getLocStart());
@@ -180,16 +195,83 @@
     }
   }
 
+  void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
+    Transaction Trans(Pass.TA);
+    Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
+    rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
+  }
+
   void transformObjCToNonObjCCast(CastExpr *E) {
     if (isSelf(E->getSubExpr()))
       return rewriteToBridgedCast(E, OBC_Bridge);
+
+    CallExpr *callE;
+    if (isPassedToCFRetain(E, callE))
+      return rewriteCastForCFRetain(E, callE);
+
+    ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
+    if (family == OMF_retain)
+      return rewriteToBridgedCast(E, OBC_BridgeRetained);
+
+    if (family == OMF_autorelease || family == OMF_release) {
+      std::string err = "it is not safe to cast to '";
+      err += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
+      err += "' the result of '";
+      err += family == OMF_autorelease ? "autorelease" : "release";
+      err += "' message; a __bridge cast may result in a pointer to a "
+          "destroyed object and a __bridge_retained may leak the object";
+      Pass.TA.reportError(err, E->getLocStart(),
+                          E->getSubExpr()->getSourceRange());
+      Stmt *parent = E;
+      do {
+        parent = StmtMap->getParentIgnoreParenImpCasts(parent);
+      } while (parent && isa<ExprWithCleanups>(parent));
+
+      if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
+        std::string note = "remove the cast and change return type of function "
+            "to '";
+        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.PrintingPolicy);
+        note += "' to have the object automatically autoreleased";
+        Pass.TA.reportNote(note, retS->getLocStart());
+      }
+    }
+
+    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
+      if (implCE->getCastKind() == CK_ObjCConsumeObject)
+        return rewriteToBridgedCast(E, OBC_BridgeRetained);
+      if (implCE->getCastKind() == CK_ObjCReclaimReturnedObject)
+        return rewriteToBridgedCast(E, OBC_Bridge);
+    }
   }
 
-  bool isSelf(Expr *E) {
+  static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
+    E = E->IgnoreParenCasts();
+    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
+      return ME->getMethodFamily();
+
+    return OMF_None;
+  }
+
+  bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
+    if ((callE = dyn_cast_or_null<CallExpr>(
+                                     StmtMap->getParentIgnoreParenImpCasts(E))))
+      if (FunctionDecl *
+            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
+        if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
+            FD->getParent()->isTranslationUnit() &&
+            FD->getLinkage() == ExternalLinkage)
+          return true;
+
+    return false;
+  }
+
+  bool isSelf(Expr *E) const {
     E = E->IgnoreParenLValueCasts();
     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
-      if (DRE->getDecl()->getIdentifier() == SelfII)
-        return true;
+      if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
+        if (IPD->getIdentifier() == SelfII)
+          return true;
+
     return false;
   }
 };
@@ -197,6 +279,6 @@
 } // end anonymous namespace
 
 void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
-  UnbridgedCastRewriter trans(pass);
+  BodyTransform<UnbridgedCastRewriter> trans(pass);
   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
 }

Modified: cfe/trunk/lib/ARCMigrate/Transforms.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Transforms.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Transforms.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/Transforms.cpp Wed Jul 27 00:28:18 2011
@@ -154,7 +154,8 @@
 bool trans::isGlobalVar(Expr *E) {
   E = E->IgnoreParenCasts();
   if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
-    return DRE->getDecl()->getDeclContext()->isFileContext();
+    return DRE->getDecl()->getDeclContext()->isFileContext() &&
+           DRE->getDecl()->getLinkage() == ExternalLinkage;
   if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
     return isGlobalVar(condOp->getTrueExpr()) &&
            isGlobalVar(condOp->getFalseExpr());
@@ -162,6 +163,13 @@
   return false;  
 }
 
+StringRef trans::getNilString(ASTContext &Ctx) {
+  if (Ctx.Idents.get("nil").hasMacroDefinition())
+    return "nil";
+  else
+    return "0";
+}
+
 namespace {
 
 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {

Modified: cfe/trunk/lib/ARCMigrate/Transforms.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Transforms.h?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Transforms.h (original)
+++ cfe/trunk/lib/ARCMigrate/Transforms.h Wed Jul 27 00:28:18 2011
@@ -56,7 +56,8 @@
 
 bool hasSideEffects(Expr *E, ASTContext &Ctx);
 bool isGlobalVar(Expr *E);
-
+/// \brief Returns "nil" or "0" if 'nil' macro is not actually defined.
+StringRef getNilString(ASTContext &Ctx);
 
 template <typename BODY_TRANS>
 class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {

Modified: cfe/trunk/lib/AST/ParentMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ParentMap.cpp?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ParentMap.cpp (original)
+++ cfe/trunk/lib/AST/ParentMap.cpp Wed Jul 27 00:28:18 2011
@@ -66,6 +66,14 @@
   return S;  
 }
 
+Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const {
+  do {
+    S = getParent(S);
+  } while (S && isa<Expr>(S) && cast<Expr>(S)->IgnoreParenImpCasts() != S);
+
+  return S;
+}
+
 Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
   Stmt *Paren = 0;
   while (isa<ParenExpr>(S)) {

Modified: cfe/trunk/test/ARCMT/Common.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/Common.h?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/Common.h (original)
+++ cfe/trunk/test/ARCMT/Common.h Wed Jul 27 00:28:18 2011
@@ -4,6 +4,8 @@
 #define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
 #endif
 
+#define nil ((void*) 0)
+
 typedef int BOOL;
 typedef unsigned NSUInteger;
 typedef int int32_t;
@@ -11,8 +13,14 @@
 typedef int32_t UChar32;
 typedef unsigned char UChar;
 
+typedef struct _NSZone NSZone;
+
+typedef const void * CFTypeRef;
+CFTypeRef CFRetain(CFTypeRef cf);
+
 @protocol NSObject
 - (BOOL)isEqual:(id)object;
+- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
 - (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
 - (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
 - (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;

Added: cfe/trunk/test/ARCMT/api.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/api.m?rev=136208&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/api.m (added)
+++ cfe/trunk/test/ARCMT/api.m Wed Jul 27 00:28:18 2011
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+void test(NSObject *o) {
+  NSZone *z = [o zone];
+}

Added: cfe/trunk/test/ARCMT/api.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/api.m.result?rev=136208&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/api.m.result (added)
+++ cfe/trunk/test/ARCMT/api.m.result Wed Jul 27 00:28:18 2011
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+void test(NSObject *o) {
+  NSZone *z = nil;
+}

Modified: cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m (original)
+++ cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m Wed Jul 27 00:28:18 2011
@@ -20,8 +20,9 @@
   id not_safe1;
   NSObject *not_safe2;
   Forw *not_safe3;
+  Foo *assign_plus1;
 }
- at property (readonly,assign) Foo *x;
+ at property (readonly) Foo *x;
 @property (assign) Foo *w;
 @property Foo *q1, *q2;
 @property (assign) WeakOptOut *oo;
@@ -29,12 +30,22 @@
 @property (assign) id not_safe1;
 @property () NSObject *not_safe2;
 @property Forw *not_safe3;
+ at property (readonly) Foo *assign_plus1;
+ at property (readonly) Foo *assign_plus2;
 
 @property (assign) Foo *no_user_ivar1;
 @property (readonly) Foo *no_user_ivar2;
+
+-(void)test;
 @end
 
 @implementation Foo
 @synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
 @synthesize no_user_ivar1, no_user_ivar2;
+ at synthesize assign_plus1, assign_plus2;
+
+-(void)test {
+  assign_plus1 = [[Foo alloc] init];
+  assign_plus2 = [Foo new];
+}
 @end

Modified: cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result (original)
+++ cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result Wed Jul 27 00:28:18 2011
@@ -20,8 +20,9 @@
   id __unsafe_unretained not_safe1;
   NSObject *__unsafe_unretained not_safe2;
   Forw *__unsafe_unretained not_safe3;
+  Foo *assign_plus1;
 }
- at property (readonly,weak) Foo *x;
+ at property (readonly) Foo *x;
 @property (weak) Foo *w;
 @property (weak) Foo *q1, *q2;
 @property (unsafe_unretained) WeakOptOut *oo;
@@ -29,12 +30,22 @@
 @property (unsafe_unretained) id not_safe1;
 @property (unsafe_unretained) NSObject *not_safe2;
 @property (unsafe_unretained) Forw *not_safe3;
+ at property (readonly) Foo *assign_plus1;
+ at property (strong, readonly) Foo *assign_plus2;
 
 @property (weak) Foo *no_user_ivar1;
 @property (weak, readonly) Foo *no_user_ivar2;
+
+-(void)test;
 @end
 
 @implementation Foo
 @synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
 @synthesize no_user_ivar1, no_user_ivar2;
+ at synthesize assign_plus1, assign_plus2;
+
+-(void)test {
+  assign_plus1 = [[Foo alloc] init];
+  assign_plus2 = [Foo new];
+}
 @end

Modified: cfe/trunk/test/ARCMT/atautorelease.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease.m?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease.m (original)
+++ cfe/trunk/test/ARCMT/atautorelease.m Wed Jul 27 00:28:18 2011
@@ -45,3 +45,17 @@
     [pool release];
     return result;
 }
+
+ at interface Foo : NSObject
+ at property (assign) id myProp;
+ at end
+
+ at implementation Foo
+ at synthesize myProp;
+
+-(void)test:(id)p {
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+  [pool drain];
+  self.myProp = p;
+}
+ at end

Modified: cfe/trunk/test/ARCMT/atautorelease.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease.m.result?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease.m.result (original)
+++ cfe/trunk/test/ARCMT/atautorelease.m.result Wed Jul 27 00:28:18 2011
@@ -44,3 +44,17 @@
         return result;
     }
 }
+
+ at interface Foo : NSObject
+ at property (unsafe_unretained) id myProp;
+ at end
+
+ at implementation Foo
+ at synthesize myProp;
+
+-(void)test:(id)p {
+  @autoreleasepool {
+  }
+  self.myProp = p;
+}
+ at end

Modified: cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m (original)
+++ cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m Wed Jul 27 00:28:18 2011
@@ -1,9 +1,13 @@
 // RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
 
-typedef int BOOL;
-typedef const struct __CFString * CFStringRef;
+#include "Common.h"
+
+ at interface NSString : NSObject
+-(id)string;
+-(id)newString;
+ at end
 
- at class NSString;
+typedef const struct __CFString * CFStringRef;
 
 void f(BOOL b) {
   CFStringRef cfstr;
@@ -12,3 +16,16 @@
     // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
   void *vp = str;  // expected-error {{disallowed}}
 }
+
+void f2(NSString *s) {
+  CFStringRef ref;
+  ref = [(CFStringRef)[s string] retain]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef' (aka 'const struct __CFString *') requires a bridged cast}} \
+    // expected-error {{ bad receiver type 'CFStringRef' (aka 'const struct __CFString *')}} \
+    // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+    // expected-note{{use __bridge_retained to make an ARC object available as a +1 'CFStringRef' (aka 'const struct __CFString *')}}
+}
+
+CFStringRef f3() {
+  return (CFStringRef)[[[NSString alloc] init] autorelease]; // expected-error {{it is not safe to cast to 'CFStringRef' the result of 'autorelease' message; a __bridge cast may result in a pointer to a destroyed object and a __bridge_retained may leak the object}} \
+    // expected-note {{remove the cast and change return type of function to 'NSString *' to have the object automatically autoreleased}}
+}

Modified: cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m (original)
+++ cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m Wed Jul 27 00:28:18 2011
@@ -5,6 +5,8 @@
 #include "Common.h"
 
 @interface NSString : NSObject
+-(id)string;
+-(id)newString;
 @end
 
 typedef const struct __CFString * CFStringRef;
@@ -27,6 +29,7 @@
   CFUUIDRef   _uuid;
   NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
   _uuidString = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid) autorelease];
+  _uuidString = CFRetain(_uuid);
 }
 
 @implementation NSString (StrExt)
@@ -36,3 +39,18 @@
   return self;
 }
 @end
+
+void f2(NSString *s) {
+  CFStringRef ref = [s string];
+  ref = (CFStringRef)[s string];
+  ref = s.string;
+  ref = [NSString new];
+  ref = [s newString];
+  ref = (CFStringRef)[NSString new];
+  ref = [[NSString alloc] init];
+  ref = [[s string] retain];
+  ref = CFRetain((CFStringRef)[s string]);
+  ref = CFRetain([s string]);
+  ref = CFRetain(s);
+  ref = [s retain];
+}

Modified: cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result (original)
+++ cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result Wed Jul 27 00:28:18 2011
@@ -5,6 +5,8 @@
 #include "Common.h"
 
 @interface NSString : NSObject
+-(id)string;
+-(id)newString;
 @end
 
 typedef const struct __CFString * CFStringRef;
@@ -27,6 +29,7 @@
   CFUUIDRef   _uuid;
   NSString *_uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
   _uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+  _uuidString = (__bridge_transfer NSString *)(CFRetain(_uuid));
 }
 
 @implementation NSString (StrExt)
@@ -36,3 +39,18 @@
   return self;
 }
 @end
+
+void f2(NSString *s) {
+  CFStringRef ref = (__bridge CFStringRef)([s string]);
+  ref = (__bridge CFStringRef)[s string];
+  ref = (__bridge CFStringRef)(s.string);
+  ref = (__bridge_retained CFStringRef)([NSString new]);
+  ref = (__bridge_retained CFStringRef)([s newString]);
+  ref = (__bridge_retained CFStringRef)[NSString new];
+  ref = (__bridge_retained CFStringRef)([[NSString alloc] init]);
+  ref = (__bridge_retained CFStringRef)([s string]);
+  ref = (__bridge_retained CFStringRef)[s string];
+  ref = (__bridge_retained CFTypeRef)([s string]);
+  ref = (__bridge_retained CFTypeRef)(s);
+  ref = (__bridge_retained CFStringRef)(s);
+}

Modified: cfe/trunk/test/ARCMT/releases.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/releases.m?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/releases.m (original)
+++ cfe/trunk/test/ARCMT/releases.m Wed Jul 27 00:28:18 2011
@@ -85,3 +85,15 @@
   RELEASE_MACRO(p);
   RELEASE_MACRO2(p);
 }
+
+ at implementation Foo2
+
+static id internal_var = 0;
+
++ (void)setIt:(id)newone {
+    if (internal_var != newone) {
+        [internal_var release];
+        internal_var = [newone retain];
+    }
+}
+ at end

Modified: cfe/trunk/test/ARCMT/releases.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/releases.m.result?rev=136208&r1=136207&r2=136208&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/releases.m.result (original)
+++ cfe/trunk/test/ARCMT/releases.m.result Wed Jul 27 00:28:18 2011
@@ -77,3 +77,14 @@
 
 void test2(id p) {
 }
+
+ at implementation Foo2
+
+static id internal_var = 0;
+
++ (void)setIt:(id)newone {
+    if (internal_var != newone) {
+        internal_var = newone;
+    }
+}
+ at end





More information about the cfe-commits mailing list