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