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