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