xref: /minix3/external/bsd/llvm/dist/clang/lib/ARCMigrate/TransProperties.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===--- TransProperties.cpp - Transformations to ARC mode ----------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // rewriteProperties:
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc // - Adds strong/weak/unsafe_unretained ownership specifier to properties that
13f4a2713aSLionel Sambuc //   are missing one.
14f4a2713aSLionel Sambuc // - Migrates properties from (retain) to (strong) and (assign) to
15f4a2713aSLionel Sambuc //   (unsafe_unretained/weak).
16f4a2713aSLionel Sambuc // - If a property is synthesized, adds the ownership specifier in the ivar
17f4a2713aSLionel Sambuc //   backing the property.
18f4a2713aSLionel Sambuc //
19f4a2713aSLionel Sambuc //  @interface Foo : NSObject {
20f4a2713aSLionel Sambuc //      NSObject *x;
21f4a2713aSLionel Sambuc //  }
22f4a2713aSLionel Sambuc //  @property (assign) id x;
23f4a2713aSLionel Sambuc //  @end
24f4a2713aSLionel Sambuc // ---->
25f4a2713aSLionel Sambuc //  @interface Foo : NSObject {
26f4a2713aSLionel Sambuc //      NSObject *__weak x;
27f4a2713aSLionel Sambuc //  }
28f4a2713aSLionel Sambuc //  @property (weak) id x;
29f4a2713aSLionel Sambuc //  @end
30f4a2713aSLionel Sambuc //
31f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
32f4a2713aSLionel Sambuc 
33f4a2713aSLionel Sambuc #include "Transforms.h"
34f4a2713aSLionel Sambuc #include "Internals.h"
35f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
36f4a2713aSLionel Sambuc #include "clang/Lex/Lexer.h"
37f4a2713aSLionel Sambuc #include "clang/Sema/SemaDiagnostic.h"
38f4a2713aSLionel Sambuc #include <map>
39f4a2713aSLionel Sambuc 
40f4a2713aSLionel Sambuc using namespace clang;
41f4a2713aSLionel Sambuc using namespace arcmt;
42f4a2713aSLionel Sambuc using namespace trans;
43f4a2713aSLionel Sambuc 
44f4a2713aSLionel Sambuc namespace {
45f4a2713aSLionel Sambuc 
46f4a2713aSLionel Sambuc class PropertiesRewriter {
47f4a2713aSLionel Sambuc   MigrationContext &MigrateCtx;
48f4a2713aSLionel Sambuc   MigrationPass &Pass;
49f4a2713aSLionel Sambuc   ObjCImplementationDecl *CurImplD;
50f4a2713aSLionel Sambuc 
51f4a2713aSLionel Sambuc   enum PropActionKind {
52f4a2713aSLionel Sambuc     PropAction_None,
53f4a2713aSLionel Sambuc     PropAction_RetainReplacedWithStrong,
54f4a2713aSLionel Sambuc     PropAction_AssignRemoved,
55f4a2713aSLionel Sambuc     PropAction_AssignRewritten,
56f4a2713aSLionel Sambuc     PropAction_MaybeAddWeakOrUnsafe
57f4a2713aSLionel Sambuc   };
58f4a2713aSLionel Sambuc 
59f4a2713aSLionel Sambuc   struct PropData {
60f4a2713aSLionel Sambuc     ObjCPropertyDecl *PropD;
61f4a2713aSLionel Sambuc     ObjCIvarDecl *IvarD;
62f4a2713aSLionel Sambuc     ObjCPropertyImplDecl *ImplD;
63f4a2713aSLionel Sambuc 
PropData__anon78783b500111::PropertiesRewriter::PropData64*0a6a1f1dSLionel Sambuc     PropData(ObjCPropertyDecl *propD)
65*0a6a1f1dSLionel Sambuc       : PropD(propD), IvarD(nullptr), ImplD(nullptr) {}
66f4a2713aSLionel Sambuc   };
67f4a2713aSLionel Sambuc 
68f4a2713aSLionel Sambuc   typedef SmallVector<PropData, 2> PropsTy;
69f4a2713aSLionel Sambuc   typedef std::map<unsigned, PropsTy> AtPropDeclsTy;
70f4a2713aSLionel Sambuc   AtPropDeclsTy AtProps;
71f4a2713aSLionel Sambuc   llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp;
72f4a2713aSLionel Sambuc 
73f4a2713aSLionel Sambuc public:
PropertiesRewriter(MigrationContext & MigrateCtx)74f4a2713aSLionel Sambuc   explicit PropertiesRewriter(MigrationContext &MigrateCtx)
75f4a2713aSLionel Sambuc     : MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
76f4a2713aSLionel Sambuc 
collectProperties(ObjCContainerDecl * D,AtPropDeclsTy & AtProps,AtPropDeclsTy * PrevAtProps=nullptr)77f4a2713aSLionel Sambuc   static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
78*0a6a1f1dSLionel Sambuc                                 AtPropDeclsTy *PrevAtProps = nullptr) {
79*0a6a1f1dSLionel Sambuc     for (auto *Prop : D->properties()) {
80*0a6a1f1dSLionel Sambuc       if (Prop->getAtLoc().isInvalid())
81f4a2713aSLionel Sambuc         continue;
82*0a6a1f1dSLionel Sambuc       unsigned RawLoc = Prop->getAtLoc().getRawEncoding();
83f4a2713aSLionel Sambuc       if (PrevAtProps)
84f4a2713aSLionel Sambuc         if (PrevAtProps->find(RawLoc) != PrevAtProps->end())
85f4a2713aSLionel Sambuc           continue;
86f4a2713aSLionel Sambuc       PropsTy &props = AtProps[RawLoc];
87*0a6a1f1dSLionel Sambuc       props.push_back(Prop);
88f4a2713aSLionel Sambuc     }
89f4a2713aSLionel Sambuc   }
90f4a2713aSLionel Sambuc 
doTransform(ObjCImplementationDecl * D)91f4a2713aSLionel Sambuc   void doTransform(ObjCImplementationDecl *D) {
92f4a2713aSLionel Sambuc     CurImplD = D;
93f4a2713aSLionel Sambuc     ObjCInterfaceDecl *iface = D->getClassInterface();
94f4a2713aSLionel Sambuc     if (!iface)
95f4a2713aSLionel Sambuc       return;
96f4a2713aSLionel Sambuc 
97f4a2713aSLionel Sambuc     collectProperties(iface, AtProps);
98f4a2713aSLionel Sambuc 
99f4a2713aSLionel Sambuc     typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
100f4a2713aSLionel Sambuc         prop_impl_iterator;
101f4a2713aSLionel Sambuc     for (prop_impl_iterator
102f4a2713aSLionel Sambuc            I = prop_impl_iterator(D->decls_begin()),
103f4a2713aSLionel Sambuc            E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
104f4a2713aSLionel Sambuc       ObjCPropertyImplDecl *implD = *I;
105f4a2713aSLionel Sambuc       if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
106f4a2713aSLionel Sambuc         continue;
107f4a2713aSLionel Sambuc       ObjCPropertyDecl *propD = implD->getPropertyDecl();
108f4a2713aSLionel Sambuc       if (!propD || propD->isInvalidDecl())
109f4a2713aSLionel Sambuc         continue;
110f4a2713aSLionel Sambuc       ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
111f4a2713aSLionel Sambuc       if (!ivarD || ivarD->isInvalidDecl())
112f4a2713aSLionel Sambuc         continue;
113f4a2713aSLionel Sambuc       unsigned rawAtLoc = propD->getAtLoc().getRawEncoding();
114f4a2713aSLionel Sambuc       AtPropDeclsTy::iterator findAtLoc = AtProps.find(rawAtLoc);
115f4a2713aSLionel Sambuc       if (findAtLoc == AtProps.end())
116f4a2713aSLionel Sambuc         continue;
117f4a2713aSLionel Sambuc 
118f4a2713aSLionel Sambuc       PropsTy &props = findAtLoc->second;
119f4a2713aSLionel Sambuc       for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
120f4a2713aSLionel Sambuc         if (I->PropD == propD) {
121f4a2713aSLionel Sambuc           I->IvarD = ivarD;
122f4a2713aSLionel Sambuc           I->ImplD = implD;
123f4a2713aSLionel Sambuc           break;
124f4a2713aSLionel Sambuc         }
125f4a2713aSLionel Sambuc       }
126f4a2713aSLionel Sambuc     }
127f4a2713aSLionel Sambuc 
128f4a2713aSLionel Sambuc     for (AtPropDeclsTy::iterator
129f4a2713aSLionel Sambuc            I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
130f4a2713aSLionel Sambuc       SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
131f4a2713aSLionel Sambuc       PropsTy &props = I->second;
132f4a2713aSLionel Sambuc       if (!getPropertyType(props)->isObjCRetainableType())
133f4a2713aSLionel Sambuc         continue;
134f4a2713aSLionel Sambuc       if (hasIvarWithExplicitARCOwnership(props))
135f4a2713aSLionel Sambuc         continue;
136f4a2713aSLionel Sambuc 
137f4a2713aSLionel Sambuc       Transaction Trans(Pass.TA);
138f4a2713aSLionel Sambuc       rewriteProperty(props, atLoc);
139f4a2713aSLionel Sambuc     }
140f4a2713aSLionel Sambuc 
141f4a2713aSLionel Sambuc     AtPropDeclsTy AtExtProps;
142f4a2713aSLionel Sambuc     // Look through extensions.
143*0a6a1f1dSLionel Sambuc     for (auto *Ext : iface->visible_extensions())
144*0a6a1f1dSLionel Sambuc       collectProperties(Ext, AtExtProps, &AtProps);
145f4a2713aSLionel Sambuc 
146f4a2713aSLionel Sambuc     for (AtPropDeclsTy::iterator
147f4a2713aSLionel Sambuc            I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
148f4a2713aSLionel Sambuc       SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
149f4a2713aSLionel Sambuc       PropsTy &props = I->second;
150f4a2713aSLionel Sambuc       Transaction Trans(Pass.TA);
151f4a2713aSLionel Sambuc       doActionForExtensionProp(props, atLoc);
152f4a2713aSLionel Sambuc     }
153f4a2713aSLionel Sambuc   }
154f4a2713aSLionel Sambuc 
155f4a2713aSLionel Sambuc private:
doPropAction(PropActionKind kind,PropsTy & props,SourceLocation atLoc,bool markAction=true)156f4a2713aSLionel Sambuc   void doPropAction(PropActionKind kind,
157f4a2713aSLionel Sambuc                     PropsTy &props, SourceLocation atLoc,
158f4a2713aSLionel Sambuc                     bool markAction = true) {
159f4a2713aSLionel Sambuc     if (markAction)
160f4a2713aSLionel Sambuc       for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
161f4a2713aSLionel Sambuc         ActionOnProp[I->PropD->getIdentifier()] = kind;
162f4a2713aSLionel Sambuc 
163f4a2713aSLionel Sambuc     switch (kind) {
164f4a2713aSLionel Sambuc     case PropAction_None:
165f4a2713aSLionel Sambuc       return;
166f4a2713aSLionel Sambuc     case PropAction_RetainReplacedWithStrong: {
167f4a2713aSLionel Sambuc       StringRef toAttr = "strong";
168f4a2713aSLionel Sambuc       MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc);
169f4a2713aSLionel Sambuc       return;
170f4a2713aSLionel Sambuc     }
171f4a2713aSLionel Sambuc     case PropAction_AssignRemoved:
172f4a2713aSLionel Sambuc       return removeAssignForDefaultStrong(props, atLoc);
173f4a2713aSLionel Sambuc     case PropAction_AssignRewritten:
174f4a2713aSLionel Sambuc       return rewriteAssign(props, atLoc);
175f4a2713aSLionel Sambuc     case PropAction_MaybeAddWeakOrUnsafe:
176f4a2713aSLionel Sambuc       return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
177f4a2713aSLionel Sambuc     }
178f4a2713aSLionel Sambuc   }
179f4a2713aSLionel Sambuc 
doActionForExtensionProp(PropsTy & props,SourceLocation atLoc)180f4a2713aSLionel Sambuc   void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
181f4a2713aSLionel Sambuc     llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
182f4a2713aSLionel Sambuc     I = ActionOnProp.find(props[0].PropD->getIdentifier());
183f4a2713aSLionel Sambuc     if (I == ActionOnProp.end())
184f4a2713aSLionel Sambuc       return;
185f4a2713aSLionel Sambuc 
186f4a2713aSLionel Sambuc     doPropAction(I->second, props, atLoc, false);
187f4a2713aSLionel Sambuc   }
188f4a2713aSLionel Sambuc 
rewriteProperty(PropsTy & props,SourceLocation atLoc)189f4a2713aSLionel Sambuc   void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
190f4a2713aSLionel Sambuc     ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
191f4a2713aSLionel Sambuc 
192f4a2713aSLionel Sambuc     if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
193f4a2713aSLionel Sambuc                      ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
194f4a2713aSLionel Sambuc                      ObjCPropertyDecl::OBJC_PR_strong |
195f4a2713aSLionel Sambuc                      ObjCPropertyDecl::OBJC_PR_weak))
196f4a2713aSLionel Sambuc       return;
197f4a2713aSLionel Sambuc 
198f4a2713aSLionel Sambuc     if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
199f4a2713aSLionel Sambuc       // strong is the default.
200f4a2713aSLionel Sambuc       return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc);
201f4a2713aSLionel Sambuc     }
202f4a2713aSLionel Sambuc 
203f4a2713aSLionel Sambuc     bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
204f4a2713aSLionel Sambuc 
205f4a2713aSLionel Sambuc     if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
206f4a2713aSLionel Sambuc       if (HasIvarAssignedAPlusOneObject)
207f4a2713aSLionel Sambuc         return doPropAction(PropAction_AssignRemoved, props, atLoc);
208f4a2713aSLionel Sambuc       return doPropAction(PropAction_AssignRewritten, props, atLoc);
209f4a2713aSLionel Sambuc     }
210f4a2713aSLionel Sambuc 
211f4a2713aSLionel Sambuc     if (HasIvarAssignedAPlusOneObject ||
212f4a2713aSLionel Sambuc         (Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
213f4a2713aSLionel Sambuc       return; // 'strong' by default.
214f4a2713aSLionel Sambuc 
215f4a2713aSLionel Sambuc     return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
216f4a2713aSLionel Sambuc   }
217f4a2713aSLionel Sambuc 
removeAssignForDefaultStrong(PropsTy & props,SourceLocation atLoc) const218f4a2713aSLionel Sambuc   void removeAssignForDefaultStrong(PropsTy &props,
219f4a2713aSLionel Sambuc                                     SourceLocation atLoc) const {
220f4a2713aSLionel Sambuc     removeAttribute("retain", atLoc);
221f4a2713aSLionel Sambuc     if (!removeAttribute("assign", atLoc))
222f4a2713aSLionel Sambuc       return;
223f4a2713aSLionel Sambuc 
224f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
225f4a2713aSLionel Sambuc       if (I->ImplD)
226f4a2713aSLionel Sambuc         Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
227f4a2713aSLionel Sambuc                                 diag::err_arc_assign_property_ownership,
228f4a2713aSLionel Sambuc                                 diag::err_arc_inconsistent_property_ownership,
229f4a2713aSLionel Sambuc                                 I->IvarD->getLocation());
230f4a2713aSLionel Sambuc     }
231f4a2713aSLionel Sambuc   }
232f4a2713aSLionel Sambuc 
rewriteAssign(PropsTy & props,SourceLocation atLoc) const233f4a2713aSLionel Sambuc   void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
234f4a2713aSLionel Sambuc     bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
235f4a2713aSLionel Sambuc                                   /*AllowOnUnknownClass=*/Pass.isGCMigration());
236f4a2713aSLionel Sambuc     const char *toWhich =
237f4a2713aSLionel Sambuc       (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" :
238f4a2713aSLionel Sambuc       (canUseWeak ? "weak" : "unsafe_unretained");
239f4a2713aSLionel Sambuc 
240f4a2713aSLionel Sambuc     bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc);
241f4a2713aSLionel Sambuc     if (!rewroteAttr)
242f4a2713aSLionel Sambuc       canUseWeak = false;
243f4a2713aSLionel Sambuc 
244f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
245f4a2713aSLionel Sambuc       if (isUserDeclared(I->IvarD)) {
246f4a2713aSLionel Sambuc         if (I->IvarD &&
247f4a2713aSLionel Sambuc             I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) {
248f4a2713aSLionel Sambuc           const char *toWhich =
249f4a2713aSLionel Sambuc             (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " :
250f4a2713aSLionel Sambuc               (canUseWeak ? "__weak " : "__unsafe_unretained ");
251f4a2713aSLionel Sambuc           Pass.TA.insert(I->IvarD->getLocation(), toWhich);
252f4a2713aSLionel Sambuc         }
253f4a2713aSLionel Sambuc       }
254f4a2713aSLionel Sambuc       if (I->ImplD)
255f4a2713aSLionel Sambuc         Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
256f4a2713aSLionel Sambuc                                 diag::err_arc_assign_property_ownership,
257f4a2713aSLionel Sambuc                                 diag::err_arc_inconsistent_property_ownership,
258f4a2713aSLionel Sambuc                                 I->IvarD->getLocation());
259f4a2713aSLionel Sambuc     }
260f4a2713aSLionel Sambuc   }
261f4a2713aSLionel Sambuc 
maybeAddWeakOrUnsafeUnretainedAttr(PropsTy & props,SourceLocation atLoc) const262f4a2713aSLionel Sambuc   void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
263f4a2713aSLionel Sambuc                                           SourceLocation atLoc) const {
264f4a2713aSLionel Sambuc     bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
265f4a2713aSLionel Sambuc                                   /*AllowOnUnknownClass=*/Pass.isGCMigration());
266f4a2713aSLionel Sambuc 
267f4a2713aSLionel Sambuc     bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
268f4a2713aSLionel Sambuc                                   atLoc);
269f4a2713aSLionel Sambuc     if (!addedAttr)
270f4a2713aSLionel Sambuc       canUseWeak = false;
271f4a2713aSLionel Sambuc 
272f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
273f4a2713aSLionel Sambuc       if (isUserDeclared(I->IvarD)) {
274f4a2713aSLionel Sambuc         if (I->IvarD &&
275f4a2713aSLionel Sambuc             I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
276f4a2713aSLionel Sambuc           Pass.TA.insert(I->IvarD->getLocation(),
277f4a2713aSLionel Sambuc                          canUseWeak ? "__weak " : "__unsafe_unretained ");
278f4a2713aSLionel Sambuc       }
279f4a2713aSLionel Sambuc       if (I->ImplD) {
280f4a2713aSLionel Sambuc         Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
281f4a2713aSLionel Sambuc                                 diag::err_arc_assign_property_ownership,
282f4a2713aSLionel Sambuc                                 diag::err_arc_inconsistent_property_ownership,
283f4a2713aSLionel Sambuc                                 I->IvarD->getLocation());
284f4a2713aSLionel Sambuc         Pass.TA.clearDiagnostic(
285f4a2713aSLionel Sambuc                            diag::err_arc_objc_property_default_assign_on_object,
286f4a2713aSLionel Sambuc                            I->ImplD->getLocation());
287f4a2713aSLionel Sambuc       }
288f4a2713aSLionel Sambuc     }
289f4a2713aSLionel Sambuc   }
290f4a2713aSLionel Sambuc 
removeAttribute(StringRef fromAttr,SourceLocation atLoc) const291f4a2713aSLionel Sambuc   bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
292f4a2713aSLionel Sambuc     return MigrateCtx.removePropertyAttribute(fromAttr, atLoc);
293f4a2713aSLionel Sambuc   }
294f4a2713aSLionel Sambuc 
rewriteAttribute(StringRef fromAttr,StringRef toAttr,SourceLocation atLoc) const295f4a2713aSLionel Sambuc   bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
296f4a2713aSLionel Sambuc                         SourceLocation atLoc) const {
297f4a2713aSLionel Sambuc     return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
298f4a2713aSLionel Sambuc   }
299f4a2713aSLionel Sambuc 
addAttribute(StringRef attr,SourceLocation atLoc) const300f4a2713aSLionel Sambuc   bool addAttribute(StringRef attr, SourceLocation atLoc) const {
301f4a2713aSLionel Sambuc     return MigrateCtx.addPropertyAttribute(attr, atLoc);
302f4a2713aSLionel Sambuc   }
303f4a2713aSLionel Sambuc 
304f4a2713aSLionel Sambuc   class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
305f4a2713aSLionel Sambuc     ObjCIvarDecl *Ivar;
306f4a2713aSLionel Sambuc   public:
PlusOneAssign(ObjCIvarDecl * D)307f4a2713aSLionel Sambuc     PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
308f4a2713aSLionel Sambuc 
VisitBinAssign(BinaryOperator * E)309f4a2713aSLionel Sambuc     bool VisitBinAssign(BinaryOperator *E) {
310f4a2713aSLionel Sambuc       Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
311f4a2713aSLionel Sambuc       if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
312f4a2713aSLionel Sambuc         if (RE->getDecl() != Ivar)
313f4a2713aSLionel Sambuc           return true;
314f4a2713aSLionel Sambuc 
315f4a2713aSLionel Sambuc         if (isPlusOneAssign(E))
316f4a2713aSLionel Sambuc           return false;
317f4a2713aSLionel Sambuc       }
318f4a2713aSLionel Sambuc 
319f4a2713aSLionel Sambuc       return true;
320f4a2713aSLionel Sambuc     }
321f4a2713aSLionel Sambuc   };
322f4a2713aSLionel Sambuc 
hasIvarAssignedAPlusOneObject(PropsTy & props) const323f4a2713aSLionel Sambuc   bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
324f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
325f4a2713aSLionel Sambuc       PlusOneAssign oneAssign(I->IvarD);
326f4a2713aSLionel Sambuc       bool notFound = oneAssign.TraverseDecl(CurImplD);
327f4a2713aSLionel Sambuc       if (!notFound)
328f4a2713aSLionel Sambuc         return true;
329f4a2713aSLionel Sambuc     }
330f4a2713aSLionel Sambuc 
331f4a2713aSLionel Sambuc     return false;
332f4a2713aSLionel Sambuc   }
333f4a2713aSLionel Sambuc 
hasIvarWithExplicitARCOwnership(PropsTy & props) const334f4a2713aSLionel Sambuc   bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
335f4a2713aSLionel Sambuc     if (Pass.isGCMigration())
336f4a2713aSLionel Sambuc       return false;
337f4a2713aSLionel Sambuc 
338f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
339f4a2713aSLionel Sambuc       if (isUserDeclared(I->IvarD)) {
340f4a2713aSLionel Sambuc         if (isa<AttributedType>(I->IvarD->getType()))
341f4a2713aSLionel Sambuc           return true;
342f4a2713aSLionel Sambuc         if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
343f4a2713aSLionel Sambuc               != Qualifiers::OCL_Strong)
344f4a2713aSLionel Sambuc           return true;
345f4a2713aSLionel Sambuc       }
346f4a2713aSLionel Sambuc     }
347f4a2713aSLionel Sambuc 
348f4a2713aSLionel Sambuc     return false;
349f4a2713aSLionel Sambuc   }
350f4a2713aSLionel Sambuc 
351f4a2713aSLionel Sambuc   // \brief Returns true if all declarations in the @property have GC __weak.
hasGCWeak(PropsTy & props,SourceLocation atLoc) const352f4a2713aSLionel Sambuc   bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
353f4a2713aSLionel Sambuc     if (!Pass.isGCMigration())
354f4a2713aSLionel Sambuc       return false;
355f4a2713aSLionel Sambuc     if (props.empty())
356f4a2713aSLionel Sambuc       return false;
357f4a2713aSLionel Sambuc     return MigrateCtx.AtPropsWeak.count(atLoc.getRawEncoding());
358f4a2713aSLionel Sambuc   }
359f4a2713aSLionel Sambuc 
isUserDeclared(ObjCIvarDecl * ivarD) const360f4a2713aSLionel Sambuc   bool isUserDeclared(ObjCIvarDecl *ivarD) const {
361f4a2713aSLionel Sambuc     return ivarD && !ivarD->getSynthesize();
362f4a2713aSLionel Sambuc   }
363f4a2713aSLionel Sambuc 
getPropertyType(PropsTy & props) const364f4a2713aSLionel Sambuc   QualType getPropertyType(PropsTy &props) const {
365f4a2713aSLionel Sambuc     assert(!props.empty());
366f4a2713aSLionel Sambuc     QualType ty = props[0].PropD->getType().getUnqualifiedType();
367f4a2713aSLionel Sambuc 
368f4a2713aSLionel Sambuc #ifndef NDEBUG
369f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
370f4a2713aSLionel Sambuc       assert(ty == I->PropD->getType().getUnqualifiedType());
371f4a2713aSLionel Sambuc #endif
372f4a2713aSLionel Sambuc 
373f4a2713aSLionel Sambuc     return ty;
374f4a2713aSLionel Sambuc   }
375f4a2713aSLionel Sambuc 
376f4a2713aSLionel Sambuc   ObjCPropertyDecl::PropertyAttributeKind
getPropertyAttrs(PropsTy & props) const377f4a2713aSLionel Sambuc   getPropertyAttrs(PropsTy &props) const {
378f4a2713aSLionel Sambuc     assert(!props.empty());
379f4a2713aSLionel Sambuc     ObjCPropertyDecl::PropertyAttributeKind
380f4a2713aSLionel Sambuc       attrs = props[0].PropD->getPropertyAttributesAsWritten();
381f4a2713aSLionel Sambuc 
382f4a2713aSLionel Sambuc #ifndef NDEBUG
383f4a2713aSLionel Sambuc     for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
384f4a2713aSLionel Sambuc       assert(attrs == I->PropD->getPropertyAttributesAsWritten());
385f4a2713aSLionel Sambuc #endif
386f4a2713aSLionel Sambuc 
387f4a2713aSLionel Sambuc     return attrs;
388f4a2713aSLionel Sambuc   }
389f4a2713aSLionel Sambuc };
390f4a2713aSLionel Sambuc 
391f4a2713aSLionel Sambuc } // anonymous namespace
392f4a2713aSLionel Sambuc 
traverseObjCImplementation(ObjCImplementationContext & ImplCtx)393f4a2713aSLionel Sambuc void PropertyRewriteTraverser::traverseObjCImplementation(
394f4a2713aSLionel Sambuc                                            ObjCImplementationContext &ImplCtx) {
395f4a2713aSLionel Sambuc   PropertiesRewriter(ImplCtx.getMigrationContext())
396f4a2713aSLionel Sambuc                                   .doTransform(ImplCtx.getImplementationDecl());
397f4a2713aSLionel Sambuc }
398