TransGCAttrs.cpp revision 471c8b49982d1132f30b0b0da27fef94fd6e4f67
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 20using namespace clang; 21using namespace arcmt; 22using namespace trans; 23 24namespace { 25 26/// \brief Collects all the places where GC attributes __strong/__weak occur. 27class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> { 28 MigrationContext &MigrateCtx; 29 bool FullyMigratable; 30 std::vector<ObjCPropertyDecl *> &AllProps; 31 32 typedef RecursiveASTVisitor<GCAttrsCollector> base; 33public: 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 187static 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 203static 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 225typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 226 227static 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 303static 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 329void 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 339void 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} 360