[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