]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/lib/ARCMigrate/TransGCAttrs.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / lib / ARCMigrate / TransGCAttrs.cpp
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<bool> 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     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();
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(RawLoc);
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.getRawEncoding()))
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   ObjCPropertyDecl::PropertyAttributeKind
235     Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
236   for (IndivPropsTy::iterator
237          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
238     ObjCPropertyDecl *PD = *PI;
239     Attrs = PD->getPropertyAttributesAsWritten();
240     TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
241     if (!TInfo)
242       return;
243     TypeLoc TL = TInfo->getTypeLoc();
244     if (AttributedTypeLoc ATL =
245             TL.getAs<AttributedTypeLoc>()) {
246       ATLs.push_back(std::make_pair(ATL, PD));
247       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(),
272                        /*AllowOnUnknownClass=*/true))
273         toAttr = "weak";
274       else
275         toAttr = "unsafe_unretained";
276     }
277     if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
278       MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
279     else
280       MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
281   }
282
283   for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
284     SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
285     if (Loc.isMacroID())
286       Loc = MigrateCtx.Pass.Ctx.getSourceManager()
287                 .getImmediateExpansionRange(Loc)
288                 .getBegin();
289     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());
293     MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
294   }
295 }
296
297 static 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() &
305           (ObjCPropertyDecl::OBJC_PR_assign |
306            ObjCPropertyDecl::OBJC_PR_readonly)) {
307       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
323 void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
324   std::vector<ObjCPropertyDecl *> AllProps;
325   GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
326                                   MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
327
328   errorForGCAttrsOnNonObjC(MigrateCtx);
329   checkAllProps(MigrateCtx, AllProps);
330   checkWeakGCAttrs(MigrateCtx);
331 }
332
333 void MigrationContext::dumpGCAttrs() {
334   llvm::errs() << "\n################\n";
335   for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
336     GCAttrOccurrence &Attr = GCAttrs[i];
337     llvm::errs() << "KIND: "
338         << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
339     llvm::errs() << "\nLOC: ";
340     Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
341     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";
353 }