blob: 94eb8781dfef24af1787eb5278a4df2d5cc86274 [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"
14#include "clang/Analysis/Support/SaveAndRestore.h"
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000015#include "clang/Sema/SemaDiagnostic.h"
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000016
17using namespace clang;
18using namespace arcmt;
19using namespace trans;
20
21namespace {
22
23/// \brief Collects all the places where GC attributes __strong/__weak occur.
24class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
25 MigrationContext &MigrateCtx;
26 bool FullyMigratable;
27
28 typedef RecursiveASTVisitor<GCAttrsCollector> base;
29public:
30 explicit GCAttrsCollector(MigrationContext &ctx)
31 : MigrateCtx(ctx), FullyMigratable(false) { }
32
33 bool shouldWalkTypesOfTypeLocs() const { return false; }
34
35 bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
36 handleAttr(TL);
37 return true;
38 }
39
40 bool TraverseDecl(Decl *D) {
41 if (!D || D->isImplicit())
42 return true;
43
44 bool migratable = isMigratable(D);
45 SaveAndRestore<bool> Save(FullyMigratable, migratable);
46
47 if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
48 lookForAttribute(DD, DD->getTypeSourceInfo());
49 else if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D))
50 lookForAttribute(PropD, PropD->getTypeSourceInfo());
51 return base::TraverseDecl(D);
52 }
53
54 void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
55 if (!TInfo)
56 return;
57 TypeLoc TL = TInfo->getTypeLoc();
58 while (TL) {
59 if (const AttributedTypeLoc *Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
60 if (handleAttr(*Attr, D))
61 break;
62 TL = Attr->getModifiedLoc();
63 } if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
64 TL = Arr->getElementLoc();
65 } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
66 TL = PT->getPointeeLoc();
67 } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
68 TL = RT->getPointeeLoc();
69 else
70 break;
71 }
72 }
73
74 bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
75 if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
76 return false;
77
78 SourceLocation Loc = TL.getAttrNameLoc();
79 unsigned RawLoc = Loc.getRawEncoding();
80 if (MigrateCtx.AttrSet.count(RawLoc))
81 return true;
82
83 ASTContext &Ctx = MigrateCtx.Pass.Ctx;
84 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000085 if (Loc.isMacroID())
86 Loc = SM.getImmediateExpansionRange(Loc).first;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000087 llvm::SmallString<32> Buf;
88 bool Invalid = false;
89 StringRef Spell = Lexer::getSpelling(
90 SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
91 Buf, SM, Ctx.getLangOptions(), &Invalid);
92 if (Invalid)
93 return false;
94 MigrationContext::GCAttrOccurrence::AttrKind Kind;
95 if (Spell == "strong")
96 Kind = MigrationContext::GCAttrOccurrence::Strong;
97 else if (Spell == "weak")
98 Kind = MigrationContext::GCAttrOccurrence::Weak;
99 else
100 return false;
101
102 MigrateCtx.AttrSet.insert(RawLoc);
103 MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
104 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
105
106 Attr.Kind = Kind;
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000107 Attr.Loc = Loc;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000108 Attr.ModifiedType = TL.getModifiedLoc().getType();
109 Attr.Dcl = D;
110 Attr.FullyMigratable = FullyMigratable;
111 return true;
112 }
113
114 bool isMigratable(Decl *D) {
115 if (isa<TranslationUnitDecl>(D))
116 return false;
117
118 if (isInMainFile(D))
119 return true;
120
121 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
122 return FD->hasBody();
123
124 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
125 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
126 return ID->getImplementation() != 0;
127 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
128 return CD->getImplementation() != 0;
129 if (isa<ObjCImplDecl>(ContD))
130 return true;
131 return false;
132 }
133
134 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
135 for (CXXRecordDecl::method_iterator
136 MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
137 if ((*MI)->isOutOfLine())
138 return true;
139 }
140 return false;
141 }
142
143 return isMigratable(cast<Decl>(D->getDeclContext()));
144 }
145
146 bool isInMainFile(Decl *D) {
147 if (!D)
148 return false;
149
150 for (Decl::redecl_iterator
151 I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
152 if (!isInMainFile((*I)->getLocation()))
153 return false;
154
155 return true;
156 }
157
158 bool isInMainFile(SourceLocation Loc) {
159 if (Loc.isInvalid())
160 return false;
161
162 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
163 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
164 }
165};
166
167} // anonymous namespace
168
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000169static void clearRedundantStrongs(MigrationContext &MigrateCtx) {
170 TransformActions &TA = MigrateCtx.Pass.TA;
171
172 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
173 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
174 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Strong &&
175 Attr.FullyMigratable && Attr.Dcl) {
176 TypeSourceInfo *TInfo = 0;
177 if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(Attr.Dcl))
178 TInfo = DD->getTypeSourceInfo();
179 else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(Attr.Dcl))
180 TInfo = PD->getTypeSourceInfo();
181 if (!TInfo)
182 continue;
183
184 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
185 Transaction Trans(TA);
186 TA.remove(Attr.Loc);
187 }
188 }
189 }
190}
191
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000192static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
193 TransformActions &TA = MigrateCtx.Pass.TA;
194
195 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
196 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
197 if (Attr.FullyMigratable && Attr.Dcl) {
198 if (Attr.ModifiedType.isNull())
199 continue;
200 if (!Attr.ModifiedType->isObjCRetainableType()) {
201 TA.reportError("GC managed memory will become unmanaged in ARC",
202 Attr.Loc);
203 }
204 }
205 }
206}
207
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000208static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
209 TransformActions &TA = MigrateCtx.Pass.TA;
210
211 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
212 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
213 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak &&
214 Attr.FullyMigratable) {
215 if (Attr.ModifiedType.isNull() ||
216 !Attr.ModifiedType->isObjCRetainableType())
217 continue;
218 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
219 /*AllowOnUnknownClass=*/true)) {
220 Transaction Trans(TA);
221 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
222 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
223 diag::err_arc_unsupported_weak_class,
224 Attr.Loc);
225 }
226 }
227 }
228}
229
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000230void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
231 GCAttrsCollector(MigrateCtx).TraverseDecl(
232 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000233
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000234 clearRedundantStrongs(MigrateCtx);
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000235 errorForGCAttrsOnNonObjC(MigrateCtx);
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000236 checkWeakGCAttrs(MigrateCtx);
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000237}
238
239void MigrationContext::dumpGCAttrs() {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000240 llvm::errs() << "\n################\n";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000241 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
242 GCAttrOccurrence &Attr = GCAttrs[i];
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000243 llvm::errs() << "KIND: "
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000244 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000245 llvm::errs() << "\nLOC: ";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000246 Attr.Loc.dump(Pass.Ctx.getSourceManager());
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000247 llvm::errs() << "\nTYPE: ";
248 Attr.ModifiedType.dump();
249 if (Attr.Dcl) {
250 llvm::errs() << "DECL:\n";
251 Attr.Dcl->dump();
252 } else {
253 llvm::errs() << "DECL: NONE";
254 }
255 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
256 llvm::errs() << "\n----------------\n";
257 }
258 llvm::errs() << "\n################\n";
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000259}