blob: 9f6066ef77daa0784dcb08d74172da6a06618902 [file] [log] [blame]
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +00001//===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Transforms.h"
11#include "Internals.h"
12#include "clang/Lex/Lexer.h"
13#include "clang/Basic/SourceManager.h"
Argyrios Kyrtzidis981a9612012-03-01 19:45:56 +000014#include "llvm/Support/SaveAndRestore.h"
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000015#include "clang/Sema/SemaDiagnostic.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000016#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000017#include "llvm/ADT/TinyPtrVector.h"
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000018
19using namespace clang;
20using namespace arcmt;
21using namespace trans;
22
23namespace {
24
25/// \brief Collects all the places where GC attributes __strong/__weak occur.
26class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
27 MigrationContext &MigrateCtx;
28 bool FullyMigratable;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000029 std::vector<ObjCPropertyDecl *> &AllProps;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000030
31 typedef RecursiveASTVisitor<GCAttrsCollector> base;
32public:
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000033 GCAttrsCollector(MigrationContext &ctx,
34 std::vector<ObjCPropertyDecl *> &AllProps)
35 : MigrateCtx(ctx), FullyMigratable(false),
36 AllProps(AllProps) { }
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000037
38 bool shouldWalkTypesOfTypeLocs() const { return false; }
39
40 bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
41 handleAttr(TL);
42 return true;
43 }
44
45 bool TraverseDecl(Decl *D) {
46 if (!D || D->isImplicit())
47 return true;
48
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000049 SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000050
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000051 if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000052 lookForAttribute(PropD, PropD->getTypeSourceInfo());
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000053 AllProps.push_back(PropD);
54 } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
55 lookForAttribute(DD, DD->getTypeSourceInfo());
56 }
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000057 return base::TraverseDecl(D);
58 }
59
60 void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
61 if (!TInfo)
62 return;
63 TypeLoc TL = TInfo->getTypeLoc();
64 while (TL) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000065 if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
66 TL = QL->getUnqualifiedLoc();
67 } else if (const AttributedTypeLoc *
68 Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000069 if (handleAttr(*Attr, D))
70 break;
71 TL = Attr->getModifiedLoc();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000072 } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000073 TL = Arr->getElementLoc();
74 } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
75 TL = PT->getPointeeLoc();
76 } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
77 TL = RT->getPointeeLoc();
78 else
79 break;
80 }
81 }
82
83 bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
84 if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
85 return false;
86
87 SourceLocation Loc = TL.getAttrNameLoc();
88 unsigned RawLoc = Loc.getRawEncoding();
89 if (MigrateCtx.AttrSet.count(RawLoc))
90 return true;
91
92 ASTContext &Ctx = MigrateCtx.Pass.Ctx;
93 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000094 if (Loc.isMacroID())
95 Loc = SM.getImmediateExpansionRange(Loc).first;
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000096 SmallString<32> Buf;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000097 bool Invalid = false;
98 StringRef Spell = Lexer::getSpelling(
99 SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000100 Buf, SM, Ctx.getLangOpts(), &Invalid);
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000101 if (Invalid)
102 return false;
103 MigrationContext::GCAttrOccurrence::AttrKind Kind;
104 if (Spell == "strong")
105 Kind = MigrationContext::GCAttrOccurrence::Strong;
106 else if (Spell == "weak")
107 Kind = MigrationContext::GCAttrOccurrence::Weak;
108 else
109 return false;
110
111 MigrateCtx.AttrSet.insert(RawLoc);
112 MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
113 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
114
115 Attr.Kind = Kind;
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000116 Attr.Loc = Loc;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000117 Attr.ModifiedType = TL.getModifiedLoc().getType();
118 Attr.Dcl = D;
119 Attr.FullyMigratable = FullyMigratable;
120 return true;
121 }
122
123 bool isMigratable(Decl *D) {
124 if (isa<TranslationUnitDecl>(D))
125 return false;
126
127 if (isInMainFile(D))
128 return true;
129
130 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
131 return FD->hasBody();
132
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000133 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
134 return hasObjCImpl(ContD);
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000135
136 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
137 for (CXXRecordDecl::method_iterator
138 MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
139 if ((*MI)->isOutOfLine())
140 return true;
141 }
142 return false;
143 }
144
145 return isMigratable(cast<Decl>(D->getDeclContext()));
146 }
147
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000148 static bool hasObjCImpl(Decl *D) {
149 if (!D)
150 return false;
151 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
152 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
153 return ID->getImplementation() != 0;
154 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
155 return CD->getImplementation() != 0;
156 if (isa<ObjCImplDecl>(ContD))
157 return true;
158 return false;
159 }
160 return false;
161 }
162
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000163 bool isInMainFile(Decl *D) {
164 if (!D)
165 return false;
166
167 for (Decl::redecl_iterator
168 I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
169 if (!isInMainFile((*I)->getLocation()))
170 return false;
171
172 return true;
173 }
174
175 bool isInMainFile(SourceLocation Loc) {
176 if (Loc.isInvalid())
177 return false;
178
179 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
180 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
181 }
182};
183
184} // anonymous namespace
185
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000186static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
187 TransformActions &TA = MigrateCtx.Pass.TA;
188
189 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
190 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
191 if (Attr.FullyMigratable && Attr.Dcl) {
192 if (Attr.ModifiedType.isNull())
193 continue;
194 if (!Attr.ModifiedType->isObjCRetainableType()) {
195 TA.reportError("GC managed memory will become unmanaged in ARC",
196 Attr.Loc);
197 }
198 }
199 }
200}
201
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000202static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
203 TransformActions &TA = MigrateCtx.Pass.TA;
204
205 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
206 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000207 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000208 if (Attr.ModifiedType.isNull() ||
209 !Attr.ModifiedType->isObjCRetainableType())
210 continue;
211 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
212 /*AllowOnUnknownClass=*/true)) {
213 Transaction Trans(TA);
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000214 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
215 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000216 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
217 diag::err_arc_unsupported_weak_class,
218 Attr.Loc);
219 }
220 }
221 }
222}
223
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000224typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
225
226static void checkAllAtProps(MigrationContext &MigrateCtx,
227 SourceLocation AtLoc,
228 IndivPropsTy &IndProps) {
229 if (IndProps.empty())
230 return;
231
232 for (IndivPropsTy::iterator
233 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
234 QualType T = (*PI)->getType();
235 if (T.isNull() || !T->isObjCRetainableType())
236 return;
237 }
238
239 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
240 bool hasWeak = false, hasStrong = false;
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000241 ObjCPropertyDecl::PropertyAttributeKind
242 Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000243 for (IndivPropsTy::iterator
244 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
245 ObjCPropertyDecl *PD = *PI;
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000246 Attrs = PD->getPropertyAttributesAsWritten();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000247 TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
248 if (!TInfo)
249 return;
250 TypeLoc TL = TInfo->getTypeLoc();
251 if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
252 ATLs.push_back(std::make_pair(*ATL, PD));
253 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
254 hasWeak = true;
255 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
256 hasStrong = true;
257 else
258 return;
259 }
260 }
261 if (ATLs.empty())
262 return;
263 if (hasWeak && hasStrong)
264 return;
265
266 TransformActions &TA = MigrateCtx.Pass.TA;
267 Transaction Trans(TA);
268
269 if (GCAttrsCollector::hasObjCImpl(
270 cast<Decl>(IndProps.front()->getDeclContext()))) {
271 if (hasWeak)
272 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
273
274 } else {
275 StringRef toAttr = "strong";
276 if (hasWeak) {
277 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
278 /*AllowOnUnkwownClass=*/true))
279 toAttr = "weak";
280 else
281 toAttr = "unsafe_unretained";
282 }
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000283 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
284 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
285 else
286 MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000287 }
288
289 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
290 SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
291 if (Loc.isMacroID())
292 Loc = MigrateCtx.Pass.Ctx.getSourceManager()
293 .getImmediateExpansionRange(Loc).first;
294 TA.remove(Loc);
295 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
296 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
297 ATLs[i].second->getLocation());
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000298 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000299 }
300}
301
302static void checkAllProps(MigrationContext &MigrateCtx,
303 std::vector<ObjCPropertyDecl *> &AllProps) {
304 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
305 llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
306
307 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
308 ObjCPropertyDecl *PD = AllProps[i];
309 if (PD->getPropertyAttributesAsWritten() &
Argyrios Kyrtzidis3fc3dcd2011-11-28 00:23:12 +0000310 (ObjCPropertyDecl::OBJC_PR_assign |
311 ObjCPropertyDecl::OBJC_PR_readonly)) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000312 SourceLocation AtLoc = PD->getAtLoc();
313 if (AtLoc.isInvalid())
314 continue;
315 unsigned RawAt = AtLoc.getRawEncoding();
316 AtProps[RawAt].push_back(PD);
317 }
318 }
319
320 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
321 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
322 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
323 IndivPropsTy &IndProps = I->second;
324 checkAllAtProps(MigrateCtx, AtLoc, IndProps);
325 }
326}
327
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000328void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000329 std::vector<ObjCPropertyDecl *> AllProps;
330 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000331 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000332
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000333 errorForGCAttrsOnNonObjC(MigrateCtx);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000334 checkAllProps(MigrateCtx, AllProps);
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000335 checkWeakGCAttrs(MigrateCtx);
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000336}
337
338void MigrationContext::dumpGCAttrs() {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000339 llvm::errs() << "\n################\n";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000340 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
341 GCAttrOccurrence &Attr = GCAttrs[i];
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000342 llvm::errs() << "KIND: "
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000343 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000344 llvm::errs() << "\nLOC: ";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000345 Attr.Loc.dump(Pass.Ctx.getSourceManager());
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000346 llvm::errs() << "\nTYPE: ";
347 Attr.ModifiedType.dump();
348 if (Attr.Dcl) {
349 llvm::errs() << "DECL:\n";
350 Attr.Dcl->dump();
351 } else {
352 llvm::errs() << "DECL: NONE";
353 }
354 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
355 llvm::errs() << "\n----------------\n";
356 }
357 llvm::errs() << "\n################\n";
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000358}