xref: /freebsd/contrib/llvm-project/clang/lib/ARCMigrate/TransProperties.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===--- TransProperties.cpp - Transformations to ARC mode ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // rewriteProperties:
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // - Adds strong/weak/unsafe_unretained ownership specifier to properties that
120b57cec5SDimitry Andric //   are missing one.
130b57cec5SDimitry Andric // - Migrates properties from (retain) to (strong) and (assign) to
140b57cec5SDimitry Andric //   (unsafe_unretained/weak).
150b57cec5SDimitry Andric // - If a property is synthesized, adds the ownership specifier in the ivar
160b57cec5SDimitry Andric //   backing the property.
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric //  @interface Foo : NSObject {
190b57cec5SDimitry Andric //      NSObject *x;
200b57cec5SDimitry Andric //  }
210b57cec5SDimitry Andric //  @property (assign) id x;
220b57cec5SDimitry Andric //  @end
230b57cec5SDimitry Andric // ---->
240b57cec5SDimitry Andric //  @interface Foo : NSObject {
250b57cec5SDimitry Andric //      NSObject *__weak x;
260b57cec5SDimitry Andric //  }
270b57cec5SDimitry Andric //  @property (weak) id x;
280b57cec5SDimitry Andric //  @end
290b57cec5SDimitry Andric //
300b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric #include "Transforms.h"
330b57cec5SDimitry Andric #include "Internals.h"
340b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
350b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
360b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h"
370b57cec5SDimitry Andric #include <map>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace clang;
400b57cec5SDimitry Andric using namespace arcmt;
410b57cec5SDimitry Andric using namespace trans;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric namespace {
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric class PropertiesRewriter {
460b57cec5SDimitry Andric   MigrationContext &MigrateCtx;
470b57cec5SDimitry Andric   MigrationPass &Pass;
48*06c3fb27SDimitry Andric   ObjCImplementationDecl *CurImplD = nullptr;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   enum PropActionKind {
510b57cec5SDimitry Andric     PropAction_None,
520b57cec5SDimitry Andric     PropAction_RetainReplacedWithStrong,
530b57cec5SDimitry Andric     PropAction_AssignRemoved,
540b57cec5SDimitry Andric     PropAction_AssignRewritten,
550b57cec5SDimitry Andric     PropAction_MaybeAddWeakOrUnsafe
560b57cec5SDimitry Andric   };
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   struct PropData {
590b57cec5SDimitry Andric     ObjCPropertyDecl *PropD;
600b57cec5SDimitry Andric     ObjCIvarDecl *IvarD;
610b57cec5SDimitry Andric     ObjCPropertyImplDecl *ImplD;
620b57cec5SDimitry Andric 
PropData__anon8393a07d0111::PropertiesRewriter::PropData630b57cec5SDimitry Andric     PropData(ObjCPropertyDecl *propD)
640b57cec5SDimitry Andric       : PropD(propD), IvarD(nullptr), ImplD(nullptr) {}
650b57cec5SDimitry Andric   };
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   typedef SmallVector<PropData, 2> PropsTy;
68e8d8bef9SDimitry Andric   typedef std::map<SourceLocation, PropsTy> AtPropDeclsTy;
690b57cec5SDimitry Andric   AtPropDeclsTy AtProps;
700b57cec5SDimitry Andric   llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric public:
PropertiesRewriter(MigrationContext & MigrateCtx)730b57cec5SDimitry Andric   explicit PropertiesRewriter(MigrationContext &MigrateCtx)
740b57cec5SDimitry Andric     : MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
750b57cec5SDimitry Andric 
collectProperties(ObjCContainerDecl * D,AtPropDeclsTy & AtProps,AtPropDeclsTy * PrevAtProps=nullptr)760b57cec5SDimitry Andric   static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
770b57cec5SDimitry Andric                                 AtPropDeclsTy *PrevAtProps = nullptr) {
780b57cec5SDimitry Andric     for (auto *Prop : D->instance_properties()) {
79e8d8bef9SDimitry Andric       SourceLocation Loc = Prop->getAtLoc();
80e8d8bef9SDimitry Andric       if (Loc.isInvalid())
810b57cec5SDimitry Andric         continue;
820b57cec5SDimitry Andric       if (PrevAtProps)
83e8d8bef9SDimitry Andric         if (PrevAtProps->find(Loc) != PrevAtProps->end())
840b57cec5SDimitry Andric           continue;
85e8d8bef9SDimitry Andric       PropsTy &props = AtProps[Loc];
860b57cec5SDimitry Andric       props.push_back(Prop);
870b57cec5SDimitry Andric     }
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric 
doTransform(ObjCImplementationDecl * D)900b57cec5SDimitry Andric   void doTransform(ObjCImplementationDecl *D) {
910b57cec5SDimitry Andric     CurImplD = D;
920b57cec5SDimitry Andric     ObjCInterfaceDecl *iface = D->getClassInterface();
930b57cec5SDimitry Andric     if (!iface)
940b57cec5SDimitry Andric       return;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     collectProperties(iface, AtProps);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric     // Look through extensions.
990b57cec5SDimitry Andric     for (auto *Ext : iface->visible_extensions())
1000b57cec5SDimitry Andric       collectProperties(Ext, AtProps);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric     typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
1030b57cec5SDimitry Andric         prop_impl_iterator;
1040b57cec5SDimitry Andric     for (prop_impl_iterator
1050b57cec5SDimitry Andric            I = prop_impl_iterator(D->decls_begin()),
1060b57cec5SDimitry Andric            E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
1070b57cec5SDimitry Andric       ObjCPropertyImplDecl *implD = *I;
1080b57cec5SDimitry Andric       if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
1090b57cec5SDimitry Andric         continue;
1100b57cec5SDimitry Andric       ObjCPropertyDecl *propD = implD->getPropertyDecl();
1110b57cec5SDimitry Andric       if (!propD || propD->isInvalidDecl())
1120b57cec5SDimitry Andric         continue;
1130b57cec5SDimitry Andric       ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
1140b57cec5SDimitry Andric       if (!ivarD || ivarD->isInvalidDecl())
1150b57cec5SDimitry Andric         continue;
116e8d8bef9SDimitry Andric       AtPropDeclsTy::iterator findAtLoc = AtProps.find(propD->getAtLoc());
1170b57cec5SDimitry Andric       if (findAtLoc == AtProps.end())
1180b57cec5SDimitry Andric         continue;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric       PropsTy &props = findAtLoc->second;
1210b57cec5SDimitry Andric       for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
1220b57cec5SDimitry Andric         if (I->PropD == propD) {
1230b57cec5SDimitry Andric           I->IvarD = ivarD;
1240b57cec5SDimitry Andric           I->ImplD = implD;
1250b57cec5SDimitry Andric           break;
1260b57cec5SDimitry Andric         }
1270b57cec5SDimitry Andric       }
1280b57cec5SDimitry Andric     }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric     for (AtPropDeclsTy::iterator
1310b57cec5SDimitry Andric            I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
132e8d8bef9SDimitry Andric       SourceLocation atLoc = I->first;
1330b57cec5SDimitry Andric       PropsTy &props = I->second;
1340b57cec5SDimitry Andric       if (!getPropertyType(props)->isObjCRetainableType())
1350b57cec5SDimitry Andric         continue;
1360b57cec5SDimitry Andric       if (hasIvarWithExplicitARCOwnership(props))
1370b57cec5SDimitry Andric         continue;
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric       Transaction Trans(Pass.TA);
1400b57cec5SDimitry Andric       rewriteProperty(props, atLoc);
1410b57cec5SDimitry Andric     }
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric private:
doPropAction(PropActionKind kind,PropsTy & props,SourceLocation atLoc,bool markAction=true)1450b57cec5SDimitry Andric   void doPropAction(PropActionKind kind,
1460b57cec5SDimitry Andric                     PropsTy &props, SourceLocation atLoc,
1470b57cec5SDimitry Andric                     bool markAction = true) {
1480b57cec5SDimitry Andric     if (markAction)
1490b57cec5SDimitry Andric       for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
1500b57cec5SDimitry Andric         ActionOnProp[I->PropD->getIdentifier()] = kind;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     switch (kind) {
1530b57cec5SDimitry Andric     case PropAction_None:
1540b57cec5SDimitry Andric       return;
1550b57cec5SDimitry Andric     case PropAction_RetainReplacedWithStrong: {
1560b57cec5SDimitry Andric       StringRef toAttr = "strong";
1570b57cec5SDimitry Andric       MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc);
1580b57cec5SDimitry Andric       return;
1590b57cec5SDimitry Andric     }
1600b57cec5SDimitry Andric     case PropAction_AssignRemoved:
1610b57cec5SDimitry Andric       return removeAssignForDefaultStrong(props, atLoc);
1620b57cec5SDimitry Andric     case PropAction_AssignRewritten:
1630b57cec5SDimitry Andric       return rewriteAssign(props, atLoc);
1640b57cec5SDimitry Andric     case PropAction_MaybeAddWeakOrUnsafe:
1650b57cec5SDimitry Andric       return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
1660b57cec5SDimitry Andric     }
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric 
rewriteProperty(PropsTy & props,SourceLocation atLoc)1690b57cec5SDimitry Andric   void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
1705ffd83dbSDimitry Andric     ObjCPropertyAttribute::Kind propAttrs = getPropertyAttrs(props);
1710b57cec5SDimitry Andric 
1725ffd83dbSDimitry Andric     if (propAttrs &
1735ffd83dbSDimitry Andric         (ObjCPropertyAttribute::kind_copy |
1745ffd83dbSDimitry Andric          ObjCPropertyAttribute::kind_unsafe_unretained |
1755ffd83dbSDimitry Andric          ObjCPropertyAttribute::kind_strong | ObjCPropertyAttribute::kind_weak))
1760b57cec5SDimitry Andric       return;
1770b57cec5SDimitry Andric 
1785ffd83dbSDimitry Andric     if (propAttrs & ObjCPropertyAttribute::kind_retain) {
1790b57cec5SDimitry Andric       // strong is the default.
1800b57cec5SDimitry Andric       return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc);
1810b57cec5SDimitry Andric     }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
1840b57cec5SDimitry Andric 
1855ffd83dbSDimitry Andric     if (propAttrs & ObjCPropertyAttribute::kind_assign) {
1860b57cec5SDimitry Andric       if (HasIvarAssignedAPlusOneObject)
1870b57cec5SDimitry Andric         return doPropAction(PropAction_AssignRemoved, props, atLoc);
1880b57cec5SDimitry Andric       return doPropAction(PropAction_AssignRewritten, props, atLoc);
1890b57cec5SDimitry Andric     }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     if (HasIvarAssignedAPlusOneObject ||
1920b57cec5SDimitry Andric         (Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
1930b57cec5SDimitry Andric       return; // 'strong' by default.
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric     return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric 
removeAssignForDefaultStrong(PropsTy & props,SourceLocation atLoc) const1980b57cec5SDimitry Andric   void removeAssignForDefaultStrong(PropsTy &props,
1990b57cec5SDimitry Andric                                     SourceLocation atLoc) const {
2000b57cec5SDimitry Andric     removeAttribute("retain", atLoc);
2010b57cec5SDimitry Andric     if (!removeAttribute("assign", atLoc))
2020b57cec5SDimitry Andric       return;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
2050b57cec5SDimitry Andric       if (I->ImplD)
2060b57cec5SDimitry Andric         Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
2070b57cec5SDimitry Andric                                 diag::err_arc_assign_property_ownership,
2080b57cec5SDimitry Andric                                 diag::err_arc_inconsistent_property_ownership,
2090b57cec5SDimitry Andric                                 I->IvarD->getLocation());
2100b57cec5SDimitry Andric     }
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric 
rewriteAssign(PropsTy & props,SourceLocation atLoc) const2130b57cec5SDimitry Andric   void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
2140b57cec5SDimitry Andric     bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
2150b57cec5SDimitry Andric                                   /*AllowOnUnknownClass=*/Pass.isGCMigration());
2160b57cec5SDimitry Andric     const char *toWhich =
2170b57cec5SDimitry Andric       (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" :
2180b57cec5SDimitry Andric       (canUseWeak ? "weak" : "unsafe_unretained");
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric     bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc);
2210b57cec5SDimitry Andric     if (!rewroteAttr)
2220b57cec5SDimitry Andric       canUseWeak = false;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
2250b57cec5SDimitry Andric       if (isUserDeclared(I->IvarD)) {
2260b57cec5SDimitry Andric         if (I->IvarD &&
2270b57cec5SDimitry Andric             I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) {
2280b57cec5SDimitry Andric           const char *toWhich =
2290b57cec5SDimitry Andric             (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " :
2300b57cec5SDimitry Andric               (canUseWeak ? "__weak " : "__unsafe_unretained ");
2310b57cec5SDimitry Andric           Pass.TA.insert(I->IvarD->getLocation(), toWhich);
2320b57cec5SDimitry Andric         }
2330b57cec5SDimitry Andric       }
2340b57cec5SDimitry Andric       if (I->ImplD)
2350b57cec5SDimitry Andric         Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
2360b57cec5SDimitry Andric                                 diag::err_arc_assign_property_ownership,
2370b57cec5SDimitry Andric                                 diag::err_arc_inconsistent_property_ownership,
2380b57cec5SDimitry Andric                                 I->IvarD->getLocation());
2390b57cec5SDimitry Andric     }
2400b57cec5SDimitry Andric   }
2410b57cec5SDimitry Andric 
maybeAddWeakOrUnsafeUnretainedAttr(PropsTy & props,SourceLocation atLoc) const2420b57cec5SDimitry Andric   void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
2430b57cec5SDimitry Andric                                           SourceLocation atLoc) const {
2440b57cec5SDimitry Andric     bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
2450b57cec5SDimitry Andric                                   /*AllowOnUnknownClass=*/Pass.isGCMigration());
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric     bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
2480b57cec5SDimitry Andric                                   atLoc);
2490b57cec5SDimitry Andric     if (!addedAttr)
2500b57cec5SDimitry Andric       canUseWeak = false;
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
2530b57cec5SDimitry Andric       if (isUserDeclared(I->IvarD)) {
2540b57cec5SDimitry Andric         if (I->IvarD &&
2550b57cec5SDimitry Andric             I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
2560b57cec5SDimitry Andric           Pass.TA.insert(I->IvarD->getLocation(),
2570b57cec5SDimitry Andric                          canUseWeak ? "__weak " : "__unsafe_unretained ");
2580b57cec5SDimitry Andric       }
2590b57cec5SDimitry Andric       if (I->ImplD) {
2600b57cec5SDimitry Andric         Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
2610b57cec5SDimitry Andric                                 diag::err_arc_assign_property_ownership,
2620b57cec5SDimitry Andric                                 diag::err_arc_inconsistent_property_ownership,
2630b57cec5SDimitry Andric                                 I->IvarD->getLocation());
2640b57cec5SDimitry Andric         Pass.TA.clearDiagnostic(
2650b57cec5SDimitry Andric                            diag::err_arc_objc_property_default_assign_on_object,
2660b57cec5SDimitry Andric                            I->ImplD->getLocation());
2670b57cec5SDimitry Andric       }
2680b57cec5SDimitry Andric     }
2690b57cec5SDimitry Andric   }
2700b57cec5SDimitry Andric 
removeAttribute(StringRef fromAttr,SourceLocation atLoc) const2710b57cec5SDimitry Andric   bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
2720b57cec5SDimitry Andric     return MigrateCtx.removePropertyAttribute(fromAttr, atLoc);
2730b57cec5SDimitry Andric   }
2740b57cec5SDimitry Andric 
rewriteAttribute(StringRef fromAttr,StringRef toAttr,SourceLocation atLoc) const2750b57cec5SDimitry Andric   bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
2760b57cec5SDimitry Andric                         SourceLocation atLoc) const {
2770b57cec5SDimitry Andric     return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
2780b57cec5SDimitry Andric   }
2790b57cec5SDimitry Andric 
addAttribute(StringRef attr,SourceLocation atLoc) const2800b57cec5SDimitry Andric   bool addAttribute(StringRef attr, SourceLocation atLoc) const {
2810b57cec5SDimitry Andric     return MigrateCtx.addPropertyAttribute(attr, atLoc);
2820b57cec5SDimitry Andric   }
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
2850b57cec5SDimitry Andric     ObjCIvarDecl *Ivar;
2860b57cec5SDimitry Andric   public:
PlusOneAssign(ObjCIvarDecl * D)2870b57cec5SDimitry Andric     PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
2880b57cec5SDimitry Andric 
VisitBinaryOperator(BinaryOperator * E)2895ffd83dbSDimitry Andric     bool VisitBinaryOperator(BinaryOperator *E) {
2905ffd83dbSDimitry Andric       if (E->getOpcode() != BO_Assign)
2915ffd83dbSDimitry Andric         return true;
2925ffd83dbSDimitry Andric 
2930b57cec5SDimitry Andric       Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
2940b57cec5SDimitry Andric       if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
2950b57cec5SDimitry Andric         if (RE->getDecl() != Ivar)
2960b57cec5SDimitry Andric           return true;
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric         if (isPlusOneAssign(E))
2990b57cec5SDimitry Andric           return false;
3000b57cec5SDimitry Andric       }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric       return true;
3030b57cec5SDimitry Andric     }
3040b57cec5SDimitry Andric   };
3050b57cec5SDimitry Andric 
hasIvarAssignedAPlusOneObject(PropsTy & props) const3060b57cec5SDimitry Andric   bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
3070b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
3080b57cec5SDimitry Andric       PlusOneAssign oneAssign(I->IvarD);
3090b57cec5SDimitry Andric       bool notFound = oneAssign.TraverseDecl(CurImplD);
3100b57cec5SDimitry Andric       if (!notFound)
3110b57cec5SDimitry Andric         return true;
3120b57cec5SDimitry Andric     }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric     return false;
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric 
hasIvarWithExplicitARCOwnership(PropsTy & props) const3170b57cec5SDimitry Andric   bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
3180b57cec5SDimitry Andric     if (Pass.isGCMigration())
3190b57cec5SDimitry Andric       return false;
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
3220b57cec5SDimitry Andric       if (isUserDeclared(I->IvarD)) {
3230b57cec5SDimitry Andric         if (isa<AttributedType>(I->IvarD->getType()))
3240b57cec5SDimitry Andric           return true;
3250b57cec5SDimitry Andric         if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
3260b57cec5SDimitry Andric               != Qualifiers::OCL_Strong)
3270b57cec5SDimitry Andric           return true;
3280b57cec5SDimitry Andric       }
3290b57cec5SDimitry Andric     }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric     return false;
3320b57cec5SDimitry Andric   }
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   // Returns true if all declarations in the @property have GC __weak.
hasGCWeak(PropsTy & props,SourceLocation atLoc) const3350b57cec5SDimitry Andric   bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
3360b57cec5SDimitry Andric     if (!Pass.isGCMigration())
3370b57cec5SDimitry Andric       return false;
3380b57cec5SDimitry Andric     if (props.empty())
3390b57cec5SDimitry Andric       return false;
340e8d8bef9SDimitry Andric     return MigrateCtx.AtPropsWeak.count(atLoc);
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
isUserDeclared(ObjCIvarDecl * ivarD) const3430b57cec5SDimitry Andric   bool isUserDeclared(ObjCIvarDecl *ivarD) const {
3440b57cec5SDimitry Andric     return ivarD && !ivarD->getSynthesize();
3450b57cec5SDimitry Andric   }
3460b57cec5SDimitry Andric 
getPropertyType(PropsTy & props) const3470b57cec5SDimitry Andric   QualType getPropertyType(PropsTy &props) const {
3480b57cec5SDimitry Andric     assert(!props.empty());
3490b57cec5SDimitry Andric     QualType ty = props[0].PropD->getType().getUnqualifiedType();
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric #ifndef NDEBUG
3520b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
3530b57cec5SDimitry Andric       assert(ty == I->PropD->getType().getUnqualifiedType());
3540b57cec5SDimitry Andric #endif
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric     return ty;
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
getPropertyAttrs(PropsTy & props) const3595ffd83dbSDimitry Andric   ObjCPropertyAttribute::Kind getPropertyAttrs(PropsTy &props) const {
3600b57cec5SDimitry Andric     assert(!props.empty());
3615ffd83dbSDimitry Andric     ObjCPropertyAttribute::Kind attrs =
3625ffd83dbSDimitry Andric         props[0].PropD->getPropertyAttributesAsWritten();
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric #ifndef NDEBUG
3650b57cec5SDimitry Andric     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
3660b57cec5SDimitry Andric       assert(attrs == I->PropD->getPropertyAttributesAsWritten());
3670b57cec5SDimitry Andric #endif
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric     return attrs;
3700b57cec5SDimitry Andric   }
3710b57cec5SDimitry Andric };
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric } // anonymous namespace
3740b57cec5SDimitry Andric 
traverseObjCImplementation(ObjCImplementationContext & ImplCtx)3750b57cec5SDimitry Andric void PropertyRewriteTraverser::traverseObjCImplementation(
3760b57cec5SDimitry Andric                                            ObjCImplementationContext &ImplCtx) {
3770b57cec5SDimitry Andric   PropertiesRewriter(ImplCtx.getMigrationContext())
3780b57cec5SDimitry Andric                                   .doTransform(ImplCtx.getImplementationDecl());
3790b57cec5SDimitry Andric }
380