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