From: Argyrios Kyrtzidis Date: Tue, 12 Jul 2011 22:05:17 +0000 (+0000) Subject: [arcmt] Before applying '__weak' check whether the objc class is annotated with objc_... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=86625b5650cdddc38c0b4cc1eb7fb460478c9d11;p=clang [arcmt] Before applying '__weak' check whether the objc class is annotated with objc_arc_weak_reference_unavailable or is in a list of classes not supporting 'weak'. rdar://9489367. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135002 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp index 97695cbccf..0e342b7a8f 100644 --- a/lib/ARCMigrate/TransBlockObjCVariable.cpp +++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp @@ -98,12 +98,12 @@ public: BlocksAttr *attr = var->getAttr(); if(!attr) continue; - bool hasWeak = Pass.Ctx.getLangOptions().ObjCRuntimeHasWeak; + bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); SourceManager &SM = Pass.Ctx.getSourceManager(); Transaction Trans(Pass.TA); Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()), "__block", - hasWeak ? "__weak" : "__unsafe_unretained"); + useWeak ? "__weak" : "__unsafe_unretained"); } } diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp index 0efc4c0fad..82ef717f31 100644 --- a/lib/ARCMigrate/TransProperties.cpp +++ b/lib/ARCMigrate/TransProperties.cpp @@ -112,7 +112,7 @@ public: } void applyWeak(PropData &prop) { - assert(Pass.Ctx.getLangOptions().ObjCRuntimeHasWeak); + assert(canApplyWeak(Pass.Ctx, prop.IvarD->getType())); Transaction Trans(Pass.TA); Pass.TA.insert(prop.IvarD->getLocation(), "__weak "); @@ -157,7 +157,7 @@ public: // There is a "error: existing ivar for assign property must be // __unsafe_unretained"; fix it. - if (!Pass.Ctx.getLangOptions().ObjCRuntimeHasWeak) { + if (!canApplyWeak(Pass.Ctx, ivarD->getType())) { // We will just add __unsafe_unretained to the ivar. Transaction Trans(Pass.TA); Pass.TA.insert(ivarD->getLocation(), "__unsafe_unretained "); diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 546829120c..c2f85f65b7 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -29,6 +29,61 @@ using llvm::StringRef; // Helpers. //===----------------------------------------------------------------------===// +/// \brief True if the class is one that does not support weak. +static bool isClassInWeakBlacklist(ObjCInterfaceDecl *cls) { + if (!cls) + return false; + + bool inList = llvm::StringSwitch(cls->getName()) + .Case("NSColorSpace", true) + .Case("NSFont", true) + .Case("NSFontPanel", true) + .Case("NSImage", true) + .Case("NSLazyBrowserCell", true) + .Case("NSWindow", true) + .Case("NSWindowController", true) + .Case("NSMenuView", true) + .Case("NSPersistentUIWindowInfo", true) + .Case("NSTableCellView", true) + .Case("NSATSTypeSetter", true) + .Case("NSATSGlyphStorage", true) + .Case("NSLineFragmentRenderingContext", true) + .Case("NSAttributeDictionary", true) + .Case("NSParagraphStyle", true) + .Case("NSTextTab", true) + .Case("NSSimpleHorizontalTypesetter", true) + .Case("_NSCachedAttributedString", true) + .Case("NSStringDrawingTextStorage", true) + .Case("NSTextView", true) + .Case("NSSubTextStorage", true) + .Default(false); + + if (inList) + return true; + + return isClassInWeakBlacklist(cls->getSuperClass()); +} + +bool trans::canApplyWeak(ASTContext &Ctx, QualType type) { + if (!Ctx.getLangOptions().ObjCRuntimeHasWeak) + return false; + + QualType T = type; + while (const PointerType *ptr = T->getAs()) + T = ptr->getPointeeType(); + if (const ObjCObjectPointerType *ObjT = T->getAs()) { + ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); + if (!Class || Class->getName() == "NSObject") + return false; // id/NSObject is not safe for weak. + if (Class->isArcWeakrefUnavailable()) + return false; + if (isClassInWeakBlacklist(Class)) + return false; + } + + return true; +} + /// \brief 'Loc' is the end of a statement range. This returns the location /// immediately after the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index 21064973bf..d52fba0130 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -44,6 +44,9 @@ void removeEmptyStatementsAndDealloc(MigrationPass &pass); // Helpers. //===----------------------------------------------------------------------===// +/// \brief Determine whether we can add weak to the given type. +bool canApplyWeak(ASTContext &Ctx, QualType type); + /// \brief 'Loc' is the end of a statement range. This returns the location /// immediately after the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m b/test/ARCMT/assign-prop-with-arc-runtime.m index 8d9f21115c..e9416fe029 100644 --- a/test/ARCMT/assign-prop-with-arc-runtime.m +++ b/test/ARCMT/assign-prop-with-arc-runtime.m @@ -4,16 +4,32 @@ #include "Common.h" +__attribute__((objc_arc_weak_reference_unavailable)) +@interface WeakOptOut +@end + +@class _NSCachedAttributedString; + +typedef _NSCachedAttributedString *BadClassForWeak; + @interface Foo : NSObject { - NSObject *x, *w, *q1, *q2; - NSObject *z1, *__unsafe_unretained z2; + Foo *x, *w, *q1, *q2; + Foo *z1, *__unsafe_unretained z2; + WeakOptOut *oo; + BadClassForWeak bcw; + id not_safe1; + NSObject *not_safe2; } -@property (readonly,assign) id x; -@property (assign) id w; -@property (assign) id q1, q2; -@property (assign) id z1, z2; +@property (readonly,assign) Foo *x; +@property (assign) Foo *w; +@property (assign) Foo *q1, *q2; +@property (assign) Foo *z1, *z2; +@property (assign) WeakOptOut *oo; +@property (assign) BadClassForWeak bcw; +@property (assign) id not_safe1; +@property (assign) NSObject *not_safe2; @end @implementation Foo -@synthesize x,w,q1,q2,z1,z2; +@synthesize x,w,q1,q2,z1,z2,oo,bcw,not_safe1,not_safe2; @end diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m.result b/test/ARCMT/assign-prop-with-arc-runtime.m.result index 2d74ae2ed9..349bfa28c4 100644 --- a/test/ARCMT/assign-prop-with-arc-runtime.m.result +++ b/test/ARCMT/assign-prop-with-arc-runtime.m.result @@ -4,16 +4,32 @@ #include "Common.h" +__attribute__((objc_arc_weak_reference_unavailable)) +@interface WeakOptOut +@end + +@class _NSCachedAttributedString; + +typedef _NSCachedAttributedString *BadClassForWeak; + @interface Foo : NSObject { - NSObject *__weak x, *__weak w, *__weak q1, *__weak q2; - NSObject *__unsafe_unretained z1, *__unsafe_unretained z2; + Foo *__weak x, *__weak w, *__weak q1, *__weak q2; + Foo *__unsafe_unretained z1, *__unsafe_unretained z2; + WeakOptOut *__unsafe_unretained oo; + BadClassForWeak __unsafe_unretained bcw; + id __unsafe_unretained not_safe1; + NSObject *__unsafe_unretained not_safe2; } -@property (readonly,weak) id x; -@property (weak) id w; -@property (weak) id q1, q2; -@property (assign) id z1, z2; +@property (readonly,weak) Foo *x; +@property (weak) Foo *w; +@property (weak) Foo *q1, *q2; +@property (assign) Foo *z1, *z2; +@property (assign) WeakOptOut *oo; +@property (assign) BadClassForWeak bcw; +@property (assign) id not_safe1; +@property (assign) NSObject *not_safe2; @end @implementation Foo -@synthesize x,w,q1,q2,z1,z2; +@synthesize x,w,q1,q2,z1,z2,oo,bcw,not_safe1,not_safe2; @end