1 //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
19 using namespace clang
;
20 using namespace arcmt
;
21 using namespace trans
;
25 /// Collects all the places where GC attributes __strong/__weak occur.
26 class GCAttrsCollector
: public RecursiveASTVisitor
<GCAttrsCollector
> {
27 MigrationContext
&MigrateCtx
;
29 std::vector
<ObjCPropertyDecl
*> &AllProps
;
31 typedef RecursiveASTVisitor
<GCAttrsCollector
> base
;
33 GCAttrsCollector(MigrationContext
&ctx
,
34 std::vector
<ObjCPropertyDecl
*> &AllProps
)
35 : MigrateCtx(ctx
), FullyMigratable(false),
36 AllProps(AllProps
) { }
38 bool shouldWalkTypesOfTypeLocs() const { return false; }
40 bool VisitAttributedTypeLoc(AttributedTypeLoc TL
) {
45 bool TraverseDecl(Decl
*D
) {
46 if (!D
|| D
->isImplicit())
49 SaveAndRestore
<bool> Save(FullyMigratable
, isMigratable(D
));
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());
57 return base::TraverseDecl(D
);
60 void lookForAttribute(Decl
*D
, TypeSourceInfo
*TInfo
) {
63 TypeLoc TL
= TInfo
->getTypeLoc();
65 if (QualifiedTypeLoc QL
= TL
.getAs
<QualifiedTypeLoc
>()) {
66 TL
= QL
.getUnqualifiedLoc();
67 } else if (AttributedTypeLoc Attr
= TL
.getAs
<AttributedTypeLoc
>()) {
68 if (handleAttr(Attr
, D
))
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();
85 bool handleAttr(AttributedTypeLoc TL
, Decl
*D
= nullptr) {
86 auto *OwnershipAttr
= TL
.getAttrAs
<ObjCOwnershipAttr
>();
90 SourceLocation Loc
= OwnershipAttr
->getLocation();
91 SourceLocation OrigLoc
= Loc
;
92 if (MigrateCtx
.AttrSet
.count(OrigLoc
))
95 ASTContext
&Ctx
= MigrateCtx
.Pass
.Ctx
;
96 SourceManager
&SM
= Ctx
.getSourceManager();
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
;
108 MigrateCtx
.AttrSet
.insert(OrigLoc
);
109 MigrateCtx
.GCAttrs
.push_back(MigrationContext::GCAttrOccurrence());
110 MigrationContext::GCAttrOccurrence
&Attr
= MigrateCtx
.GCAttrs
.back();
114 Attr
.ModifiedType
= TL
.getModifiedLoc().getType();
116 Attr
.FullyMigratable
= FullyMigratable
;
120 bool isMigratable(Decl
*D
) {
121 if (isa
<TranslationUnitDecl
>(D
))
127 if (FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
))
128 return FD
->hasBody();
130 if (ObjCContainerDecl
*ContD
= dyn_cast
<ObjCContainerDecl
>(D
))
131 return hasObjCImpl(ContD
);
133 if (CXXRecordDecl
*RD
= dyn_cast
<CXXRecordDecl
>(D
)) {
134 for (const auto *MI
: RD
->methods()) {
135 if (MI
->isOutOfLine())
141 return isMigratable(cast
<Decl
>(D
->getDeclContext()));
144 static bool hasObjCImpl(Decl
*D
) {
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
);
157 bool isInMainFile(Decl
*D
) {
161 for (auto I
: D
->redecls())
162 if (!isInMainFile(I
->getLocation()))
168 bool isInMainFile(SourceLocation Loc
) {
172 SourceManager
&SM
= MigrateCtx
.Pass
.Ctx
.getSourceManager();
173 return SM
.isInFileID(SM
.getExpansionLoc(Loc
), SM
.getMainFileID());
177 } // anonymous namespace
179 static void errorForGCAttrsOnNonObjC(MigrationContext
&MigrateCtx
) {
180 TransformActions
&TA
= MigrateCtx
.Pass
.TA
;
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())
187 if (!Attr
.ModifiedType
->isObjCRetainableType()) {
188 TA
.reportError("GC managed memory will become unmanaged in ARC",
195 static void checkWeakGCAttrs(MigrationContext
&MigrateCtx
) {
196 TransformActions
&TA
= MigrateCtx
.Pass
.TA
;
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())
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
,
217 typedef llvm::TinyPtrVector
<ObjCPropertyDecl
*> IndivPropsTy
;
219 static void checkAllAtProps(MigrationContext
&MigrateCtx
,
220 SourceLocation AtLoc
,
221 IndivPropsTy
&IndProps
) {
222 if (IndProps
.empty())
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())
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();
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
) {
248 } else if (TInfo
->getType().getObjCLifetime() == Qualifiers::OCL_Strong
)
256 if (hasWeak
&& hasStrong
)
259 TransformActions
&TA
= MigrateCtx
.Pass
.TA
;
260 Transaction
Trans(TA
);
262 if (GCAttrsCollector::hasObjCImpl(
263 cast
<Decl
>(IndProps
.front()->getDeclContext()))) {
265 MigrateCtx
.AtPropsWeak
.insert(AtLoc
);
268 StringRef toAttr
= "strong";
270 if (canApplyWeak(MigrateCtx
.Pass
.Ctx
, IndProps
.front()->getType(),
271 /*AllowOnUnknownClass=*/true))
274 toAttr
= "unsafe_unretained";
276 if (Attrs
& ObjCPropertyAttribute::kind_assign
)
277 MigrateCtx
.rewritePropertyAttribute("assign", toAttr
, AtLoc
);
279 MigrateCtx
.addPropertyAttribute(toAttr
, AtLoc
);
282 for (unsigned i
= 0, e
= ATLs
.size(); i
!= e
; ++i
) {
283 SourceLocation Loc
= ATLs
[i
].first
.getAttr()->getLocation();
285 Loc
= MigrateCtx
.Pass
.Ctx
.getSourceManager()
286 .getImmediateExpansionRange(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
);
296 static void checkAllProps(MigrationContext
&MigrateCtx
,
297 std::vector
<ObjCPropertyDecl
*> &AllProps
) {
298 typedef llvm::TinyPtrVector
<ObjCPropertyDecl
*> IndivPropsTy
;
299 llvm::DenseMap
<SourceLocation
, IndivPropsTy
> AtProps
;
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())
309 AtProps
[AtLoc
].push_back(PD
);
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
);
320 void GCAttrsTraverser::traverseTU(MigrationContext
&MigrateCtx
) {
321 std::vector
<ObjCPropertyDecl
*> AllProps
;
322 GCAttrsCollector(MigrateCtx
, AllProps
).TraverseDecl(
323 MigrateCtx
.Pass
.Ctx
.getTranslationUnitDecl());
325 errorForGCAttrsOnNonObjC(MigrateCtx
);
326 checkAllProps(MigrateCtx
, AllProps
);
327 checkWeakGCAttrs(MigrateCtx
);
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();
341 llvm::errs() << "DECL:\n";
344 llvm::errs() << "DECL: NONE";
346 llvm::errs() << "\nMIGRATABLE: " << Attr
.FullyMigratable
;
347 llvm::errs() << "\n----------------\n";
349 llvm::errs() << "\n################\n";