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 #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.getLangOptions(), &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 clearRedundantStrongs(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.Kind == MigrationContext::GCAttrOccurrence::Strong && 192 Attr.FullyMigratable && Attr.Dcl) { 193 TypeSourceInfo *TInfo = 0; 194 if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(Attr.Dcl)) 195 TInfo = DD->getTypeSourceInfo(); 196 else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(Attr.Dcl)) 197 TInfo = PD->getTypeSourceInfo(); 198 if (!TInfo) 199 continue; 200 201 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) { 202 Transaction Trans(TA); 203 TA.remove(Attr.Loc); 204 MigrateCtx.RemovedAttrSet.insert(Attr.Loc.getRawEncoding()); 205 } 206 } 207 } 208 } 209 210 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) { 211 TransformActions &TA = MigrateCtx.Pass.TA; 212 213 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) { 214 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i]; 215 if (Attr.FullyMigratable && Attr.Dcl) { 216 if (Attr.ModifiedType.isNull()) 217 continue; 218 if (!Attr.ModifiedType->isObjCRetainableType()) { 219 TA.reportError("GC managed memory will become unmanaged in ARC", 220 Attr.Loc); 221 } 222 } 223 } 224 } 225 226 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) { 227 TransformActions &TA = MigrateCtx.Pass.TA; 228 229 for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) { 230 MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i]; 231 if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) { 232 if (Attr.ModifiedType.isNull() || 233 !Attr.ModifiedType->isObjCRetainableType()) 234 continue; 235 if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType, 236 /*AllowOnUnknownClass=*/true)) { 237 Transaction Trans(TA); 238 if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding())) 239 TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained"); 240 TA.clearDiagnostic(diag::err_arc_weak_no_runtime, 241 diag::err_arc_unsupported_weak_class, 242 Attr.Loc); 243 } 244 } 245 } 246 } 247 248 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 249 250 static void checkAllAtProps(MigrationContext &MigrateCtx, 251 SourceLocation AtLoc, 252 IndivPropsTy &IndProps) { 253 if (IndProps.empty()) 254 return; 255 256 for (IndivPropsTy::iterator 257 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { 258 QualType T = (*PI)->getType(); 259 if (T.isNull() || !T->isObjCRetainableType()) 260 return; 261 } 262 263 SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs; 264 bool hasWeak = false, hasStrong = false; 265 ObjCPropertyDecl::PropertyAttributeKind 266 Attrs = ObjCPropertyDecl::OBJC_PR_noattr; 267 for (IndivPropsTy::iterator 268 PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { 269 ObjCPropertyDecl *PD = *PI; 270 Attrs = PD->getPropertyAttributesAsWritten(); 271 TypeSourceInfo *TInfo = PD->getTypeSourceInfo(); 272 if (!TInfo) 273 return; 274 TypeLoc TL = TInfo->getTypeLoc(); 275 if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) { 276 ATLs.push_back(std::make_pair(*ATL, PD)); 277 if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { 278 hasWeak = true; 279 } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) 280 hasStrong = true; 281 else 282 return; 283 } 284 } 285 if (ATLs.empty()) 286 return; 287 if (hasWeak && hasStrong) 288 return; 289 290 TransformActions &TA = MigrateCtx.Pass.TA; 291 Transaction Trans(TA); 292 293 if (GCAttrsCollector::hasObjCImpl( 294 cast<Decl>(IndProps.front()->getDeclContext()))) { 295 if (hasWeak) 296 MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding()); 297 298 } else { 299 StringRef toAttr = "strong"; 300 if (hasWeak) { 301 if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(), 302 /*AllowOnUnkwownClass=*/true)) 303 toAttr = "weak"; 304 else 305 toAttr = "unsafe_unretained"; 306 } 307 if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) 308 MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc); 309 else 310 MigrateCtx.addPropertyAttribute(toAttr, AtLoc); 311 } 312 313 for (unsigned i = 0, e = ATLs.size(); i != e; ++i) { 314 SourceLocation Loc = ATLs[i].first.getAttrNameLoc(); 315 if (Loc.isMacroID()) 316 Loc = MigrateCtx.Pass.Ctx.getSourceManager() 317 .getImmediateExpansionRange(Loc).first; 318 TA.remove(Loc); 319 TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc); 320 TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership, 321 ATLs[i].second->getLocation()); 322 MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding()); 323 } 324 } 325 326 static void checkAllProps(MigrationContext &MigrateCtx, 327 std::vector<ObjCPropertyDecl *> &AllProps) { 328 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 329 llvm::DenseMap<unsigned, IndivPropsTy> AtProps; 330 331 for (unsigned i = 0, e = AllProps.size(); i != e; ++i) { 332 ObjCPropertyDecl *PD = AllProps[i]; 333 if (PD->getPropertyAttributesAsWritten() & 334 (ObjCPropertyDecl::OBJC_PR_assign | 335 ObjCPropertyDecl::OBJC_PR_readonly)) { 336 SourceLocation AtLoc = PD->getAtLoc(); 337 if (AtLoc.isInvalid()) 338 continue; 339 unsigned RawAt = AtLoc.getRawEncoding(); 340 AtProps[RawAt].push_back(PD); 341 } 342 } 343 344 for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator 345 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) { 346 SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first); 347 IndivPropsTy &IndProps = I->second; 348 checkAllAtProps(MigrateCtx, AtLoc, IndProps); 349 } 350 } 351 352 void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) { 353 std::vector<ObjCPropertyDecl *> AllProps; 354 GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl( 355 MigrateCtx.Pass.Ctx.getTranslationUnitDecl()); 356 357 clearRedundantStrongs(MigrateCtx); 358 errorForGCAttrsOnNonObjC(MigrateCtx); 359 checkAllProps(MigrateCtx, AllProps); 360 checkWeakGCAttrs(MigrateCtx); 361 } 362 363 void MigrationContext::dumpGCAttrs() { 364 llvm::errs() << "\n################\n"; 365 for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) { 366 GCAttrOccurrence &Attr = GCAttrs[i]; 367 llvm::errs() << "KIND: " 368 << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak"); 369 llvm::errs() << "\nLOC: "; 370 Attr.Loc.dump(Pass.Ctx.getSourceManager()); 371 llvm::errs() << "\nTYPE: "; 372 Attr.ModifiedType.dump(); 373 if (Attr.Dcl) { 374 llvm::errs() << "DECL:\n"; 375 Attr.Dcl->dump(); 376 } else { 377 llvm::errs() << "DECL: NONE"; 378 } 379 llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable; 380 llvm::errs() << "\n----------------\n"; 381 } 382 llvm::errs() << "\n################\n"; 383 } 384