]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/ARCMigrate/TransGCAttrs.cpp
Merge llvm, clang, compiler-rt, libc++, lld, and lldb release_80 branch
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / ARCMigrate / TransGCAttrs.cpp
1 //===--- 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"
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"
19
20 using namespace clang;
21 using namespace arcmt;
22 using namespace trans;
23
24 namespace {
25
26 /// Collects all the places where GC attributes __strong/__weak occur.
27 class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
28   MigrationContext &MigrateCtx;
29   bool FullyMigratable;
30   std::vector<ObjCPropertyDecl *> &AllProps;
31
32   typedef RecursiveASTVisitor<GCAttrsCollector> base;
33 public:
34   GCAttrsCollector(MigrationContext &ctx,
35                    std::vector<ObjCPropertyDecl *> &AllProps)
36     : MigrateCtx(ctx), FullyMigratable(false),
37       AllProps(AllProps) { }
38
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
50     SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
51
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());
57     }
58     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) {
66       if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
67         TL = QL.getUnqualifiedLoc();
68       } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
69         if (handleAttr(Attr, D))
70           break;
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();
78       else
79         break;
80     }
81   }
82
83   bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
84     auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
85     if (!OwnershipAttr)
86       return false;
87
88     SourceLocation Loc = OwnershipAttr->getLocation();
89     unsigned RawLoc = Loc.getRawEncoding();
90     if (MigrateCtx.AttrSet.count(RawLoc))
91       return true;
92
93     ASTContext &Ctx = MigrateCtx.Pass.Ctx;
94     SourceManager &SM = Ctx.getSourceManager();
95     if (Loc.isMacroID())
96       Loc = SM.getImmediateExpansionRange(Loc).getBegin();
97     StringRef Spell = OwnershipAttr->getKind()->getName();
98     MigrationContext::GCAttrOccurrence::AttrKind Kind;
99     if (Spell == "strong")
100       Kind = MigrationContext::GCAttrOccurrence::Strong;
101     else if (Spell == "weak")
102       Kind = MigrationContext::GCAttrOccurrence::Weak;
103     else
104       return false;
105
106     MigrateCtx.AttrSet.insert(RawLoc);
107     MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
108     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
109
110     Attr.Kind = Kind;
111     Attr.Loc = Loc;
112     Attr.ModifiedType = TL.getModifiedLoc().getType();
113     Attr.Dcl = D;
114     Attr.FullyMigratable = FullyMigratable;
115     return true;
116   }
117
118   bool isMigratable(Decl *D) {
119     if (isa<TranslationUnitDecl>(D))
120       return false;
121
122     if (isInMainFile(D))
123       return true;
124
125     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
126       return FD->hasBody();
127
128     if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
129       return hasObjCImpl(ContD);
130
131     if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
132       for (const auto *MI : RD->methods()) {
133         if (MI->isOutOfLine())
134           return true;
135       }
136       return false;
137     }
138
139     return isMigratable(cast<Decl>(D->getDeclContext()));
140   }
141
142   static bool hasObjCImpl(Decl *D) {
143     if (!D)
144       return false;
145     if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
146       if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
147         return ID->getImplementation() != nullptr;
148       if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
149         return CD->getImplementation() != nullptr;
150       return isa<ObjCImplDecl>(ContD);
151     }
152     return false;
153   }
154
155   bool isInMainFile(Decl *D) {
156     if (!D)
157       return false;
158
159     for (auto I : D->redecls())
160       if (!isInMainFile(I->getLocation()))
161         return false;
162
163     return true;
164   }
165
166   bool isInMainFile(SourceLocation Loc) {
167     if (Loc.isInvalid())
168       return false;
169
170     SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
171     return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
172   }
173 };
174
175 } // anonymous namespace
176
177 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
178   TransformActions &TA = MigrateCtx.Pass.TA;
179
180   for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
181     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
182     if (Attr.FullyMigratable && Attr.Dcl) {
183       if (Attr.ModifiedType.isNull())
184         continue;
185       if (!Attr.ModifiedType->isObjCRetainableType()) {
186         TA.reportError("GC managed memory will become unmanaged in ARC",
187                        Attr.Loc);
188       }
189     }
190   }
191 }
192
193 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
194   TransformActions &TA = MigrateCtx.Pass.TA;
195
196   for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
197     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
198     if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
199       if (Attr.ModifiedType.isNull() ||
200           !Attr.ModifiedType->isObjCRetainableType())
201         continue;
202       if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
203                         /*AllowOnUnknownClass=*/true)) {
204         Transaction Trans(TA);
205         if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
206           TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
207         TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
208                            diag::err_arc_unsupported_weak_class,
209                            Attr.Loc);
210       }
211     }
212   }
213 }
214
215 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
216
217 static void checkAllAtProps(MigrationContext &MigrateCtx,
218                             SourceLocation AtLoc,
219                             IndivPropsTy &IndProps) {
220   if (IndProps.empty())
221     return;
222
223   for (IndivPropsTy::iterator
224          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
225     QualType T = (*PI)->getType();
226     if (T.isNull() || !T->isObjCRetainableType())
227       return;
228   }
229
230   SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
231   bool hasWeak = false, hasStrong = false;
232   ObjCPropertyDecl::PropertyAttributeKind
233     Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
234   for (IndivPropsTy::iterator
235          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
236     ObjCPropertyDecl *PD = *PI;
237     Attrs = PD->getPropertyAttributesAsWritten();
238     TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
239     if (!TInfo)
240       return;
241     TypeLoc TL = TInfo->getTypeLoc();
242     if (AttributedTypeLoc ATL =
243             TL.getAs<AttributedTypeLoc>()) {
244       ATLs.push_back(std::make_pair(ATL, PD));
245       if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
246         hasWeak = true;
247       } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
248         hasStrong = true;
249       else
250         return;
251     }
252   }
253   if (ATLs.empty())
254     return;
255   if (hasWeak && hasStrong)
256     return;
257
258   TransformActions &TA = MigrateCtx.Pass.TA;
259   Transaction Trans(TA);
260
261   if (GCAttrsCollector::hasObjCImpl(
262                               cast<Decl>(IndProps.front()->getDeclContext()))) {
263     if (hasWeak)
264       MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
265
266   } else {
267     StringRef toAttr = "strong";
268     if (hasWeak) {
269       if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
270                        /*AllowOnUnkwownClass=*/true))
271         toAttr = "weak";
272       else
273         toAttr = "unsafe_unretained";
274     }
275     if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
276       MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
277     else
278       MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
279   }
280
281   for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
282     SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
283     if (Loc.isMacroID())
284       Loc = MigrateCtx.Pass.Ctx.getSourceManager()
285                 .getImmediateExpansionRange(Loc)
286                 .getBegin();
287     TA.remove(Loc);
288     TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
289     TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
290                        ATLs[i].second->getLocation());
291     MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
292   }
293 }
294
295 static void checkAllProps(MigrationContext &MigrateCtx,
296                           std::vector<ObjCPropertyDecl *> &AllProps) {
297   typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
298   llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
299
300   for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
301     ObjCPropertyDecl *PD = AllProps[i];
302     if (PD->getPropertyAttributesAsWritten() &
303           (ObjCPropertyDecl::OBJC_PR_assign |
304            ObjCPropertyDecl::OBJC_PR_readonly)) {
305       SourceLocation AtLoc = PD->getAtLoc();
306       if (AtLoc.isInvalid())
307         continue;
308       unsigned RawAt = AtLoc.getRawEncoding();
309       AtProps[RawAt].push_back(PD);
310     }
311   }
312
313   for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
314          I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
315     SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
316     IndivPropsTy &IndProps = I->second;
317     checkAllAtProps(MigrateCtx, AtLoc, IndProps);
318   }
319 }
320
321 void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
322   std::vector<ObjCPropertyDecl *> AllProps;
323   GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
324                                   MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
325
326   errorForGCAttrsOnNonObjC(MigrateCtx);
327   checkAllProps(MigrateCtx, AllProps);
328   checkWeakGCAttrs(MigrateCtx);
329 }
330
331 void MigrationContext::dumpGCAttrs() {
332   llvm::errs() << "\n################\n";
333   for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
334     GCAttrOccurrence &Attr = GCAttrs[i];
335     llvm::errs() << "KIND: "
336         << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
337     llvm::errs() << "\nLOC: ";
338     Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
339     llvm::errs() << "\nTYPE: ";
340     Attr.ModifiedType.dump();
341     if (Attr.Dcl) {
342       llvm::errs() << "DECL:\n";
343       Attr.Dcl->dump();
344     } else {
345       llvm::errs() << "DECL: NONE";
346     }
347     llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
348     llvm::errs() << "\n----------------\n";
349   }
350   llvm::errs() << "\n################\n";
351 }