TransGCAttrs.cpp revision 280b4ada965f89607684446e826d830f0b8a7864
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 "clang/Analysis/Support/SaveAndRestore.h"
15
16using namespace clang;
17using namespace arcmt;
18using namespace trans;
19
20namespace {
21
22/// \brief Collects all the places where GC attributes __strong/__weak occur.
23class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
24  MigrationContext &MigrateCtx;
25  bool FullyMigratable;
26
27  typedef RecursiveASTVisitor<GCAttrsCollector> base;
28public:
29  explicit GCAttrsCollector(MigrationContext &ctx)
30    : MigrateCtx(ctx), FullyMigratable(false) { }
31
32  bool shouldWalkTypesOfTypeLocs() const { return false; }
33
34  bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
35    handleAttr(TL);
36    return true;
37  }
38
39  bool TraverseDecl(Decl *D) {
40    if (!D || D->isImplicit())
41      return true;
42
43    bool migratable = isMigratable(D);
44    SaveAndRestore<bool> Save(FullyMigratable, migratable);
45
46    if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
47      lookForAttribute(DD, DD->getTypeSourceInfo());
48    else if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D))
49      lookForAttribute(PropD, PropD->getTypeSourceInfo());
50    return base::TraverseDecl(D);
51  }
52
53  void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
54    if (!TInfo)
55      return;
56    TypeLoc TL = TInfo->getTypeLoc();
57    while (TL) {
58      if (const AttributedTypeLoc *Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
59        if (handleAttr(*Attr, D))
60          break;
61        TL = Attr->getModifiedLoc();
62      } if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
63        TL = Arr->getElementLoc();
64      } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
65        TL = PT->getPointeeLoc();
66      } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
67        TL = RT->getPointeeLoc();
68      else
69        break;
70    }
71  }
72
73  bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
74    if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
75      return false;
76
77    SourceLocation Loc = TL.getAttrNameLoc();
78    unsigned RawLoc = Loc.getRawEncoding();
79    if (MigrateCtx.AttrSet.count(RawLoc))
80      return true;
81
82    ASTContext &Ctx = MigrateCtx.Pass.Ctx;
83    SourceManager &SM = Ctx.getSourceManager();
84    llvm::SmallString<32> Buf;
85    bool Invalid = false;
86    StringRef Spell = Lexer::getSpelling(
87                                  SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
88                                  Buf, SM, Ctx.getLangOptions(), &Invalid);
89    if (Invalid)
90      return false;
91    MigrationContext::GCAttrOccurrence::AttrKind Kind;
92    if (Spell == "strong")
93      Kind = MigrationContext::GCAttrOccurrence::Strong;
94    else if (Spell == "weak")
95      Kind = MigrationContext::GCAttrOccurrence::Weak;
96    else
97      return false;
98
99    MigrateCtx.AttrSet.insert(RawLoc);
100    MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
101    MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
102
103    Attr.Kind = Kind;
104    Attr.Loc = SM.getImmediateExpansionRange(Loc).first;
105    Attr.ModifiedType = TL.getModifiedLoc().getType();
106    Attr.Dcl = D;
107    Attr.FullyMigratable = FullyMigratable;
108    return true;
109  }
110
111  bool isMigratable(Decl *D) {
112    if (isa<TranslationUnitDecl>(D))
113      return false;
114
115    if (isInMainFile(D))
116      return true;
117
118    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
119      return FD->hasBody();
120
121    if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
122      if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
123        return ID->getImplementation() != 0;
124      if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
125        return CD->getImplementation() != 0;
126      if (isa<ObjCImplDecl>(ContD))
127        return true;
128      return false;
129    }
130
131    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
132      for (CXXRecordDecl::method_iterator
133             MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
134        if ((*MI)->isOutOfLine())
135          return true;
136      }
137      return false;
138    }
139
140    return isMigratable(cast<Decl>(D->getDeclContext()));
141  }
142
143  bool isInMainFile(Decl *D) {
144    if (!D)
145      return false;
146
147    for (Decl::redecl_iterator
148           I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
149      if (!isInMainFile((*I)->getLocation()))
150        return false;
151
152    return true;
153  }
154
155  bool isInMainFile(SourceLocation Loc) {
156    if (Loc.isInvalid())
157      return false;
158
159    SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
160    return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
161  }
162};
163
164} // anonymous namespace
165
166static void clearRedundantStrongs(MigrationContext &MigrateCtx) {
167  TransformActions &TA = MigrateCtx.Pass.TA;
168
169  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
170    MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
171    if (Attr.Kind == MigrationContext::GCAttrOccurrence::Strong &&
172        Attr.FullyMigratable && Attr.Dcl) {
173      TypeSourceInfo *TInfo = 0;
174      if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(Attr.Dcl))
175        TInfo = DD->getTypeSourceInfo();
176      else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(Attr.Dcl))
177        TInfo = PD->getTypeSourceInfo();
178      if (!TInfo)
179        continue;
180
181      if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
182        Transaction Trans(TA);
183        TA.remove(Attr.Loc);
184      }
185    }
186  }
187}
188
189static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
190  TransformActions &TA = MigrateCtx.Pass.TA;
191
192  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
193    MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
194    if (Attr.FullyMigratable && Attr.Dcl) {
195      if (Attr.ModifiedType.isNull())
196        continue;
197      if (!Attr.ModifiedType->isObjCRetainableType()) {
198        TA.reportError("GC managed memory will become unmanaged in ARC",
199                       Attr.Loc);
200      }
201    }
202  }
203}
204
205void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
206  GCAttrsCollector(MigrateCtx).TraverseDecl(
207                                  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
208
209  clearRedundantStrongs(MigrateCtx);
210  errorForGCAttrsOnNonObjC(MigrateCtx);
211}
212
213void MigrationContext::dumpGCAttrs() {
214  llvm::errs() << "\n################\n";
215  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
216    GCAttrOccurrence &Attr = GCAttrs[i];
217    llvm::errs() << "KIND: "
218        << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
219    llvm::errs() << "\nLOC: ";
220    Attr.Loc.dump(Pass.Ctx.getSourceManager());
221    llvm::errs() << "\nTYPE: ";
222    Attr.ModifiedType.dump();
223    if (Attr.Dcl) {
224      llvm::errs() << "DECL:\n";
225      Attr.Dcl->dump();
226    } else {
227      llvm::errs() << "DECL: NONE";
228    }
229    llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
230    llvm::errs() << "\n----------------\n";
231  }
232  llvm::errs() << "\n################\n";
233}
234