Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/ARCMigrate/TransGCAttrs.cpp
35236 views
1
//===--- TransGCAttrs.cpp - Transformations to ARC mode -------------------===//
2
//
3
// 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
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "Transforms.h"
10
#include "Internals.h"
11
#include "clang/AST/ASTContext.h"
12
#include "clang/Basic/SourceManager.h"
13
#include "clang/Lex/Lexer.h"
14
#include "clang/Sema/SemaDiagnostic.h"
15
#include "llvm/ADT/SmallString.h"
16
#include "llvm/ADT/TinyPtrVector.h"
17
#include "llvm/Support/SaveAndRestore.h"
18
19
using namespace clang;
20
using namespace arcmt;
21
using namespace trans;
22
23
namespace {
24
25
/// Collects all the places where GC attributes __strong/__weak occur.
26
class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
27
MigrationContext &MigrateCtx;
28
bool FullyMigratable;
29
std::vector<ObjCPropertyDecl *> &AllProps;
30
31
typedef RecursiveASTVisitor<GCAttrsCollector> base;
32
public:
33
GCAttrsCollector(MigrationContext &ctx,
34
std::vector<ObjCPropertyDecl *> &AllProps)
35
: MigrateCtx(ctx), FullyMigratable(false),
36
AllProps(AllProps) { }
37
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
49
SaveAndRestore Save(FullyMigratable, isMigratable(D));
50
51
if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
52
lookForAttribute(PropD, PropD->getTypeSourceInfo());
53
AllProps.push_back(PropD);
54
} else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
55
lookForAttribute(DD, DD->getTypeSourceInfo());
56
}
57
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) {
65
if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
66
TL = QL.getUnqualifiedLoc();
67
} else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
68
if (handleAttr(Attr, D))
69
break;
70
TL = Attr.getModifiedLoc();
71
} else if (MacroQualifiedTypeLoc MDTL =
72
TL.getAs<MacroQualifiedTypeLoc>()) {
73
TL = MDTL.getInnerLoc();
74
} 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();
80
else
81
break;
82
}
83
}
84
85
bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
86
auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
87
if (!OwnershipAttr)
88
return false;
89
90
SourceLocation Loc = OwnershipAttr->getLocation();
91
SourceLocation OrigLoc = Loc;
92
if (MigrateCtx.AttrSet.count(OrigLoc))
93
return true;
94
95
ASTContext &Ctx = MigrateCtx.Pass.Ctx;
96
SourceManager &SM = Ctx.getSourceManager();
97
if (Loc.isMacroID())
98
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
99
StringRef Spell = OwnershipAttr->getKind()->getName();
100
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;
107
108
MigrateCtx.AttrSet.insert(OrigLoc);
109
MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
110
MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
111
112
Attr.Kind = Kind;
113
Attr.Loc = Loc;
114
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
130
if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
131
return hasObjCImpl(ContD);
132
133
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
134
for (const auto *MI : RD->methods()) {
135
if (MI->isOutOfLine())
136
return true;
137
}
138
return false;
139
}
140
141
return isMigratable(cast<Decl>(D->getDeclContext()));
142
}
143
144
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))
149
return ID->getImplementation() != nullptr;
150
if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
151
return CD->getImplementation() != nullptr;
152
return isa<ObjCImplDecl>(ContD);
153
}
154
return false;
155
}
156
157
bool isInMainFile(Decl *D) {
158
if (!D)
159
return false;
160
161
for (auto *I : D->redecls())
162
if (!isInMainFile(I->getLocation()))
163
return false;
164
165
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
179
static 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
195
static 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];
200
if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
201
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);
207
if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc))
208
TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
209
TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
210
diag::err_arc_unsupported_weak_class,
211
Attr.Loc);
212
}
213
}
214
}
215
}
216
217
typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
218
219
static 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;
234
ObjCPropertyAttribute::Kind Attrs = ObjCPropertyAttribute::kind_noattr;
235
for (IndivPropsTy::iterator
236
PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
237
ObjCPropertyDecl *PD = *PI;
238
Attrs = PD->getPropertyAttributesAsWritten();
239
TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
240
if (!TInfo)
241
return;
242
TypeLoc TL = TInfo->getTypeLoc();
243
if (AttributedTypeLoc ATL =
244
TL.getAs<AttributedTypeLoc>()) {
245
ATLs.push_back(std::make_pair(ATL, PD));
246
if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
247
hasWeak = true;
248
} else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
249
hasStrong = true;
250
else
251
return;
252
}
253
}
254
if (ATLs.empty())
255
return;
256
if (hasWeak && hasStrong)
257
return;
258
259
TransformActions &TA = MigrateCtx.Pass.TA;
260
Transaction Trans(TA);
261
262
if (GCAttrsCollector::hasObjCImpl(
263
cast<Decl>(IndProps.front()->getDeclContext()))) {
264
if (hasWeak)
265
MigrateCtx.AtPropsWeak.insert(AtLoc);
266
267
} else {
268
StringRef toAttr = "strong";
269
if (hasWeak) {
270
if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
271
/*AllowOnUnknownClass=*/true))
272
toAttr = "weak";
273
else
274
toAttr = "unsafe_unretained";
275
}
276
if (Attrs & ObjCPropertyAttribute::kind_assign)
277
MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
278
else
279
MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
280
}
281
282
for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
283
SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
284
if (Loc.isMacroID())
285
Loc = MigrateCtx.Pass.Ctx.getSourceManager()
286
.getImmediateExpansionRange(Loc)
287
.getBegin();
288
TA.remove(Loc);
289
TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
290
TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
291
ATLs[i].second->getLocation());
292
MigrateCtx.RemovedAttrSet.insert(Loc);
293
}
294
}
295
296
static void checkAllProps(MigrationContext &MigrateCtx,
297
std::vector<ObjCPropertyDecl *> &AllProps) {
298
typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
299
llvm::DenseMap<SourceLocation, IndivPropsTy> AtProps;
300
301
for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
302
ObjCPropertyDecl *PD = AllProps[i];
303
if (PD->getPropertyAttributesAsWritten() &
304
(ObjCPropertyAttribute::kind_assign |
305
ObjCPropertyAttribute::kind_readonly)) {
306
SourceLocation AtLoc = PD->getAtLoc();
307
if (AtLoc.isInvalid())
308
continue;
309
AtProps[AtLoc].push_back(PD);
310
}
311
}
312
313
for (auto I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
314
SourceLocation AtLoc = I->first;
315
IndivPropsTy &IndProps = I->second;
316
checkAllAtProps(MigrateCtx, AtLoc, IndProps);
317
}
318
}
319
320
void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
321
std::vector<ObjCPropertyDecl *> AllProps;
322
GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
323
MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
324
325
errorForGCAttrsOnNonObjC(MigrateCtx);
326
checkAllProps(MigrateCtx, AllProps);
327
checkWeakGCAttrs(MigrateCtx);
328
}
329
330
void MigrationContext::dumpGCAttrs() {
331
llvm::errs() << "\n################\n";
332
for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
333
GCAttrOccurrence &Attr = GCAttrs[i];
334
llvm::errs() << "KIND: "
335
<< (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
336
llvm::errs() << "\nLOC: ";
337
Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
338
llvm::errs() << "\nTYPE: ";
339
Attr.ModifiedType.dump();
340
if (Attr.Dcl) {
341
llvm::errs() << "DECL:\n";
342
Attr.Dcl->dump();
343
} else {
344
llvm::errs() << "DECL: NONE";
345
}
346
llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
347
llvm::errs() << "\n----------------\n";
348
}
349
llvm::errs() << "\n################\n";
350
}
351
352