blob: 1c645ace89a4e40ff31f7551c7b9985bd96e0dbb [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"
12#include "clang/Lex/Lexer.h"
13#include "clang/Basic/SourceManager.h"
14#include "clang/Analysis/Support/SaveAndRestore.h"
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000015#include "clang/Sema/SemaDiagnostic.h"
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000016#include "llvm/ADT/TinyPtrVector.h"
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000017
18using namespace clang;
19using namespace arcmt;
20using namespace trans;
21
22namespace {
23
24/// \brief Collects all the places where GC attributes __strong/__weak occur.
25class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
26 MigrationContext &MigrateCtx;
27 bool FullyMigratable;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000028 std::vector<ObjCPropertyDecl *> &AllProps;
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000029
30 typedef RecursiveASTVisitor<GCAttrsCollector> base;
31public:
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000032 GCAttrsCollector(MigrationContext &ctx,
33 std::vector<ObjCPropertyDecl *> &AllProps)
34 : MigrateCtx(ctx), FullyMigratable(false),
35 AllProps(AllProps) { }
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000036
37 bool shouldWalkTypesOfTypeLocs() const { return false; }
38
39 bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
40 handleAttr(TL);
41 return true;
42 }
43
44 bool TraverseDecl(Decl *D) {
45 if (!D || D->isImplicit())
46 return true;
47
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000048 SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000049
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000050 if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000051 lookForAttribute(PropD, PropD->getTypeSourceInfo());
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000052 AllProps.push_back(PropD);
53 } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
54 lookForAttribute(DD, DD->getTypeSourceInfo());
55 }
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000056 return base::TraverseDecl(D);
57 }
58
59 void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
60 if (!TInfo)
61 return;
62 TypeLoc TL = TInfo->getTypeLoc();
63 while (TL) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000064 if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
65 TL = QL->getUnqualifiedLoc();
66 } else if (const AttributedTypeLoc *
67 Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000068 if (handleAttr(*Attr, D))
69 break;
70 TL = Attr->getModifiedLoc();
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000071 } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000072 TL = Arr->getElementLoc();
73 } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
74 TL = PT->getPointeeLoc();
75 } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
76 TL = RT->getPointeeLoc();
77 else
78 break;
79 }
80 }
81
82 bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
83 if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
84 return false;
85
86 SourceLocation Loc = TL.getAttrNameLoc();
87 unsigned RawLoc = Loc.getRawEncoding();
88 if (MigrateCtx.AttrSet.count(RawLoc))
89 return true;
90
91 ASTContext &Ctx = MigrateCtx.Pass.Ctx;
92 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000093 if (Loc.isMacroID())
94 Loc = SM.getImmediateExpansionRange(Loc).first;
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +000095 llvm::SmallString<32> Buf;
96 bool Invalid = false;
97 StringRef Spell = Lexer::getSpelling(
98 SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
99 Buf, SM, Ctx.getLangOptions(), &Invalid);
100 if (Invalid)
101 return false;
102 MigrationContext::GCAttrOccurrence::AttrKind Kind;
103 if (Spell == "strong")
104 Kind = MigrationContext::GCAttrOccurrence::Strong;
105 else if (Spell == "weak")
106 Kind = MigrationContext::GCAttrOccurrence::Weak;
107 else
108 return false;
109
110 MigrateCtx.AttrSet.insert(RawLoc);
111 MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
112 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
113
114 Attr.Kind = Kind;
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000115 Attr.Loc = Loc;
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000116 Attr.ModifiedType = TL.getModifiedLoc().getType();
117 Attr.Dcl = D;
118 Attr.FullyMigratable = FullyMigratable;
119 return true;
120 }
121
122 bool isMigratable(Decl *D) {
123 if (isa<TranslationUnitDecl>(D))
124 return false;
125
126 if (isInMainFile(D))
127 return true;
128
129 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
130 return FD->hasBody();
131
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000132 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
133 return hasObjCImpl(ContD);
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000134
135 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
136 for (CXXRecordDecl::method_iterator
137 MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
138 if ((*MI)->isOutOfLine())
139 return true;
140 }
141 return false;
142 }
143
144 return isMigratable(cast<Decl>(D->getDeclContext()));
145 }
146
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000147 static bool hasObjCImpl(Decl *D) {
148 if (!D)
149 return false;
150 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
151 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
152 return ID->getImplementation() != 0;
153 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
154 return CD->getImplementation() != 0;
155 if (isa<ObjCImplDecl>(ContD))
156 return true;
157 return false;
158 }
159 return false;
160 }
161
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000162 bool isInMainFile(Decl *D) {
163 if (!D)
164 return false;
165
166 for (Decl::redecl_iterator
167 I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
168 if (!isInMainFile((*I)->getLocation()))
169 return false;
170
171 return true;
172 }
173
174 bool isInMainFile(SourceLocation Loc) {
175 if (Loc.isInvalid())
176 return false;
177
178 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
179 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
180 }
181};
182
183} // anonymous namespace
184
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000185static void clearRedundantStrongs(MigrationContext &MigrateCtx) {
186 TransformActions &TA = MigrateCtx.Pass.TA;
187
188 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
189 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
190 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Strong &&
191 Attr.FullyMigratable && Attr.Dcl) {
192 TypeSourceInfo *TInfo = 0;
193 if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(Attr.Dcl))
194 TInfo = DD->getTypeSourceInfo();
195 else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(Attr.Dcl))
196 TInfo = PD->getTypeSourceInfo();
197 if (!TInfo)
198 continue;
199
200 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
201 Transaction Trans(TA);
202 TA.remove(Attr.Loc);
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000203 MigrateCtx.RemovedAttrSet.insert(Attr.Loc.getRawEncoding());
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000204 }
205 }
206 }
207}
208
Argyrios Kyrtzidis280b4ad2011-11-06 18:58:23 +0000209static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
210 TransformActions &TA = MigrateCtx.Pass.TA;
211
212 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
213 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
214 if (Attr.FullyMigratable && Attr.Dcl) {
215 if (Attr.ModifiedType.isNull())
216 continue;
217 if (!Attr.ModifiedType->isObjCRetainableType()) {
218 TA.reportError("GC managed memory will become unmanaged in ARC",
219 Attr.Loc);
220 }
221 }
222 }
223}
224
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000225static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
226 TransformActions &TA = MigrateCtx.Pass.TA;
227
228 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
229 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000230 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000231 if (Attr.ModifiedType.isNull() ||
232 !Attr.ModifiedType->isObjCRetainableType())
233 continue;
234 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
235 /*AllowOnUnknownClass=*/true)) {
236 Transaction Trans(TA);
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000237 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
238 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +0000239 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
240 diag::err_arc_unsupported_weak_class,
241 Attr.Loc);
242 }
243 }
244 }
245}
246
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000247typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
248
249static void checkAllAtProps(MigrationContext &MigrateCtx,
250 SourceLocation AtLoc,
251 IndivPropsTy &IndProps) {
252 if (IndProps.empty())
253 return;
254
255 for (IndivPropsTy::iterator
256 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
257 QualType T = (*PI)->getType();
258 if (T.isNull() || !T->isObjCRetainableType())
259 return;
260 }
261
262 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
263 bool hasWeak = false, hasStrong = false;
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000264 ObjCPropertyDecl::PropertyAttributeKind
265 Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000266 for (IndivPropsTy::iterator
267 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
268 ObjCPropertyDecl *PD = *PI;
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000269 Attrs = PD->getPropertyAttributesAsWritten();
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000270 TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
271 if (!TInfo)
272 return;
273 TypeLoc TL = TInfo->getTypeLoc();
274 if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
275 ATLs.push_back(std::make_pair(*ATL, PD));
276 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
277 hasWeak = true;
278 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
279 hasStrong = true;
280 else
281 return;
282 }
283 }
284 if (ATLs.empty())
285 return;
286 if (hasWeak && hasStrong)
287 return;
288
289 TransformActions &TA = MigrateCtx.Pass.TA;
290 Transaction Trans(TA);
291
292 if (GCAttrsCollector::hasObjCImpl(
293 cast<Decl>(IndProps.front()->getDeclContext()))) {
294 if (hasWeak)
295 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
296
297 } else {
298 StringRef toAttr = "strong";
299 if (hasWeak) {
300 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
301 /*AllowOnUnkwownClass=*/true))
302 toAttr = "weak";
303 else
304 toAttr = "unsafe_unretained";
305 }
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000306 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
307 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
308 else
309 MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000310 }
311
312 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
313 SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
314 if (Loc.isMacroID())
315 Loc = MigrateCtx.Pass.Ctx.getSourceManager()
316 .getImmediateExpansionRange(Loc).first;
317 TA.remove(Loc);
318 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
319 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
320 ATLs[i].second->getLocation());
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000321 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000322 }
323}
324
325static void checkAllProps(MigrationContext &MigrateCtx,
326 std::vector<ObjCPropertyDecl *> &AllProps) {
327 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
328 llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
329
330 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
331 ObjCPropertyDecl *PD = AllProps[i];
332 if (PD->getPropertyAttributesAsWritten() &
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000333 (ObjCPropertyDecl::OBJC_PR_assign |
334 ObjCPropertyDecl::OBJC_PR_readonly)) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000335 SourceLocation AtLoc = PD->getAtLoc();
336 if (AtLoc.isInvalid())
337 continue;
338 unsigned RawAt = AtLoc.getRawEncoding();
339 AtProps[RawAt].push_back(PD);
340 }
341 }
342
343 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
344 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
345 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
346 IndivPropsTy &IndProps = I->second;
347 checkAllAtProps(MigrateCtx, AtLoc, IndProps);
348 }
349}
350
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000351void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000352 std::vector<ObjCPropertyDecl *> AllProps;
353 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000354 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidis280b4ad2011-11-06 18:58:23 +0000355
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000356 clearRedundantStrongs(MigrateCtx);
Argyrios Kyrtzidis280b4ad2011-11-06 18:58:23 +0000357 errorForGCAttrsOnNonObjC(MigrateCtx);
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000358 checkAllProps(MigrateCtx, AllProps);
Argyrios Kyrtzidis7cfd7fe2011-11-08 02:02:38 +0000359 checkWeakGCAttrs(MigrateCtx);
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000360}
361
362void MigrationContext::dumpGCAttrs() {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000363 llvm::errs() << "\n################\n";
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000364 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
365 GCAttrOccurrence &Attr = GCAttrs[i];
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000366 llvm::errs() << "KIND: "
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000367 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000368 llvm::errs() << "\nLOC: ";
Argyrios Kyrtzidis17ac3192011-11-06 18:58:17 +0000369 Attr.Loc.dump(Pass.Ctx.getSourceManager());
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000370 llvm::errs() << "\nTYPE: ";
371 Attr.ModifiedType.dump();
372 if (Attr.Dcl) {
373 llvm::errs() << "DECL:\n";
374 Attr.Dcl->dump();
375 } else {
376 llvm::errs() << "DECL: NONE";
377 }
378 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
379 llvm::errs() << "\n----------------\n";
380 }
381 llvm::errs() << "\n################\n";
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000382}