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