blob: 5e3162197ed1b01a0148b795de88960f6a5d0bf3 [file] [log] [blame]
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +00001//===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "Transforms.h"
10#include "Internals.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000011#include "clang/AST/ASTContext.h"
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000012#include "clang/Basic/SourceManager.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000013#include "clang/Lex/Lexer.h"
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000014#include "clang/Sema/SemaDiagnostic.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000015#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000016#include "llvm/ADT/TinyPtrVector.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000017#include "llvm/Support/SaveAndRestore.h"
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000018
19using namespace clang;
20using namespace arcmt;
21using namespace trans;
22
23namespace {
24
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000025/// Collects all the places where GC attributes __strong/__weak occur.
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000026class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
27 MigrationContext &MigrateCtx;
28 bool FullyMigratable;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000029 std::vector<ObjCPropertyDecl *> &AllProps;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000030
31 typedef RecursiveASTVisitor<GCAttrsCollector> base;
32public:
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000033 GCAttrsCollector(MigrationContext &ctx,
34 std::vector<ObjCPropertyDecl *> &AllProps)
35 : MigrateCtx(ctx), FullyMigratable(false),
36 AllProps(AllProps) { }
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000037
38 bool shouldWalkTypesOfTypeLocs() const { return false; }
39
40 bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
41 handleAttr(TL);
42 return true;
43 }
44
45 bool TraverseDecl(Decl *D) {
46 if (!D || D->isImplicit())
47 return true;
48
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000049 SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
Fangrui Song6907ce22018-07-30 19:24:48 +000050
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000051 if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000052 lookForAttribute(PropD, PropD->getTypeSourceInfo());
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000053 AllProps.push_back(PropD);
54 } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
55 lookForAttribute(DD, DD->getTypeSourceInfo());
56 }
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000057 return base::TraverseDecl(D);
58 }
59
60 void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
61 if (!TInfo)
62 return;
63 TypeLoc TL = TInfo->getTypeLoc();
64 while (TL) {
David Blaikie6adc78e2013-02-18 22:06:02 +000065 if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
66 TL = QL.getUnqualifiedLoc();
67 } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
68 if (handleAttr(Attr, D))
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000069 break;
David Blaikie6adc78e2013-02-18 22:06:02 +000070 TL = Attr.getModifiedLoc();
Leonard Chanc72aaf62019-05-07 03:20:17 +000071 } else if (MacroQualifiedTypeLoc MDTL =
72 TL.getAs<MacroQualifiedTypeLoc>()) {
73 TL = MDTL.getInnerLoc();
David Blaikie6adc78e2013-02-18 22:06:02 +000074 } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
75 TL = Arr.getElementLoc();
76 } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
77 TL = PT.getPointeeLoc();
78 } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
79 TL = RT.getPointeeLoc();
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000080 else
81 break;
82 }
83 }
84
Craig Topper8ae12032014-05-07 06:21:57 +000085 bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
Richard Smithe43e2b32018-08-20 21:47:29 +000086 auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
87 if (!OwnershipAttr)
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000088 return false;
89
Richard Smithe43e2b32018-08-20 21:47:29 +000090 SourceLocation Loc = OwnershipAttr->getLocation();
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +000091 unsigned RawLoc = Loc.getRawEncoding();
92 if (MigrateCtx.AttrSet.count(RawLoc))
93 return true;
94
95 ASTContext &Ctx = MigrateCtx.Pass.Ctx;
96 SourceManager &SM = Ctx.getSourceManager();
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000097 if (Loc.isMacroID())
Richard Smithb5f81712018-04-30 05:25:48 +000098 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
Richard Smithe43e2b32018-08-20 21:47:29 +000099 StringRef Spell = OwnershipAttr->getKind()->getName();
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000100 MigrationContext::GCAttrOccurrence::AttrKind Kind;
101 if (Spell == "strong")
102 Kind = MigrationContext::GCAttrOccurrence::Strong;
103 else if (Spell == "weak")
104 Kind = MigrationContext::GCAttrOccurrence::Weak;
105 else
106 return false;
Fangrui Song6907ce22018-07-30 19:24:48 +0000107
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000108 MigrateCtx.AttrSet.insert(RawLoc);
109 MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
110 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
111
112 Attr.Kind = Kind;
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000113 Attr.Loc = Loc;
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000114 Attr.ModifiedType = TL.getModifiedLoc().getType();
115 Attr.Dcl = D;
116 Attr.FullyMigratable = FullyMigratable;
117 return true;
118 }
119
120 bool isMigratable(Decl *D) {
121 if (isa<TranslationUnitDecl>(D))
122 return false;
123
124 if (isInMainFile(D))
125 return true;
126
127 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
128 return FD->hasBody();
129
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000130 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
131 return hasObjCImpl(ContD);
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000132
133 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
Aaron Ballman2b124d12014-03-13 16:36:16 +0000134 for (const auto *MI : RD->methods()) {
David Blaikie2d7c57e2012-04-30 02:36:29 +0000135 if (MI->isOutOfLine())
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000136 return true;
137 }
138 return false;
139 }
140
141 return isMigratable(cast<Decl>(D->getDeclContext()));
142 }
143
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000144 static bool hasObjCImpl(Decl *D) {
145 if (!D)
146 return false;
147 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
148 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
Craig Topper8ae12032014-05-07 06:21:57 +0000149 return ID->getImplementation() != nullptr;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000150 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
Craig Topper8ae12032014-05-07 06:21:57 +0000151 return CD->getImplementation() != nullptr;
Alexander Kornienkoad988852015-11-06 01:26:37 +0000152 return isa<ObjCImplDecl>(ContD);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000153 }
154 return false;
155 }
156
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000157 bool isInMainFile(Decl *D) {
158 if (!D)
159 return false;
160
Aaron Ballman86c93902014-03-06 23:45:36 +0000161 for (auto I : D->redecls())
David Blaikieb15de1e2012-05-01 00:48:43 +0000162 if (!isInMainFile(I->getLocation()))
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000163 return false;
Fangrui Song6907ce22018-07-30 19:24:48 +0000164
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000165 return true;
166 }
167
168 bool isInMainFile(SourceLocation Loc) {
169 if (Loc.isInvalid())
170 return false;
171
172 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
173 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
174 }
175};
176
177} // anonymous namespace
178
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000179static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
180 TransformActions &TA = MigrateCtx.Pass.TA;
181
182 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
183 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
184 if (Attr.FullyMigratable && Attr.Dcl) {
185 if (Attr.ModifiedType.isNull())
186 continue;
187 if (!Attr.ModifiedType->isObjCRetainableType()) {
188 TA.reportError("GC managed memory will become unmanaged in ARC",
189 Attr.Loc);
190 }
191 }
192 }
193}
194
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000195static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
196 TransformActions &TA = MigrateCtx.Pass.TA;
197
198 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
199 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000200 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000201 if (Attr.ModifiedType.isNull() ||
202 !Attr.ModifiedType->isObjCRetainableType())
203 continue;
204 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
205 /*AllowOnUnknownClass=*/true)) {
206 Transaction Trans(TA);
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000207 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
208 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +0000209 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
210 diag::err_arc_unsupported_weak_class,
211 Attr.Loc);
212 }
213 }
214 }
215}
216
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000217typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
218
219static void checkAllAtProps(MigrationContext &MigrateCtx,
220 SourceLocation AtLoc,
221 IndivPropsTy &IndProps) {
222 if (IndProps.empty())
223 return;
224
225 for (IndivPropsTy::iterator
226 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
227 QualType T = (*PI)->getType();
228 if (T.isNull() || !T->isObjCRetainableType())
229 return;
230 }
231
232 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
233 bool hasWeak = false, hasStrong = false;
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000234 ObjCPropertyDecl::PropertyAttributeKind
235 Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000236 for (IndivPropsTy::iterator
237 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
238 ObjCPropertyDecl *PD = *PI;
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000239 Attrs = PD->getPropertyAttributesAsWritten();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000240 TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
241 if (!TInfo)
242 return;
243 TypeLoc TL = TInfo->getTypeLoc();
David Blaikie6adc78e2013-02-18 22:06:02 +0000244 if (AttributedTypeLoc ATL =
245 TL.getAs<AttributedTypeLoc>()) {
246 ATLs.push_back(std::make_pair(ATL, PD));
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000247 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
248 hasWeak = true;
249 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
250 hasStrong = true;
251 else
252 return;
253 }
254 }
255 if (ATLs.empty())
256 return;
257 if (hasWeak && hasStrong)
258 return;
259
260 TransformActions &TA = MigrateCtx.Pass.TA;
261 Transaction Trans(TA);
262
263 if (GCAttrsCollector::hasObjCImpl(
264 cast<Decl>(IndProps.front()->getDeclContext()))) {
265 if (hasWeak)
266 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
267
268 } else {
269 StringRef toAttr = "strong";
270 if (hasWeak) {
271 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
Rui Ueyama49a3ad22019-07-16 04:46:31 +0000272 /*AllowOnUnknownClass=*/true))
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000273 toAttr = "weak";
274 else
275 toAttr = "unsafe_unretained";
276 }
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000277 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
278 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
279 else
280 MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000281 }
282
283 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
Richard Smithe43e2b32018-08-20 21:47:29 +0000284 SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000285 if (Loc.isMacroID())
286 Loc = MigrateCtx.Pass.Ctx.getSourceManager()
Richard Smithb5f81712018-04-30 05:25:48 +0000287 .getImmediateExpansionRange(Loc)
288 .getBegin();
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000289 TA.remove(Loc);
290 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
291 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
292 ATLs[i].second->getLocation());
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000293 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000294 }
295}
296
297static void checkAllProps(MigrationContext &MigrateCtx,
298 std::vector<ObjCPropertyDecl *> &AllProps) {
299 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
300 llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
301
302 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
303 ObjCPropertyDecl *PD = AllProps[i];
304 if (PD->getPropertyAttributesAsWritten() &
Argyrios Kyrtzidis3fc3dcd2011-11-28 00:23:12 +0000305 (ObjCPropertyDecl::OBJC_PR_assign |
306 ObjCPropertyDecl::OBJC_PR_readonly)) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000307 SourceLocation AtLoc = PD->getAtLoc();
308 if (AtLoc.isInvalid())
309 continue;
310 unsigned RawAt = AtLoc.getRawEncoding();
311 AtProps[RawAt].push_back(PD);
312 }
313 }
314
315 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
316 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
317 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
318 IndivPropsTy &IndProps = I->second;
319 checkAllAtProps(MigrateCtx, AtLoc, IndProps);
320 }
321}
322
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000323void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000324 std::vector<ObjCPropertyDecl *> AllProps;
325 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000326 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000327
Argyrios Kyrtzidisf233dac2011-11-06 18:58:23 +0000328 errorForGCAttrsOnNonObjC(MigrateCtx);
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000329 checkAllProps(MigrateCtx, AllProps);
Argyrios Kyrtzidis2519a082011-11-08 02:02:38 +0000330 checkWeakGCAttrs(MigrateCtx);
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000331}
332
333void MigrationContext::dumpGCAttrs() {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000334 llvm::errs() << "\n################\n";
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000335 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
336 GCAttrOccurrence &Attr = GCAttrs[i];
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000337 llvm::errs() << "KIND: "
Argyrios Kyrtzidis0c233fa2011-11-06 18:58:17 +0000338 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000339 llvm::errs() << "\nLOC: ";
Stephen Kelly3124ce72018-08-15 20:32:06 +0000340 Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000341 llvm::errs() << "\nTYPE: ";
342 Attr.ModifiedType.dump();
343 if (Attr.Dcl) {
344 llvm::errs() << "DECL:\n";
345 Attr.Dcl->dump();
346 } else {
347 llvm::errs() << "DECL: NONE";
348 }
349 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
350 llvm::errs() << "\n----------------\n";
351 }
352 llvm::errs() << "\n################\n";
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000353}