blob: 4fd21aa6c26999f00b866af9d1fce479ae4e1f8f [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"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000012#include "clang/AST/ASTContext.h"
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000013#include "clang/Basic/SourceManager.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000014#include "clang/Lex/Lexer.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"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000018#include "llvm/Support/SaveAndRestore.h"
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000019
20using namespace clang;
21using namespace arcmt;
22using namespace trans;
23
24namespace {
25
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000026/// Collects all the places where GC attributes __strong/__weak occur.
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000027class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
28 MigrationContext &MigrateCtx;
29 bool FullyMigratable;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000030 std::vector<ObjCPropertyDecl *> &AllProps;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000031
32 typedef RecursiveASTVisitor<GCAttrsCollector> base;
33public:
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000034 GCAttrsCollector(MigrationContext &ctx,
35 std::vector<ObjCPropertyDecl *> &AllProps)
36 : MigrateCtx(ctx), FullyMigratable(false),
37 AllProps(AllProps) { }
Argyrios Kyrtzidise43ae792011-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 Kyrtzidis722d21c2011-11-07 18:46:46 +000050 SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000051
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000052 if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000053 lookForAttribute(PropD, PropD->getTypeSourceInfo());
Argyrios Kyrtzidis722d21c2011-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 Kyrtzidise43ae792011-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) {
David Blaikie6adc78e2013-02-18 22:06:02 +000066 if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
67 TL = QL.getUnqualifiedLoc();
68 } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
69 if (handleAttr(Attr, D))
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000070 break;
David Blaikie6adc78e2013-02-18 22:06:02 +000071 TL = Attr.getModifiedLoc();
72 } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
73 TL = Arr.getElementLoc();
74 } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
75 TL = PT.getPointeeLoc();
76 } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
77 TL = RT.getPointeeLoc();
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000078 else
79 break;
80 }
81 }
82
Craig Topper8ae12032014-05-07 06:21:57 +000083 bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000084 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())
Richard Smithb5f81712018-04-30 05:25:48 +000095 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
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)) {
Aaron Ballman2b124d12014-03-13 16:36:16 +0000137 for (const auto *MI : RD->methods()) {
David Blaikie2d7c57e2012-04-30 02:36:29 +0000138 if (MI->isOutOfLine())
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000139 return true;
140 }
141 return false;
142 }
143
144 return isMigratable(cast<Decl>(D->getDeclContext()));
145 }
146
Argyrios Kyrtzidis722d21c2011-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))
Craig Topper8ae12032014-05-07 06:21:57 +0000152 return ID->getImplementation() != nullptr;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000153 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
Craig Topper8ae12032014-05-07 06:21:57 +0000154 return CD->getImplementation() != nullptr;
Alexander Kornienkoad988852015-11-06 01:26:37 +0000155 return isa<ObjCImplDecl>(ContD);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000156 }
157 return false;
158 }
159
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000160 bool isInMainFile(Decl *D) {
161 if (!D)
162 return false;
163
Aaron Ballman86c93902014-03-06 23:45:36 +0000164 for (auto I : D->redecls())
David Blaikieb15de1e2012-05-01 00:48:43 +0000165 if (!isInMainFile(I->getLocation()))
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000166 return false;
167
168 return true;
169 }
170
171 bool isInMainFile(SourceLocation Loc) {
172 if (Loc.isInvalid())
173 return false;
174
175 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
176 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
177 }
178};
179
180} // anonymous namespace
181
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000182static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
183 TransformActions &TA = MigrateCtx.Pass.TA;
184
185 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
186 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
187 if (Attr.FullyMigratable && Attr.Dcl) {
188 if (Attr.ModifiedType.isNull())
189 continue;
190 if (!Attr.ModifiedType->isObjCRetainableType()) {
191 TA.reportError("GC managed memory will become unmanaged in ARC",
192 Attr.Loc);
193 }
194 }
195 }
196}
197
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000198static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
199 TransformActions &TA = MigrateCtx.Pass.TA;
200
201 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
202 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000203 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000204 if (Attr.ModifiedType.isNull() ||
205 !Attr.ModifiedType->isObjCRetainableType())
206 continue;
207 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
208 /*AllowOnUnknownClass=*/true)) {
209 Transaction Trans(TA);
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000210 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
211 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000212 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
213 diag::err_arc_unsupported_weak_class,
214 Attr.Loc);
215 }
216 }
217 }
218}
219
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000220typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
221
222static void checkAllAtProps(MigrationContext &MigrateCtx,
223 SourceLocation AtLoc,
224 IndivPropsTy &IndProps) {
225 if (IndProps.empty())
226 return;
227
228 for (IndivPropsTy::iterator
229 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
230 QualType T = (*PI)->getType();
231 if (T.isNull() || !T->isObjCRetainableType())
232 return;
233 }
234
235 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
236 bool hasWeak = false, hasStrong = false;
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000237 ObjCPropertyDecl::PropertyAttributeKind
238 Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000239 for (IndivPropsTy::iterator
240 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
241 ObjCPropertyDecl *PD = *PI;
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000242 Attrs = PD->getPropertyAttributesAsWritten();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000243 TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
244 if (!TInfo)
245 return;
246 TypeLoc TL = TInfo->getTypeLoc();
David Blaikie6adc78e2013-02-18 22:06:02 +0000247 if (AttributedTypeLoc ATL =
248 TL.getAs<AttributedTypeLoc>()) {
249 ATLs.push_back(std::make_pair(ATL, PD));
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000250 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
251 hasWeak = true;
252 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
253 hasStrong = true;
254 else
255 return;
256 }
257 }
258 if (ATLs.empty())
259 return;
260 if (hasWeak && hasStrong)
261 return;
262
263 TransformActions &TA = MigrateCtx.Pass.TA;
264 Transaction Trans(TA);
265
266 if (GCAttrsCollector::hasObjCImpl(
267 cast<Decl>(IndProps.front()->getDeclContext()))) {
268 if (hasWeak)
269 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
270
271 } else {
272 StringRef toAttr = "strong";
273 if (hasWeak) {
274 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
275 /*AllowOnUnkwownClass=*/true))
276 toAttr = "weak";
277 else
278 toAttr = "unsafe_unretained";
279 }
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000280 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
281 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
282 else
283 MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000284 }
285
286 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
287 SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
288 if (Loc.isMacroID())
289 Loc = MigrateCtx.Pass.Ctx.getSourceManager()
Richard Smithb5f81712018-04-30 05:25:48 +0000290 .getImmediateExpansionRange(Loc)
291 .getBegin();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000292 TA.remove(Loc);
293 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
294 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
295 ATLs[i].second->getLocation());
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000296 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000297 }
298}
299
300static void checkAllProps(MigrationContext &MigrateCtx,
301 std::vector<ObjCPropertyDecl *> &AllProps) {
302 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
303 llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
304
305 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
306 ObjCPropertyDecl *PD = AllProps[i];
307 if (PD->getPropertyAttributesAsWritten() &
Argyrios Kyrtzidis3fc3dcd2011-11-28 00:23:12 +0000308 (ObjCPropertyDecl::OBJC_PR_assign |
309 ObjCPropertyDecl::OBJC_PR_readonly)) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000310 SourceLocation AtLoc = PD->getAtLoc();
311 if (AtLoc.isInvalid())
312 continue;
313 unsigned RawAt = AtLoc.getRawEncoding();
314 AtProps[RawAt].push_back(PD);
315 }
316 }
317
318 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
319 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
320 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
321 IndivPropsTy &IndProps = I->second;
322 checkAllAtProps(MigrateCtx, AtLoc, IndProps);
323 }
324}
325
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000326void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000327 std::vector<ObjCPropertyDecl *> AllProps;
328 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000329 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000330
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000331 errorForGCAttrsOnNonObjC(MigrateCtx);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000332 checkAllProps(MigrateCtx, AllProps);
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000333 checkWeakGCAttrs(MigrateCtx);
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000334}
335
336void MigrationContext::dumpGCAttrs() {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000337 llvm::errs() << "\n################\n";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000338 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
339 GCAttrOccurrence &Attr = GCAttrs[i];
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000340 llvm::errs() << "KIND: "
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000341 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000342 llvm::errs() << "\nLOC: ";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000343 Attr.Loc.dump(Pass.Ctx.getSourceManager());
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000344 llvm::errs() << "\nTYPE: ";
345 Attr.ModifiedType.dump();
346 if (Attr.Dcl) {
347 llvm::errs() << "DECL:\n";
348 Attr.Dcl->dump();
349 } else {
350 llvm::errs() << "DECL: NONE";
351 }
352 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
353 llvm::errs() << "\n----------------\n";
354 }
355 llvm::errs() << "\n################\n";
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000356}