From ce9b73999974bf2efae2dd614dcec67017b817fe Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Tue, 12 Jul 2011 22:05:17 +0000 Subject: [PATCH] [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. llvm-svn: 135002 --- .../lib/ARCMigrate/TransBlockObjCVariable.cpp | 4 +- clang/lib/ARCMigrate/TransProperties.cpp | 4 +- clang/lib/ARCMigrate/Transforms.cpp | 55 +++++++++++++++++++ clang/lib/ARCMigrate/Transforms.h | 3 + .../test/ARCMT/assign-prop-with-arc-runtime.m | 30 +++++++--- .../assign-prop-with-arc-runtime.m.result | 30 +++++++--- 6 files changed, 108 insertions(+), 18 deletions(-) diff --git a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp index 97695cbccfa5..0e342b7a8f8c 100644 --- a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp +++ b/clang/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/clang/lib/ARCMigrate/TransProperties.cpp b/clang/lib/ARCMigrate/TransProperties.cpp index 0efc4c0fadf0..82ef717f3155 100644 --- a/clang/lib/ARCMigrate/TransProperties.cpp +++ b/clang/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/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp index 546829120c06..c2f85f65b76b 100644 --- a/clang/lib/ARCMigrate/Transforms.cpp +++ b/clang/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/clang/lib/ARCMigrate/Transforms.h b/clang/lib/ARCMigrate/Transforms.h index 21064973bf71..d52fba013078 100644 --- a/clang/lib/ARCMigrate/Transforms.h +++ b/clang/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/clang/test/ARCMT/assign-prop-with-arc-runtime.m b/clang/test/ARCMT/assign-prop-with-arc-runtime.m index 8d9f21115c53..e9416fe02929 100644 --- a/clang/test/ARCMT/assign-prop-with-arc-runtime.m +++ b/clang/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/clang/test/ARCMT/assign-prop-with-arc-runtime.m.result b/clang/test/ARCMT/assign-prop-with-arc-runtime.m.result index 2d74ae2ed9f7..349bfa28c45d 100644 --- a/clang/test/ARCMT/assign-prop-with-arc-runtime.m.result +++ b/clang/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 -- GitLab