1*67e74705SXin Li //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "Transforms.h"
11*67e74705SXin Li #include "Internals.h"
12*67e74705SXin Li #include "clang/AST/ASTContext.h"
13*67e74705SXin Li #include "clang/Basic/SourceManager.h"
14*67e74705SXin Li #include "clang/Lex/Lexer.h"
15*67e74705SXin Li #include "clang/Sema/SemaDiagnostic.h"
16*67e74705SXin Li #include "llvm/ADT/SmallString.h"
17*67e74705SXin Li #include "llvm/ADT/TinyPtrVector.h"
18*67e74705SXin Li #include "llvm/Support/SaveAndRestore.h"
19*67e74705SXin Li
20*67e74705SXin Li using namespace clang;
21*67e74705SXin Li using namespace arcmt;
22*67e74705SXin Li using namespace trans;
23*67e74705SXin Li
24*67e74705SXin Li namespace {
25*67e74705SXin Li
26*67e74705SXin Li /// \brief Collects all the places where GC attributes __strong/__weak occur.
27*67e74705SXin Li class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
28*67e74705SXin Li MigrationContext &MigrateCtx;
29*67e74705SXin Li bool FullyMigratable;
30*67e74705SXin Li std::vector<ObjCPropertyDecl *> &AllProps;
31*67e74705SXin Li
32*67e74705SXin Li typedef RecursiveASTVisitor<GCAttrsCollector> base;
33*67e74705SXin Li public:
GCAttrsCollector(MigrationContext & ctx,std::vector<ObjCPropertyDecl * > & AllProps)34*67e74705SXin Li GCAttrsCollector(MigrationContext &ctx,
35*67e74705SXin Li std::vector<ObjCPropertyDecl *> &AllProps)
36*67e74705SXin Li : MigrateCtx(ctx), FullyMigratable(false),
37*67e74705SXin Li AllProps(AllProps) { }
38*67e74705SXin Li
shouldWalkTypesOfTypeLocs() const39*67e74705SXin Li bool shouldWalkTypesOfTypeLocs() const { return false; }
40*67e74705SXin Li
VisitAttributedTypeLoc(AttributedTypeLoc TL)41*67e74705SXin Li bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
42*67e74705SXin Li handleAttr(TL);
43*67e74705SXin Li return true;
44*67e74705SXin Li }
45*67e74705SXin Li
TraverseDecl(Decl * D)46*67e74705SXin Li bool TraverseDecl(Decl *D) {
47*67e74705SXin Li if (!D || D->isImplicit())
48*67e74705SXin Li return true;
49*67e74705SXin Li
50*67e74705SXin Li SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
51*67e74705SXin Li
52*67e74705SXin Li if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
53*67e74705SXin Li lookForAttribute(PropD, PropD->getTypeSourceInfo());
54*67e74705SXin Li AllProps.push_back(PropD);
55*67e74705SXin Li } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
56*67e74705SXin Li lookForAttribute(DD, DD->getTypeSourceInfo());
57*67e74705SXin Li }
58*67e74705SXin Li return base::TraverseDecl(D);
59*67e74705SXin Li }
60*67e74705SXin Li
lookForAttribute(Decl * D,TypeSourceInfo * TInfo)61*67e74705SXin Li void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
62*67e74705SXin Li if (!TInfo)
63*67e74705SXin Li return;
64*67e74705SXin Li TypeLoc TL = TInfo->getTypeLoc();
65*67e74705SXin Li while (TL) {
66*67e74705SXin Li if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
67*67e74705SXin Li TL = QL.getUnqualifiedLoc();
68*67e74705SXin Li } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
69*67e74705SXin Li if (handleAttr(Attr, D))
70*67e74705SXin Li break;
71*67e74705SXin Li TL = Attr.getModifiedLoc();
72*67e74705SXin Li } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
73*67e74705SXin Li TL = Arr.getElementLoc();
74*67e74705SXin Li } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
75*67e74705SXin Li TL = PT.getPointeeLoc();
76*67e74705SXin Li } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
77*67e74705SXin Li TL = RT.getPointeeLoc();
78*67e74705SXin Li else
79*67e74705SXin Li break;
80*67e74705SXin Li }
81*67e74705SXin Li }
82*67e74705SXin Li
handleAttr(AttributedTypeLoc TL,Decl * D=nullptr)83*67e74705SXin Li bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
84*67e74705SXin Li if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
85*67e74705SXin Li return false;
86*67e74705SXin Li
87*67e74705SXin Li SourceLocation Loc = TL.getAttrNameLoc();
88*67e74705SXin Li unsigned RawLoc = Loc.getRawEncoding();
89*67e74705SXin Li if (MigrateCtx.AttrSet.count(RawLoc))
90*67e74705SXin Li return true;
91*67e74705SXin Li
92*67e74705SXin Li ASTContext &Ctx = MigrateCtx.Pass.Ctx;
93*67e74705SXin Li SourceManager &SM = Ctx.getSourceManager();
94*67e74705SXin Li if (Loc.isMacroID())
95*67e74705SXin Li Loc = SM.getImmediateExpansionRange(Loc).first;
96*67e74705SXin Li SmallString<32> Buf;
97*67e74705SXin Li bool Invalid = false;
98*67e74705SXin Li StringRef Spell = Lexer::getSpelling(
99*67e74705SXin Li SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
100*67e74705SXin Li Buf, SM, Ctx.getLangOpts(), &Invalid);
101*67e74705SXin Li if (Invalid)
102*67e74705SXin Li return false;
103*67e74705SXin Li MigrationContext::GCAttrOccurrence::AttrKind Kind;
104*67e74705SXin Li if (Spell == "strong")
105*67e74705SXin Li Kind = MigrationContext::GCAttrOccurrence::Strong;
106*67e74705SXin Li else if (Spell == "weak")
107*67e74705SXin Li Kind = MigrationContext::GCAttrOccurrence::Weak;
108*67e74705SXin Li else
109*67e74705SXin Li return false;
110*67e74705SXin Li
111*67e74705SXin Li MigrateCtx.AttrSet.insert(RawLoc);
112*67e74705SXin Li MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
113*67e74705SXin Li MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
114*67e74705SXin Li
115*67e74705SXin Li Attr.Kind = Kind;
116*67e74705SXin Li Attr.Loc = Loc;
117*67e74705SXin Li Attr.ModifiedType = TL.getModifiedLoc().getType();
118*67e74705SXin Li Attr.Dcl = D;
119*67e74705SXin Li Attr.FullyMigratable = FullyMigratable;
120*67e74705SXin Li return true;
121*67e74705SXin Li }
122*67e74705SXin Li
isMigratable(Decl * D)123*67e74705SXin Li bool isMigratable(Decl *D) {
124*67e74705SXin Li if (isa<TranslationUnitDecl>(D))
125*67e74705SXin Li return false;
126*67e74705SXin Li
127*67e74705SXin Li if (isInMainFile(D))
128*67e74705SXin Li return true;
129*67e74705SXin Li
130*67e74705SXin Li if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
131*67e74705SXin Li return FD->hasBody();
132*67e74705SXin Li
133*67e74705SXin Li if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
134*67e74705SXin Li return hasObjCImpl(ContD);
135*67e74705SXin Li
136*67e74705SXin Li if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
137*67e74705SXin Li for (const auto *MI : RD->methods()) {
138*67e74705SXin Li if (MI->isOutOfLine())
139*67e74705SXin Li return true;
140*67e74705SXin Li }
141*67e74705SXin Li return false;
142*67e74705SXin Li }
143*67e74705SXin Li
144*67e74705SXin Li return isMigratable(cast<Decl>(D->getDeclContext()));
145*67e74705SXin Li }
146*67e74705SXin Li
hasObjCImpl(Decl * D)147*67e74705SXin Li static bool hasObjCImpl(Decl *D) {
148*67e74705SXin Li if (!D)
149*67e74705SXin Li return false;
150*67e74705SXin Li if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
151*67e74705SXin Li if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
152*67e74705SXin Li return ID->getImplementation() != nullptr;
153*67e74705SXin Li if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
154*67e74705SXin Li return CD->getImplementation() != nullptr;
155*67e74705SXin Li return isa<ObjCImplDecl>(ContD);
156*67e74705SXin Li }
157*67e74705SXin Li return false;
158*67e74705SXin Li }
159*67e74705SXin Li
isInMainFile(Decl * D)160*67e74705SXin Li bool isInMainFile(Decl *D) {
161*67e74705SXin Li if (!D)
162*67e74705SXin Li return false;
163*67e74705SXin Li
164*67e74705SXin Li for (auto I : D->redecls())
165*67e74705SXin Li if (!isInMainFile(I->getLocation()))
166*67e74705SXin Li return false;
167*67e74705SXin Li
168*67e74705SXin Li return true;
169*67e74705SXin Li }
170*67e74705SXin Li
isInMainFile(SourceLocation Loc)171*67e74705SXin Li bool isInMainFile(SourceLocation Loc) {
172*67e74705SXin Li if (Loc.isInvalid())
173*67e74705SXin Li return false;
174*67e74705SXin Li
175*67e74705SXin Li SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
176*67e74705SXin Li return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
177*67e74705SXin Li }
178*67e74705SXin Li };
179*67e74705SXin Li
180*67e74705SXin Li } // anonymous namespace
181*67e74705SXin Li
errorForGCAttrsOnNonObjC(MigrationContext & MigrateCtx)182*67e74705SXin Li static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
183*67e74705SXin Li TransformActions &TA = MigrateCtx.Pass.TA;
184*67e74705SXin Li
185*67e74705SXin Li for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
186*67e74705SXin Li MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
187*67e74705SXin Li if (Attr.FullyMigratable && Attr.Dcl) {
188*67e74705SXin Li if (Attr.ModifiedType.isNull())
189*67e74705SXin Li continue;
190*67e74705SXin Li if (!Attr.ModifiedType->isObjCRetainableType()) {
191*67e74705SXin Li TA.reportError("GC managed memory will become unmanaged in ARC",
192*67e74705SXin Li Attr.Loc);
193*67e74705SXin Li }
194*67e74705SXin Li }
195*67e74705SXin Li }
196*67e74705SXin Li }
197*67e74705SXin Li
checkWeakGCAttrs(MigrationContext & MigrateCtx)198*67e74705SXin Li static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
199*67e74705SXin Li TransformActions &TA = MigrateCtx.Pass.TA;
200*67e74705SXin Li
201*67e74705SXin Li for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
202*67e74705SXin Li MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
203*67e74705SXin Li if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
204*67e74705SXin Li if (Attr.ModifiedType.isNull() ||
205*67e74705SXin Li !Attr.ModifiedType->isObjCRetainableType())
206*67e74705SXin Li continue;
207*67e74705SXin Li if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
208*67e74705SXin Li /*AllowOnUnknownClass=*/true)) {
209*67e74705SXin Li Transaction Trans(TA);
210*67e74705SXin Li if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
211*67e74705SXin Li TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
212*67e74705SXin Li TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
213*67e74705SXin Li diag::err_arc_unsupported_weak_class,
214*67e74705SXin Li Attr.Loc);
215*67e74705SXin Li }
216*67e74705SXin Li }
217*67e74705SXin Li }
218*67e74705SXin Li }
219*67e74705SXin Li
220*67e74705SXin Li typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
221*67e74705SXin Li
checkAllAtProps(MigrationContext & MigrateCtx,SourceLocation AtLoc,IndivPropsTy & IndProps)222*67e74705SXin Li static void checkAllAtProps(MigrationContext &MigrateCtx,
223*67e74705SXin Li SourceLocation AtLoc,
224*67e74705SXin Li IndivPropsTy &IndProps) {
225*67e74705SXin Li if (IndProps.empty())
226*67e74705SXin Li return;
227*67e74705SXin Li
228*67e74705SXin Li for (IndivPropsTy::iterator
229*67e74705SXin Li PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
230*67e74705SXin Li QualType T = (*PI)->getType();
231*67e74705SXin Li if (T.isNull() || !T->isObjCRetainableType())
232*67e74705SXin Li return;
233*67e74705SXin Li }
234*67e74705SXin Li
235*67e74705SXin Li SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
236*67e74705SXin Li bool hasWeak = false, hasStrong = false;
237*67e74705SXin Li ObjCPropertyDecl::PropertyAttributeKind
238*67e74705SXin Li Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
239*67e74705SXin Li for (IndivPropsTy::iterator
240*67e74705SXin Li PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
241*67e74705SXin Li ObjCPropertyDecl *PD = *PI;
242*67e74705SXin Li Attrs = PD->getPropertyAttributesAsWritten();
243*67e74705SXin Li TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
244*67e74705SXin Li if (!TInfo)
245*67e74705SXin Li return;
246*67e74705SXin Li TypeLoc TL = TInfo->getTypeLoc();
247*67e74705SXin Li if (AttributedTypeLoc ATL =
248*67e74705SXin Li TL.getAs<AttributedTypeLoc>()) {
249*67e74705SXin Li ATLs.push_back(std::make_pair(ATL, PD));
250*67e74705SXin Li if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
251*67e74705SXin Li hasWeak = true;
252*67e74705SXin Li } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
253*67e74705SXin Li hasStrong = true;
254*67e74705SXin Li else
255*67e74705SXin Li return;
256*67e74705SXin Li }
257*67e74705SXin Li }
258*67e74705SXin Li if (ATLs.empty())
259*67e74705SXin Li return;
260*67e74705SXin Li if (hasWeak && hasStrong)
261*67e74705SXin Li return;
262*67e74705SXin Li
263*67e74705SXin Li TransformActions &TA = MigrateCtx.Pass.TA;
264*67e74705SXin Li Transaction Trans(TA);
265*67e74705SXin Li
266*67e74705SXin Li if (GCAttrsCollector::hasObjCImpl(
267*67e74705SXin Li cast<Decl>(IndProps.front()->getDeclContext()))) {
268*67e74705SXin Li if (hasWeak)
269*67e74705SXin Li MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
270*67e74705SXin Li
271*67e74705SXin Li } else {
272*67e74705SXin Li StringRef toAttr = "strong";
273*67e74705SXin Li if (hasWeak) {
274*67e74705SXin Li if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
275*67e74705SXin Li /*AllowOnUnkwownClass=*/true))
276*67e74705SXin Li toAttr = "weak";
277*67e74705SXin Li else
278*67e74705SXin Li toAttr = "unsafe_unretained";
279*67e74705SXin Li }
280*67e74705SXin Li if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
281*67e74705SXin Li MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
282*67e74705SXin Li else
283*67e74705SXin Li MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
284*67e74705SXin Li }
285*67e74705SXin Li
286*67e74705SXin Li for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
287*67e74705SXin Li SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
288*67e74705SXin Li if (Loc.isMacroID())
289*67e74705SXin Li Loc = MigrateCtx.Pass.Ctx.getSourceManager()
290*67e74705SXin Li .getImmediateExpansionRange(Loc).first;
291*67e74705SXin Li TA.remove(Loc);
292*67e74705SXin Li TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
293*67e74705SXin Li TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
294*67e74705SXin Li ATLs[i].second->getLocation());
295*67e74705SXin Li MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
296*67e74705SXin Li }
297*67e74705SXin Li }
298*67e74705SXin Li
checkAllProps(MigrationContext & MigrateCtx,std::vector<ObjCPropertyDecl * > & AllProps)299*67e74705SXin Li static void checkAllProps(MigrationContext &MigrateCtx,
300*67e74705SXin Li std::vector<ObjCPropertyDecl *> &AllProps) {
301*67e74705SXin Li typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
302*67e74705SXin Li llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
303*67e74705SXin Li
304*67e74705SXin Li for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
305*67e74705SXin Li ObjCPropertyDecl *PD = AllProps[i];
306*67e74705SXin Li if (PD->getPropertyAttributesAsWritten() &
307*67e74705SXin Li (ObjCPropertyDecl::OBJC_PR_assign |
308*67e74705SXin Li ObjCPropertyDecl::OBJC_PR_readonly)) {
309*67e74705SXin Li SourceLocation AtLoc = PD->getAtLoc();
310*67e74705SXin Li if (AtLoc.isInvalid())
311*67e74705SXin Li continue;
312*67e74705SXin Li unsigned RawAt = AtLoc.getRawEncoding();
313*67e74705SXin Li AtProps[RawAt].push_back(PD);
314*67e74705SXin Li }
315*67e74705SXin Li }
316*67e74705SXin Li
317*67e74705SXin Li for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
318*67e74705SXin Li I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
319*67e74705SXin Li SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
320*67e74705SXin Li IndivPropsTy &IndProps = I->second;
321*67e74705SXin Li checkAllAtProps(MigrateCtx, AtLoc, IndProps);
322*67e74705SXin Li }
323*67e74705SXin Li }
324*67e74705SXin Li
traverseTU(MigrationContext & MigrateCtx)325*67e74705SXin Li void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
326*67e74705SXin Li std::vector<ObjCPropertyDecl *> AllProps;
327*67e74705SXin Li GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
328*67e74705SXin Li MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
329*67e74705SXin Li
330*67e74705SXin Li errorForGCAttrsOnNonObjC(MigrateCtx);
331*67e74705SXin Li checkAllProps(MigrateCtx, AllProps);
332*67e74705SXin Li checkWeakGCAttrs(MigrateCtx);
333*67e74705SXin Li }
334*67e74705SXin Li
dumpGCAttrs()335*67e74705SXin Li void MigrationContext::dumpGCAttrs() {
336*67e74705SXin Li llvm::errs() << "\n################\n";
337*67e74705SXin Li for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
338*67e74705SXin Li GCAttrOccurrence &Attr = GCAttrs[i];
339*67e74705SXin Li llvm::errs() << "KIND: "
340*67e74705SXin Li << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
341*67e74705SXin Li llvm::errs() << "\nLOC: ";
342*67e74705SXin Li Attr.Loc.dump(Pass.Ctx.getSourceManager());
343*67e74705SXin Li llvm::errs() << "\nTYPE: ";
344*67e74705SXin Li Attr.ModifiedType.dump();
345*67e74705SXin Li if (Attr.Dcl) {
346*67e74705SXin Li llvm::errs() << "DECL:\n";
347*67e74705SXin Li Attr.Dcl->dump();
348*67e74705SXin Li } else {
349*67e74705SXin Li llvm::errs() << "DECL: NONE";
350*67e74705SXin Li }
351*67e74705SXin Li llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
352*67e74705SXin Li llvm::errs() << "\n----------------\n";
353*67e74705SXin Li }
354*67e74705SXin Li llvm::errs() << "\n################\n";
355*67e74705SXin Li }
356