1 //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "Transforms.h"
11 #include "Internals.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/Basic/SourceManager.h"
14 #include "clang/Lex/Lexer.h"
15 #include "clang/Sema/SemaDiagnostic.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/TinyPtrVector.h"
18 #include "llvm/Support/SaveAndRestore.h"
20 using namespace clang;
21 using namespace arcmt;
22 using namespace trans;
26 /// \brief Collects all the places where GC attributes __strong/__weak occur.
27 class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
28 MigrationContext &MigrateCtx;
30 std::vector<ObjCPropertyDecl *> &AllProps;
32 typedef RecursiveASTVisitor<GCAttrsCollector> base;
34 GCAttrsCollector(MigrationContext &ctx,
35 std::vector<ObjCPropertyDecl *> &AllProps)
36 : MigrateCtx(ctx), FullyMigratable(false),
37 AllProps(AllProps) { }
39 bool shouldWalkTypesOfTypeLocs() const { return false; }
41 bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
46 bool TraverseDecl(Decl *D) {
47 if (!D || D->isImplicit())
50 SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
52 if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
53 lookForAttribute(PropD, PropD->getTypeSourceInfo());
54 AllProps.push_back(PropD);
55 } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
56 lookForAttribute(DD, DD->getTypeSourceInfo());
58 return base::TraverseDecl(D);
61 void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
64 TypeLoc TL = TInfo->getTypeLoc();
66 if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
67 TL = QL.getUnqualifiedLoc();
68 } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
69 if (handleAttr(Attr, D))
71 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();
83 bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
84 if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
87 SourceLocation Loc = TL.getAttrNameLoc();
88 unsigned RawLoc = Loc.getRawEncoding();
89 if (MigrateCtx.AttrSet.count(RawLoc))
92 ASTContext &Ctx = MigrateCtx.Pass.Ctx;
93 SourceManager &SM = Ctx.getSourceManager();
95 Loc = SM.getImmediateExpansionRange(Loc).first;
98 StringRef Spell = Lexer::getSpelling(
99 SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
100 Buf, SM, Ctx.getLangOpts(), &Invalid);
103 MigrationContext::GCAttrOccurrence::AttrKind Kind;
104 if (Spell == "strong")
105 Kind = MigrationContext::GCAttrOccurrence::Strong;
106 else if (Spell == "weak")
107 Kind = MigrationContext::GCAttrOccurrence::Weak;
111 MigrateCtx.AttrSet.insert(RawLoc);
112 MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
113 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
117 Attr.ModifiedType = TL.getModifiedLoc().getType();
119 Attr.FullyMigratable = FullyMigratable;
123 bool isMigratable(Decl *D) {
124 if (isa<TranslationUnitDecl>(D))
130 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
131 return FD->hasBody();
133 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
134 return hasObjCImpl(ContD);
136 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
137 for (const auto *MI : RD->methods()) {
138 if (MI->isOutOfLine())
144 return isMigratable(cast<Decl>(D->getDeclContext()));
147 static bool hasObjCImpl(Decl *D) {
150 if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
151 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
152 return ID->getImplementation() != nullptr;
153 if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
154 return CD->getImplementation() != nullptr;
155 return isa<ObjCImplDecl>(ContD);
160 bool isInMainFile(Decl *D) {
164 for (auto I : D->redecls())
165 if (!isInMainFile(I->getLocation()))
171 bool isInMainFile(SourceLocation Loc) {
175 SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
176 return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
180 } // anonymous namespace
182 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
183 TransformActions &TA = MigrateCtx.Pass.TA;
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())
190 if (!Attr.ModifiedType->isObjCRetainableType()) {
191 TA.reportError("GC managed memory will become unmanaged in ARC",
198 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
199 TransformActions &TA = MigrateCtx.Pass.TA;
201 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
202 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
203 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
204 if (Attr.ModifiedType.isNull() ||
205 !Attr.ModifiedType->isObjCRetainableType())
207 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
208 /*AllowOnUnknownClass=*/true)) {
209 Transaction Trans(TA);
210 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
211 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
212 TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
213 diag::err_arc_unsupported_weak_class,
220 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
222 static void checkAllAtProps(MigrationContext &MigrateCtx,
223 SourceLocation AtLoc,
224 IndivPropsTy &IndProps) {
225 if (IndProps.empty())
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())
235 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
236 bool hasWeak = false, hasStrong = false;
237 ObjCPropertyDecl::PropertyAttributeKind
238 Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
239 for (IndivPropsTy::iterator
240 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
241 ObjCPropertyDecl *PD = *PI;
242 Attrs = PD->getPropertyAttributesAsWritten();
243 TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
246 TypeLoc TL = TInfo->getTypeLoc();
247 if (AttributedTypeLoc ATL =
248 TL.getAs<AttributedTypeLoc>()) {
249 ATLs.push_back(std::make_pair(ATL, PD));
250 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
252 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
260 if (hasWeak && hasStrong)
263 TransformActions &TA = MigrateCtx.Pass.TA;
264 Transaction Trans(TA);
266 if (GCAttrsCollector::hasObjCImpl(
267 cast<Decl>(IndProps.front()->getDeclContext()))) {
269 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
272 StringRef toAttr = "strong";
274 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
275 /*AllowOnUnkwownClass=*/true))
278 toAttr = "unsafe_unretained";
280 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
281 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
283 MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
286 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
287 SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
289 Loc = MigrateCtx.Pass.Ctx.getSourceManager()
290 .getImmediateExpansionRange(Loc).first;
292 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
293 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
294 ATLs[i].second->getLocation());
295 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
299 static void checkAllProps(MigrationContext &MigrateCtx,
300 std::vector<ObjCPropertyDecl *> &AllProps) {
301 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
302 llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
304 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
305 ObjCPropertyDecl *PD = AllProps[i];
306 if (PD->getPropertyAttributesAsWritten() &
307 (ObjCPropertyDecl::OBJC_PR_assign |
308 ObjCPropertyDecl::OBJC_PR_readonly)) {
309 SourceLocation AtLoc = PD->getAtLoc();
310 if (AtLoc.isInvalid())
312 unsigned RawAt = AtLoc.getRawEncoding();
313 AtProps[RawAt].push_back(PD);
317 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
318 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
319 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
320 IndivPropsTy &IndProps = I->second;
321 checkAllAtProps(MigrateCtx, AtLoc, IndProps);
325 void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
326 std::vector<ObjCPropertyDecl *> AllProps;
327 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
328 MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
330 errorForGCAttrsOnNonObjC(MigrateCtx);
331 checkAllProps(MigrateCtx, AllProps);
332 checkWeakGCAttrs(MigrateCtx);
335 void MigrationContext::dumpGCAttrs() {
336 llvm::errs() << "\n################\n";
337 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
338 GCAttrOccurrence &Attr = GCAttrs[i];
339 llvm::errs() << "KIND: "
340 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
341 llvm::errs() << "\nLOC: ";
342 Attr.Loc.dump(Pass.Ctx.getSourceManager());
343 llvm::errs() << "\nTYPE: ";
344 Attr.ModifiedType.dump();
346 llvm::errs() << "DECL:\n";
349 llvm::errs() << "DECL: NONE";
351 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
352 llvm::errs() << "\n----------------\n";
354 llvm::errs() << "\n################\n";