1234287Sdim//===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===// 2234287Sdim// 3234287Sdim// The LLVM Compiler Infrastructure 4234287Sdim// 5234287Sdim// This file is distributed under the University of Illinois Open Source 6234287Sdim// License. See LICENSE.TXT for details. 7234287Sdim// 8234287Sdim//===----------------------------------------------------------------------===// 9234287Sdim 10234287Sdim#include "Transforms.h" 11234287Sdim#include "Internals.h" 12245431Sdim#include "clang/AST/ASTContext.h" 13245431Sdim#include "clang/Basic/SourceManager.h" 14234287Sdim#include "clang/Lex/Lexer.h" 15234287Sdim#include "clang/Sema/SemaDiagnostic.h" 16234287Sdim#include "llvm/ADT/SmallString.h" 17234287Sdim#include "llvm/ADT/TinyPtrVector.h" 18245431Sdim#include "llvm/Support/SaveAndRestore.h" 19234287Sdim 20234287Sdimusing namespace clang; 21234287Sdimusing namespace arcmt; 22234287Sdimusing namespace trans; 23234287Sdim 24234287Sdimnamespace { 25234287Sdim 26234287Sdim/// \brief Collects all the places where GC attributes __strong/__weak occur. 27234287Sdimclass GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> { 28234287Sdim MigrationContext &MigrateCtx; 29234287Sdim bool FullyMigratable; 30234287Sdim std::vector<ObjCPropertyDecl *> &AllProps; 31234287Sdim 32234287Sdim typedef RecursiveASTVisitor<GCAttrsCollector> base; 33234287Sdimpublic: 34234287Sdim GCAttrsCollector(MigrationContext &ctx, 35234287Sdim std::vector<ObjCPropertyDecl *> &AllProps) 36234287Sdim : MigrateCtx(ctx), FullyMigratable(false), 37234287Sdim AllProps(AllProps) { } 38234287Sdim 39234287Sdim bool shouldWalkTypesOfTypeLocs() const { return false; } 40234287Sdim 41234287Sdim bool VisitAttributedTypeLoc(AttributedTypeLoc TL) { 42234287Sdim handleAttr(TL); 43234287Sdim return true; 44234287Sdim } 45234287Sdim 46234287Sdim bool TraverseDecl(Decl *D) { 47234287Sdim if (!D || D->isImplicit()) 48234287Sdim return true; 49234287Sdim 50234287Sdim SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D)); 51234287Sdim 52234287Sdim if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) { 53234287Sdim lookForAttribute(PropD, PropD->getTypeSourceInfo()); 54234287Sdim AllProps.push_back(PropD); 55234287Sdim } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { 56234287Sdim lookForAttribute(DD, DD->getTypeSourceInfo()); 57234287Sdim } 58234287Sdim return base::TraverseDecl(D); 59234287Sdim } 60234287Sdim 61234287Sdim void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) { 62234287Sdim if (!TInfo) 63234287Sdim return; 64234287Sdim TypeLoc TL = TInfo->getTypeLoc(); 65234287Sdim while (TL) { 66252723Sdim if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) { 67252723Sdim TL = QL.getUnqualifiedLoc(); 68252723Sdim } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) { 69252723Sdim if (handleAttr(Attr, D)) 70234287Sdim break; 71252723Sdim TL = Attr.getModifiedLoc(); 72252723Sdim } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) { 73252723Sdim TL = Arr.getElementLoc(); 74252723Sdim } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) { 75252723Sdim TL = PT.getPointeeLoc(); 76252723Sdim } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>()) 77252723Sdim TL = RT.getPointeeLoc(); 78234287Sdim else 79234287Sdim break; 80234287Sdim } 81234287Sdim } 82234287Sdim 83234287Sdim bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) { 84234287Sdim if (TL.getAttrKind() != AttributedType::attr_objc_ownership) 85234287Sdim return false; 86234287Sdim 87234287Sdim SourceLocation Loc = TL.getAttrNameLoc(); 88234287Sdim unsigned RawLoc = Loc.getRawEncoding(); 89234287Sdim if (MigrateCtx.AttrSet.count(RawLoc)) 90234287Sdim return true; 91234287Sdim 92234287Sdim ASTContext &Ctx = MigrateCtx.Pass.Ctx; 93234287Sdim SourceManager &SM = Ctx.getSourceManager(); 94234287Sdim if (Loc.isMacroID()) 95234287Sdim Loc = SM.getImmediateExpansionRange(Loc).first; 96234287Sdim SmallString<32> Buf; 97234287Sdim bool Invalid = false; 98234287Sdim StringRef Spell = Lexer::getSpelling( 99234287Sdim SM.getSpellingLoc(TL.getAttrEnumOperandLoc()), 100234287Sdim Buf, SM, Ctx.getLangOpts(), &Invalid); 101234287Sdim if (Invalid) 102234287Sdim return false; 103234287Sdim MigrationContext::GCAttrOccurrence::AttrKind Kind; 104234287Sdim if (Spell == "strong") 105234287Sdim Kind = MigrationContext::GCAttrOccurrence::Strong; 106234287Sdim else if (Spell == "weak") 107234287Sdim Kind = MigrationContext::GCAttrOccurrence::Weak; 108234287Sdim else 109234287Sdim return false; 110234287Sdim 111234287Sdim MigrateCtx.AttrSet.insert(RawLoc); 112234287Sdim MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence()); 113234287Sdim MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back(); 114234287Sdim 115234287Sdim Attr.Kind = Kind; 116234287Sdim Attr.Loc = Loc; 117234287Sdim Attr.ModifiedType = TL.getModifiedLoc().getType(); 118234287Sdim Attr.Dcl = D; 119234287Sdim Attr.FullyMigratable = FullyMigratable; 120234287Sdim return true; 121234287Sdim } 122234287Sdim 123234287Sdim bool isMigratable(Decl *D) { 124234287Sdim if (isa<TranslationUnitDecl>(D)) 125234287Sdim return false; 126234287Sdim 127234287Sdim if (isInMainFile(D)) 128234287Sdim return true; 129234287Sdim 130234287Sdim if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 131234287Sdim return FD->hasBody(); 132234287Sdim 133234287Sdim if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) 134234287Sdim return hasObjCImpl(ContD); 135234287Sdim 136234287Sdim if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { 137234287Sdim for (CXXRecordDecl::method_iterator 138234287Sdim MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) { 139245431Sdim if (MI->isOutOfLine()) 140234287Sdim return true; 141234287Sdim } 142234287Sdim return false; 143234287Sdim } 144234287Sdim 145234287Sdim return isMigratable(cast<Decl>(D->getDeclContext())); 146234287Sdim } 147234287Sdim 148234287Sdim static bool hasObjCImpl(Decl *D) { 149234287Sdim if (!D) 150234287Sdim return false; 151234287Sdim if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) { 152234287Sdim if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD)) 153234287Sdim return ID->getImplementation() != 0; 154234287Sdim if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD)) 155234287Sdim return CD->getImplementation() != 0; 156234287Sdim if (isa<ObjCImplDecl>(ContD)) 157234287Sdim return true; 158234287Sdim return false; 159234287Sdim } 160234287Sdim return false; 161234287Sdim } 162234287Sdim 163234287Sdim bool isInMainFile(Decl *D) { 164234287Sdim if (!D) 165234287Sdim return false; 166234287Sdim 167234287Sdim for (Decl::redecl_iterator 168234287Sdim I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I) 169245431Sdim if (!isInMainFile(I->getLocation())) 170234287Sdim return false; 171234287Sdim 172234287Sdim return true; 173234287Sdim } 174234287Sdim 175234287Sdim bool isInMainFile(SourceLocation Loc) { 176234287Sdim if (Loc.isInvalid()) 177234287Sdim return false; 178234287Sdim 179234287Sdim SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager(); 180234287Sdim return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID()); 181234287Sdim } 182234287Sdim}; 183234287Sdim 184234287Sdim} // anonymous namespace 185234287Sdim 186234287Sdimstatic void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) { 187234287Sdim TransformActions &TA = MigrateCtx.Pass.TA; 188234287Sdim 189234287Sdim for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) { 190234287Sdim MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i]; 191234287Sdim if (Attr.FullyMigratable && Attr.Dcl) { 192234287Sdim if (Attr.ModifiedType.isNull()) 193234287Sdim continue; 194234287Sdim if (!Attr.ModifiedType->isObjCRetainableType()) { 195234287Sdim TA.reportError("GC managed memory will become unmanaged in ARC", 196234287Sdim Attr.Loc); 197234287Sdim } 198234287Sdim } 199234287Sdim } 200234287Sdim} 201234287Sdim 202234287Sdimstatic void checkWeakGCAttrs(MigrationContext &MigrateCtx) { 203234287Sdim TransformActions &TA = MigrateCtx.Pass.TA; 204234287Sdim 205234287Sdim for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) { 206234287Sdim MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i]; 207234287Sdim if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) { 208234287Sdim if (Attr.ModifiedType.isNull() || 209234287Sdim !Attr.ModifiedType->isObjCRetainableType()) 210234287Sdim continue; 211234287Sdim if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType, 212234287Sdim /*AllowOnUnknownClass=*/true)) { 213234287Sdim Transaction Trans(TA); 214234287Sdim if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding())) 215234287Sdim TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained"); 216234287Sdim TA.clearDiagnostic(diag::err_arc_weak_no_runtime, 217234287Sdim diag::err_arc_unsupported_weak_class, 218234287Sdim Attr.Loc); 219234287Sdim } 220234287Sdim } 221234287Sdim } 222234287Sdim} 223234287Sdim 224234287Sdimtypedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 225234287Sdim 226234287Sdimstatic void checkAllAtProps(MigrationContext &MigrateCtx, 227234287Sdim SourceLocation AtLoc, 228234287Sdim IndivPropsTy &IndProps) { 229234287Sdim if (IndProps.empty()) 230234287Sdim return; 231234287Sdim 232234287Sdim for (IndivPropsTy::iterator 233234287Sdim PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { 234234287Sdim QualType T = (*PI)->getType(); 235234287Sdim if (T.isNull() || !T->isObjCRetainableType()) 236234287Sdim return; 237234287Sdim } 238234287Sdim 239234287Sdim SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs; 240234287Sdim bool hasWeak = false, hasStrong = false; 241234287Sdim ObjCPropertyDecl::PropertyAttributeKind 242234287Sdim Attrs = ObjCPropertyDecl::OBJC_PR_noattr; 243234287Sdim for (IndivPropsTy::iterator 244234287Sdim PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { 245234287Sdim ObjCPropertyDecl *PD = *PI; 246234287Sdim Attrs = PD->getPropertyAttributesAsWritten(); 247234287Sdim TypeSourceInfo *TInfo = PD->getTypeSourceInfo(); 248234287Sdim if (!TInfo) 249234287Sdim return; 250234287Sdim TypeLoc TL = TInfo->getTypeLoc(); 251252723Sdim if (AttributedTypeLoc ATL = 252252723Sdim TL.getAs<AttributedTypeLoc>()) { 253252723Sdim ATLs.push_back(std::make_pair(ATL, PD)); 254234287Sdim if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { 255234287Sdim hasWeak = true; 256234287Sdim } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) 257234287Sdim hasStrong = true; 258234287Sdim else 259234287Sdim return; 260234287Sdim } 261234287Sdim } 262234287Sdim if (ATLs.empty()) 263234287Sdim return; 264234287Sdim if (hasWeak && hasStrong) 265234287Sdim return; 266234287Sdim 267234287Sdim TransformActions &TA = MigrateCtx.Pass.TA; 268234287Sdim Transaction Trans(TA); 269234287Sdim 270234287Sdim if (GCAttrsCollector::hasObjCImpl( 271234287Sdim cast<Decl>(IndProps.front()->getDeclContext()))) { 272234287Sdim if (hasWeak) 273234287Sdim MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding()); 274234287Sdim 275234287Sdim } else { 276234287Sdim StringRef toAttr = "strong"; 277234287Sdim if (hasWeak) { 278234287Sdim if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(), 279234287Sdim /*AllowOnUnkwownClass=*/true)) 280234287Sdim toAttr = "weak"; 281234287Sdim else 282234287Sdim toAttr = "unsafe_unretained"; 283234287Sdim } 284234287Sdim if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) 285234287Sdim MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc); 286234287Sdim else 287234287Sdim MigrateCtx.addPropertyAttribute(toAttr, AtLoc); 288234287Sdim } 289234287Sdim 290234287Sdim for (unsigned i = 0, e = ATLs.size(); i != e; ++i) { 291234287Sdim SourceLocation Loc = ATLs[i].first.getAttrNameLoc(); 292234287Sdim if (Loc.isMacroID()) 293234287Sdim Loc = MigrateCtx.Pass.Ctx.getSourceManager() 294234287Sdim .getImmediateExpansionRange(Loc).first; 295234287Sdim TA.remove(Loc); 296234287Sdim TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc); 297234287Sdim TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership, 298234287Sdim ATLs[i].second->getLocation()); 299234287Sdim MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding()); 300234287Sdim } 301234287Sdim} 302234287Sdim 303234287Sdimstatic void checkAllProps(MigrationContext &MigrateCtx, 304234287Sdim std::vector<ObjCPropertyDecl *> &AllProps) { 305234287Sdim typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 306234287Sdim llvm::DenseMap<unsigned, IndivPropsTy> AtProps; 307234287Sdim 308234287Sdim for (unsigned i = 0, e = AllProps.size(); i != e; ++i) { 309234287Sdim ObjCPropertyDecl *PD = AllProps[i]; 310234287Sdim if (PD->getPropertyAttributesAsWritten() & 311234287Sdim (ObjCPropertyDecl::OBJC_PR_assign | 312234287Sdim ObjCPropertyDecl::OBJC_PR_readonly)) { 313234287Sdim SourceLocation AtLoc = PD->getAtLoc(); 314234287Sdim if (AtLoc.isInvalid()) 315234287Sdim continue; 316234287Sdim unsigned RawAt = AtLoc.getRawEncoding(); 317234287Sdim AtProps[RawAt].push_back(PD); 318234287Sdim } 319234287Sdim } 320234287Sdim 321234287Sdim for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator 322234287Sdim I = AtProps.begin(), E = AtProps.end(); I != E; ++I) { 323234287Sdim SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first); 324234287Sdim IndivPropsTy &IndProps = I->second; 325234287Sdim checkAllAtProps(MigrateCtx, AtLoc, IndProps); 326234287Sdim } 327234287Sdim} 328234287Sdim 329234287Sdimvoid GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) { 330234287Sdim std::vector<ObjCPropertyDecl *> AllProps; 331234287Sdim GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl( 332234287Sdim MigrateCtx.Pass.Ctx.getTranslationUnitDecl()); 333234287Sdim 334234287Sdim errorForGCAttrsOnNonObjC(MigrateCtx); 335234287Sdim checkAllProps(MigrateCtx, AllProps); 336234287Sdim checkWeakGCAttrs(MigrateCtx); 337234287Sdim} 338234287Sdim 339234287Sdimvoid MigrationContext::dumpGCAttrs() { 340234287Sdim llvm::errs() << "\n################\n"; 341234287Sdim for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) { 342234287Sdim GCAttrOccurrence &Attr = GCAttrs[i]; 343234287Sdim llvm::errs() << "KIND: " 344234287Sdim << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak"); 345234287Sdim llvm::errs() << "\nLOC: "; 346234287Sdim Attr.Loc.dump(Pass.Ctx.getSourceManager()); 347234287Sdim llvm::errs() << "\nTYPE: "; 348234287Sdim Attr.ModifiedType.dump(); 349234287Sdim if (Attr.Dcl) { 350234287Sdim llvm::errs() << "DECL:\n"; 351234287Sdim Attr.Dcl->dump(); 352234287Sdim } else { 353234287Sdim llvm::errs() << "DECL: NONE"; 354234287Sdim } 355234287Sdim llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable; 356234287Sdim llvm::errs() << "\n----------------\n"; 357234287Sdim } 358234287Sdim llvm::errs() << "\n################\n"; 359234287Sdim} 360