1*0fca6ea1SDimitry Andric //===--- TransGCAttrs.cpp - Transformations to ARC mode -------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Transforms.h" 100b57cec5SDimitry Andric #include "Internals.h" 110b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 120b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 130b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 140b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h" 150b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 160b57cec5SDimitry Andric #include "llvm/ADT/TinyPtrVector.h" 170b57cec5SDimitry Andric #include "llvm/Support/SaveAndRestore.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric using namespace clang; 200b57cec5SDimitry Andric using namespace arcmt; 210b57cec5SDimitry Andric using namespace trans; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric /// Collects all the places where GC attributes __strong/__weak occur. 260b57cec5SDimitry Andric class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> { 270b57cec5SDimitry Andric MigrationContext &MigrateCtx; 280b57cec5SDimitry Andric bool FullyMigratable; 290b57cec5SDimitry Andric std::vector<ObjCPropertyDecl *> &AllProps; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric typedef RecursiveASTVisitor<GCAttrsCollector> base; 320b57cec5SDimitry Andric public: 330b57cec5SDimitry Andric GCAttrsCollector(MigrationContext &ctx, 340b57cec5SDimitry Andric std::vector<ObjCPropertyDecl *> &AllProps) 350b57cec5SDimitry Andric : MigrateCtx(ctx), FullyMigratable(false), 360b57cec5SDimitry Andric AllProps(AllProps) { } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric bool shouldWalkTypesOfTypeLocs() const { return false; } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric bool VisitAttributedTypeLoc(AttributedTypeLoc TL) { 410b57cec5SDimitry Andric handleAttr(TL); 420b57cec5SDimitry Andric return true; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric bool TraverseDecl(Decl *D) { 460b57cec5SDimitry Andric if (!D || D->isImplicit()) 470b57cec5SDimitry Andric return true; 480b57cec5SDimitry Andric 49bdd1243dSDimitry Andric SaveAndRestore Save(FullyMigratable, isMigratable(D)); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) { 520b57cec5SDimitry Andric lookForAttribute(PropD, PropD->getTypeSourceInfo()); 530b57cec5SDimitry Andric AllProps.push_back(PropD); 540b57cec5SDimitry Andric } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { 550b57cec5SDimitry Andric lookForAttribute(DD, DD->getTypeSourceInfo()); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric return base::TraverseDecl(D); 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) { 610b57cec5SDimitry Andric if (!TInfo) 620b57cec5SDimitry Andric return; 630b57cec5SDimitry Andric TypeLoc TL = TInfo->getTypeLoc(); 640b57cec5SDimitry Andric while (TL) { 650b57cec5SDimitry Andric if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) { 660b57cec5SDimitry Andric TL = QL.getUnqualifiedLoc(); 670b57cec5SDimitry Andric } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) { 680b57cec5SDimitry Andric if (handleAttr(Attr, D)) 690b57cec5SDimitry Andric break; 700b57cec5SDimitry Andric TL = Attr.getModifiedLoc(); 710b57cec5SDimitry Andric } else if (MacroQualifiedTypeLoc MDTL = 720b57cec5SDimitry Andric TL.getAs<MacroQualifiedTypeLoc>()) { 730b57cec5SDimitry Andric TL = MDTL.getInnerLoc(); 740b57cec5SDimitry Andric } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) { 750b57cec5SDimitry Andric TL = Arr.getElementLoc(); 760b57cec5SDimitry Andric } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) { 770b57cec5SDimitry Andric TL = PT.getPointeeLoc(); 780b57cec5SDimitry Andric } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>()) 790b57cec5SDimitry Andric TL = RT.getPointeeLoc(); 800b57cec5SDimitry Andric else 810b57cec5SDimitry Andric break; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) { 860b57cec5SDimitry Andric auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>(); 870b57cec5SDimitry Andric if (!OwnershipAttr) 880b57cec5SDimitry Andric return false; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric SourceLocation Loc = OwnershipAttr->getLocation(); 91e8d8bef9SDimitry Andric SourceLocation OrigLoc = Loc; 92e8d8bef9SDimitry Andric if (MigrateCtx.AttrSet.count(OrigLoc)) 930b57cec5SDimitry Andric return true; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric ASTContext &Ctx = MigrateCtx.Pass.Ctx; 960b57cec5SDimitry Andric SourceManager &SM = Ctx.getSourceManager(); 970b57cec5SDimitry Andric if (Loc.isMacroID()) 980b57cec5SDimitry Andric Loc = SM.getImmediateExpansionRange(Loc).getBegin(); 990b57cec5SDimitry Andric StringRef Spell = OwnershipAttr->getKind()->getName(); 1000b57cec5SDimitry Andric MigrationContext::GCAttrOccurrence::AttrKind Kind; 1010b57cec5SDimitry Andric if (Spell == "strong") 1020b57cec5SDimitry Andric Kind = MigrationContext::GCAttrOccurrence::Strong; 1030b57cec5SDimitry Andric else if (Spell == "weak") 1040b57cec5SDimitry Andric Kind = MigrationContext::GCAttrOccurrence::Weak; 1050b57cec5SDimitry Andric else 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric 108e8d8bef9SDimitry Andric MigrateCtx.AttrSet.insert(OrigLoc); 1090b57cec5SDimitry Andric MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence()); 1100b57cec5SDimitry Andric MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back(); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric Attr.Kind = Kind; 1130b57cec5SDimitry Andric Attr.Loc = Loc; 1140b57cec5SDimitry Andric Attr.ModifiedType = TL.getModifiedLoc().getType(); 1150b57cec5SDimitry Andric Attr.Dcl = D; 1160b57cec5SDimitry Andric Attr.FullyMigratable = FullyMigratable; 1170b57cec5SDimitry Andric return true; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric bool isMigratable(Decl *D) { 1210b57cec5SDimitry Andric if (isa<TranslationUnitDecl>(D)) 1220b57cec5SDimitry Andric return false; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric if (isInMainFile(D)) 1250b57cec5SDimitry Andric return true; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 1280b57cec5SDimitry Andric return FD->hasBody(); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) 1310b57cec5SDimitry Andric return hasObjCImpl(ContD); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { 1340b57cec5SDimitry Andric for (const auto *MI : RD->methods()) { 1350b57cec5SDimitry Andric if (MI->isOutOfLine()) 1360b57cec5SDimitry Andric return true; 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric return false; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric return isMigratable(cast<Decl>(D->getDeclContext())); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric static bool hasObjCImpl(Decl *D) { 1450b57cec5SDimitry Andric if (!D) 1460b57cec5SDimitry Andric return false; 1470b57cec5SDimitry Andric if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) { 1480b57cec5SDimitry Andric if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD)) 1490b57cec5SDimitry Andric return ID->getImplementation() != nullptr; 1500b57cec5SDimitry Andric if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD)) 1510b57cec5SDimitry Andric return CD->getImplementation() != nullptr; 1520b57cec5SDimitry Andric return isa<ObjCImplDecl>(ContD); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric return false; 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric bool isInMainFile(Decl *D) { 1580b57cec5SDimitry Andric if (!D) 1590b57cec5SDimitry Andric return false; 1600b57cec5SDimitry Andric 161bdd1243dSDimitry Andric for (auto *I : D->redecls()) 1620b57cec5SDimitry Andric if (!isInMainFile(I->getLocation())) 1630b57cec5SDimitry Andric return false; 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric return true; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric bool isInMainFile(SourceLocation Loc) { 1690b57cec5SDimitry Andric if (Loc.isInvalid()) 1700b57cec5SDimitry Andric return false; 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager(); 1730b57cec5SDimitry Andric return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID()); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric }; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric } // anonymous namespace 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) { 1800b57cec5SDimitry Andric TransformActions &TA = MigrateCtx.Pass.TA; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) { 1830b57cec5SDimitry Andric MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i]; 1840b57cec5SDimitry Andric if (Attr.FullyMigratable && Attr.Dcl) { 1850b57cec5SDimitry Andric if (Attr.ModifiedType.isNull()) 1860b57cec5SDimitry Andric continue; 1870b57cec5SDimitry Andric if (!Attr.ModifiedType->isObjCRetainableType()) { 1880b57cec5SDimitry Andric TA.reportError("GC managed memory will become unmanaged in ARC", 1890b57cec5SDimitry Andric Attr.Loc); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric static void checkWeakGCAttrs(MigrationContext &MigrateCtx) { 1960b57cec5SDimitry Andric TransformActions &TA = MigrateCtx.Pass.TA; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) { 1990b57cec5SDimitry Andric MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i]; 2000b57cec5SDimitry Andric if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) { 2010b57cec5SDimitry Andric if (Attr.ModifiedType.isNull() || 2020b57cec5SDimitry Andric !Attr.ModifiedType->isObjCRetainableType()) 2030b57cec5SDimitry Andric continue; 2040b57cec5SDimitry Andric if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType, 2050b57cec5SDimitry Andric /*AllowOnUnknownClass=*/true)) { 2060b57cec5SDimitry Andric Transaction Trans(TA); 207e8d8bef9SDimitry Andric if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc)) 2080b57cec5SDimitry Andric TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained"); 2090b57cec5SDimitry Andric TA.clearDiagnostic(diag::err_arc_weak_no_runtime, 2100b57cec5SDimitry Andric diag::err_arc_unsupported_weak_class, 2110b57cec5SDimitry Andric Attr.Loc); 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric static void checkAllAtProps(MigrationContext &MigrateCtx, 2200b57cec5SDimitry Andric SourceLocation AtLoc, 2210b57cec5SDimitry Andric IndivPropsTy &IndProps) { 2220b57cec5SDimitry Andric if (IndProps.empty()) 2230b57cec5SDimitry Andric return; 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric for (IndivPropsTy::iterator 2260b57cec5SDimitry Andric PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { 2270b57cec5SDimitry Andric QualType T = (*PI)->getType(); 2280b57cec5SDimitry Andric if (T.isNull() || !T->isObjCRetainableType()) 2290b57cec5SDimitry Andric return; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs; 2330b57cec5SDimitry Andric bool hasWeak = false, hasStrong = false; 2345ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind Attrs = ObjCPropertyAttribute::kind_noattr; 2350b57cec5SDimitry Andric for (IndivPropsTy::iterator 2360b57cec5SDimitry Andric PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) { 2370b57cec5SDimitry Andric ObjCPropertyDecl *PD = *PI; 2380b57cec5SDimitry Andric Attrs = PD->getPropertyAttributesAsWritten(); 2390b57cec5SDimitry Andric TypeSourceInfo *TInfo = PD->getTypeSourceInfo(); 2400b57cec5SDimitry Andric if (!TInfo) 2410b57cec5SDimitry Andric return; 2420b57cec5SDimitry Andric TypeLoc TL = TInfo->getTypeLoc(); 2430b57cec5SDimitry Andric if (AttributedTypeLoc ATL = 2440b57cec5SDimitry Andric TL.getAs<AttributedTypeLoc>()) { 2450b57cec5SDimitry Andric ATLs.push_back(std::make_pair(ATL, PD)); 2460b57cec5SDimitry Andric if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { 2470b57cec5SDimitry Andric hasWeak = true; 2480b57cec5SDimitry Andric } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) 2490b57cec5SDimitry Andric hasStrong = true; 2500b57cec5SDimitry Andric else 2510b57cec5SDimitry Andric return; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric if (ATLs.empty()) 2550b57cec5SDimitry Andric return; 2560b57cec5SDimitry Andric if (hasWeak && hasStrong) 2570b57cec5SDimitry Andric return; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric TransformActions &TA = MigrateCtx.Pass.TA; 2600b57cec5SDimitry Andric Transaction Trans(TA); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric if (GCAttrsCollector::hasObjCImpl( 2630b57cec5SDimitry Andric cast<Decl>(IndProps.front()->getDeclContext()))) { 2640b57cec5SDimitry Andric if (hasWeak) 265e8d8bef9SDimitry Andric MigrateCtx.AtPropsWeak.insert(AtLoc); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric } else { 2680b57cec5SDimitry Andric StringRef toAttr = "strong"; 2690b57cec5SDimitry Andric if (hasWeak) { 2700b57cec5SDimitry Andric if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(), 2710b57cec5SDimitry Andric /*AllowOnUnknownClass=*/true)) 2720b57cec5SDimitry Andric toAttr = "weak"; 2730b57cec5SDimitry Andric else 2740b57cec5SDimitry Andric toAttr = "unsafe_unretained"; 2750b57cec5SDimitry Andric } 2765ffd83dbSDimitry Andric if (Attrs & ObjCPropertyAttribute::kind_assign) 2770b57cec5SDimitry Andric MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc); 2780b57cec5SDimitry Andric else 2790b57cec5SDimitry Andric MigrateCtx.addPropertyAttribute(toAttr, AtLoc); 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric for (unsigned i = 0, e = ATLs.size(); i != e; ++i) { 2830b57cec5SDimitry Andric SourceLocation Loc = ATLs[i].first.getAttr()->getLocation(); 2840b57cec5SDimitry Andric if (Loc.isMacroID()) 2850b57cec5SDimitry Andric Loc = MigrateCtx.Pass.Ctx.getSourceManager() 2860b57cec5SDimitry Andric .getImmediateExpansionRange(Loc) 2870b57cec5SDimitry Andric .getBegin(); 2880b57cec5SDimitry Andric TA.remove(Loc); 2890b57cec5SDimitry Andric TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc); 2900b57cec5SDimitry Andric TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership, 2910b57cec5SDimitry Andric ATLs[i].second->getLocation()); 292e8d8bef9SDimitry Andric MigrateCtx.RemovedAttrSet.insert(Loc); 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric static void checkAllProps(MigrationContext &MigrateCtx, 2970b57cec5SDimitry Andric std::vector<ObjCPropertyDecl *> &AllProps) { 2980b57cec5SDimitry Andric typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy; 299e8d8bef9SDimitry Andric llvm::DenseMap<SourceLocation, IndivPropsTy> AtProps; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric for (unsigned i = 0, e = AllProps.size(); i != e; ++i) { 3020b57cec5SDimitry Andric ObjCPropertyDecl *PD = AllProps[i]; 3030b57cec5SDimitry Andric if (PD->getPropertyAttributesAsWritten() & 3045ffd83dbSDimitry Andric (ObjCPropertyAttribute::kind_assign | 3055ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_readonly)) { 3060b57cec5SDimitry Andric SourceLocation AtLoc = PD->getAtLoc(); 3070b57cec5SDimitry Andric if (AtLoc.isInvalid()) 3080b57cec5SDimitry Andric continue; 309e8d8bef9SDimitry Andric AtProps[AtLoc].push_back(PD); 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 313e8d8bef9SDimitry Andric for (auto I = AtProps.begin(), E = AtProps.end(); I != E; ++I) { 314e8d8bef9SDimitry Andric SourceLocation AtLoc = I->first; 3150b57cec5SDimitry Andric IndivPropsTy &IndProps = I->second; 3160b57cec5SDimitry Andric checkAllAtProps(MigrateCtx, AtLoc, IndProps); 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) { 3210b57cec5SDimitry Andric std::vector<ObjCPropertyDecl *> AllProps; 3220b57cec5SDimitry Andric GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl( 3230b57cec5SDimitry Andric MigrateCtx.Pass.Ctx.getTranslationUnitDecl()); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric errorForGCAttrsOnNonObjC(MigrateCtx); 3260b57cec5SDimitry Andric checkAllProps(MigrateCtx, AllProps); 3270b57cec5SDimitry Andric checkWeakGCAttrs(MigrateCtx); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric void MigrationContext::dumpGCAttrs() { 3310b57cec5SDimitry Andric llvm::errs() << "\n################\n"; 3320b57cec5SDimitry Andric for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) { 3330b57cec5SDimitry Andric GCAttrOccurrence &Attr = GCAttrs[i]; 3340b57cec5SDimitry Andric llvm::errs() << "KIND: " 3350b57cec5SDimitry Andric << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak"); 3360b57cec5SDimitry Andric llvm::errs() << "\nLOC: "; 3370b57cec5SDimitry Andric Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager()); 3380b57cec5SDimitry Andric llvm::errs() << "\nTYPE: "; 3390b57cec5SDimitry Andric Attr.ModifiedType.dump(); 3400b57cec5SDimitry Andric if (Attr.Dcl) { 3410b57cec5SDimitry Andric llvm::errs() << "DECL:\n"; 3420b57cec5SDimitry Andric Attr.Dcl->dump(); 3430b57cec5SDimitry Andric } else { 3440b57cec5SDimitry Andric llvm::errs() << "DECL: NONE"; 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable; 3470b57cec5SDimitry Andric llvm::errs() << "\n----------------\n"; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric llvm::errs() << "\n################\n"; 3500b57cec5SDimitry Andric } 351