blob: eec7306ba74a63674ddffadbdc6afafa5a843ac9 [file] [log] [blame]
Argyrios Kyrtzidisf38fa732011-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"
Benjamin Kramer471c8b42012-07-04 20:19:54 +000012#include "clang/AST/ASTContext.h"
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000013#include "clang/Basic/SourceManager.h"
Benjamin Kramer471c8b42012-07-04 20:19:54 +000014#include "clang/Lex/Lexer.h"
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000015#include "clang/Sema/SemaDiagnostic.h"
Benjamin Kramer8fe83e12012-02-04 13:45:25 +000016#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000017#include "llvm/ADT/TinyPtrVector.h"
Benjamin Kramer471c8b42012-07-04 20:19:54 +000018#include "llvm/Support/SaveAndRestore.h"
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000019
20using namespace clang;
21using namespace arcmt;
22using namespace trans;
23
24namespace {
25
26/// \brief Collects all the places where GC attributes __strong/__weak occur.
27class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
28 MigrationContext &MigrateCtx;
29 bool FullyMigratable;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000030 std::vector<ObjCPropertyDecl *> &AllProps;
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000031
32 typedef RecursiveASTVisitor<GCAttrsCollector> base;
33public:
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000034 GCAttrsCollector(MigrationContext &ctx,
35 std::vector<ObjCPropertyDecl *> &AllProps)
36 : MigrateCtx(ctx), FullyMigratable(false),
37 AllProps(AllProps) { }
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000038
39 bool shouldWalkTypesOfTypeLocs() const { return false; }
40
41 bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
42 handleAttr(TL);
43 return true;
44 }
45
46 bool TraverseDecl(Decl *D) {
47 if (!D || D->isImplicit())
48 return true;
49
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000050 SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000051
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000052 if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000053 lookForAttribute(PropD, PropD->getTypeSourceInfo());
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000054 AllProps.push_back(PropD);
55 } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
56 lookForAttribute(DD, DD->getTypeSourceInfo());
57 }
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000058 return base::TraverseDecl(D);
59 }
60
61 void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
62 if (!TInfo)
63 return;
64 TypeLoc TL = TInfo->getTypeLoc();
65 while (TL) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000066 if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
67 TL = QL->getUnqualifiedLoc();
68 } else if (const AttributedTypeLoc *
69 Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000070 if (handleAttr(*Attr, D))
71 break;
72 TL = Attr->getModifiedLoc();
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000073 } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000074 TL = Arr->getElementLoc();
75 } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
76 TL = PT->getPointeeLoc();
77 } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
78 TL = RT->getPointeeLoc();
79 else
80 break;
81 }
82 }
83
84 bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
85 if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
86 return false;
87
88 SourceLocation Loc = TL.getAttrNameLoc();
89 unsigned RawLoc = Loc.getRawEncoding();
90 if (MigrateCtx.AttrSet.count(RawLoc))
91 return true;
92
93 ASTContext &Ctx = MigrateCtx.Pass.Ctx;
94 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000095 if (Loc.isMacroID())
96 Loc = SM.getImmediateExpansionRange(Loc).first;
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +000097 SmallString<32> Buf;
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000098 bool Invalid = false;
99 StringRef Spell = Lexer::getSpelling(
100 SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
David Blaikie4e4d0842012-03-11 07:00:24 +0000101 Buf, SM, Ctx.getLangOpts(), &Invalid);
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000102 if (Invalid)
103 return false;
104 MigrationContext::GCAttrOccurrence::AttrKind Kind;
105 if (Spell == "strong")
106 Kind = MigrationContext::GCAttrOccurrence::Strong;
107 else if (Spell == "weak")
108 Kind = MigrationContext::GCAttrOccurrence::Weak;
109 else
110 return false;
111
112 MigrateCtx.AttrSet.insert(RawLoc);
113 MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
114 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
115
116 Attr.Kind = Kind;
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000117 Attr.Loc = Loc;
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000118 Attr.ModifiedType = TL.getModifiedLoc().getType();
119 Attr.Dcl = D;
120 Attr.FullyMigratable = FullyMigratable;
121 return true;
122 }
123
124 bool isMigratable(Decl *D) {
125 if (isa<TranslationUnitDecl>(D))
126 return false;
127
128 if (isInMainFile(D))
129 return true;
130
131 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
132 return FD->hasBody();
133
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000134 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
135 return hasObjCImpl(ContD);
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000136
137 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
138 for (CXXRecordDecl::method_iterator
139 MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
David Blaikie262bc182012-04-30 02:36:29 +0000140 if (MI->isOutOfLine())
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000141 return true;
142 }
143 return false;
144 }
145
146 return isMigratable(cast<Decl>(D->getDeclContext()));
147 }
148
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000149 static bool hasObjCImpl(Decl *D) {
150 if (!D)
151 return false;
152 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
153 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
154 return ID->getImplementation() != 0;
155 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
156 return CD->getImplementation() != 0;
157 if (isa<ObjCImplDecl>(ContD))
158 return true;
159 return false;
160 }
161 return false;
162 }
163
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000164 bool isInMainFile(Decl *D) {
165 if (!D)
166 return false;
167
168 for (Decl::redecl_iterator
169 I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
David Blaikiebd4fa452012-05-01 00:48:43 +0000170 if (!isInMainFile(I->getLocation()))
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000171 return false;
172
173 return true;
174 }
175
176 bool isInMainFile(SourceLocation Loc) {
177 if (Loc.isInvalid())
178 return false;
179
180 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
181 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
182 }
183};
184
185} // anonymous namespace
186
Argyrios Kyrtzidis280b4ad2011-11-06 18:58:23 +0000187static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
188 TransformActions &TA = MigrateCtx.Pass.TA;
189
190 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
191 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
192 if (Attr.FullyMigratable && Attr.Dcl) {
193 if (Attr.ModifiedType.isNull())
194 continue;
195 if (!Attr.ModifiedType->isObjCRetainableType()) {
196 TA.reportError("GC managed memory will become unmanaged in ARC",
197 Attr.Loc);
198 }
199 }
200 }
201}
202
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000203static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
204 TransformActions &TA = MigrateCtx.Pass.TA;
205
206 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
207 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000208 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000209 if (Attr.ModifiedType.isNull() ||
210 !Attr.ModifiedType->isObjCRetainableType())
211 continue;
212 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
213 /*AllowOnUnknownClass=*/true)) {
214 Transaction Trans(TA);
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000215 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
216 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000217 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
218 diag::err_arc_unsupported_weak_class,
219 Attr.Loc);
220 }
221 }
222 }
223}
224
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000225typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
226
227static void checkAllAtProps(MigrationContext &MigrateCtx,
228 SourceLocation AtLoc,
229 IndivPropsTy &IndProps) {
230 if (IndProps.empty())
231 return;
232
233 for (IndivPropsTy::iterator
234 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
235 QualType T = (*PI)->getType();
236 if (T.isNull() || !T->isObjCRetainableType())
237 return;
238 }
239
240 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
241 bool hasWeak = false, hasStrong = false;
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000242 ObjCPropertyDecl::PropertyAttributeKind
243 Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000244 for (IndivPropsTy::iterator
245 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
246 ObjCPropertyDecl *PD = *PI;
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000247 Attrs = PD->getPropertyAttributesAsWritten();
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000248 TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
249 if (!TInfo)
250 return;
251 TypeLoc TL = TInfo->getTypeLoc();
252 if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
253 ATLs.push_back(std::make_pair(*ATL, PD));
254 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
255 hasWeak = true;
256 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
257 hasStrong = true;
258 else
259 return;
260 }
261 }
262 if (ATLs.empty())
263 return;
264 if (hasWeak && hasStrong)
265 return;
266
267 TransformActions &TA = MigrateCtx.Pass.TA;
268 Transaction Trans(TA);
269
270 if (GCAttrsCollector::hasObjCImpl(
271 cast<Decl>(IndProps.front()->getDeclContext()))) {
272 if (hasWeak)
273 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
274
275 } else {
276 StringRef toAttr = "strong";
277 if (hasWeak) {
278 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
279 /*AllowOnUnkwownClass=*/true))
280 toAttr = "weak";
281 else
282 toAttr = "unsafe_unretained";
283 }
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000284 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
285 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
286 else
287 MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000288 }
289
290 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
291 SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
292 if (Loc.isMacroID())
293 Loc = MigrateCtx.Pass.Ctx.getSourceManager()
294 .getImmediateExpansionRange(Loc).first;
295 TA.remove(Loc);
296 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
297 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
298 ATLs[i].second->getLocation());
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000299 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000300 }
301}
302
303static void checkAllProps(MigrationContext &MigrateCtx,
304 std::vector<ObjCPropertyDecl *> &AllProps) {
305 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
306 llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
307
308 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
309 ObjCPropertyDecl *PD = AllProps[i];
310 if (PD->getPropertyAttributesAsWritten() &
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000311 (ObjCPropertyDecl::OBJC_PR_assign |
312 ObjCPropertyDecl::OBJC_PR_readonly)) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000313 SourceLocation AtLoc = PD->getAtLoc();
314 if (AtLoc.isInvalid())
315 continue;
316 unsigned RawAt = AtLoc.getRawEncoding();
317 AtProps[RawAt].push_back(PD);
318 }
319 }
320
321 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
322 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
323 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
324 IndivPropsTy &IndProps = I->second;
325 checkAllAtProps(MigrateCtx, AtLoc, IndProps);
326 }
327}
328
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000329void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000330 std::vector<ObjCPropertyDecl *> AllProps;
331 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000332 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidis280b4ad2011-11-06 18:58:23 +0000333
Argyrios Kyrtzidis280b4ad2011-11-06 18:58:23 +0000334 errorForGCAttrsOnNonObjC(MigrateCtx);
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000335 checkAllProps(MigrateCtx, AllProps);
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000336 checkWeakGCAttrs(MigrateCtx);
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000337}
338
339void MigrationContext::dumpGCAttrs() {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000340 llvm::errs() << "\n################\n";
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000341 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
342 GCAttrOccurrence &Attr = GCAttrs[i];
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000343 llvm::errs() << "KIND: "
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000344 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000345 llvm::errs() << "\nLOC: ";
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000346 Attr.Loc.dump(Pass.Ctx.getSourceManager());
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000347 llvm::errs() << "\nTYPE: ";
348 Attr.ModifiedType.dump();
349 if (Attr.Dcl) {
350 llvm::errs() << "DECL:\n";
351 Attr.Dcl->dump();
352 } else {
353 llvm::errs() << "DECL: NONE";
354 }
355 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
356 llvm::errs() << "\n----------------\n";
357 }
358 llvm::errs() << "\n################\n";
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000359}