Path: blob/main/contrib/llvm-project/clang/lib/ARCMigrate/TransGCAttrs.cpp
35236 views
//===--- TransGCAttrs.cpp - Transformations to ARC mode -------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Transforms.h"9#include "Internals.h"10#include "clang/AST/ASTContext.h"11#include "clang/Basic/SourceManager.h"12#include "clang/Lex/Lexer.h"13#include "clang/Sema/SemaDiagnostic.h"14#include "llvm/ADT/SmallString.h"15#include "llvm/ADT/TinyPtrVector.h"16#include "llvm/Support/SaveAndRestore.h"1718using namespace clang;19using namespace arcmt;20using namespace trans;2122namespace {2324/// Collects all the places where GC attributes __strong/__weak occur.25class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {26MigrationContext &MigrateCtx;27bool FullyMigratable;28std::vector<ObjCPropertyDecl *> &AllProps;2930typedef RecursiveASTVisitor<GCAttrsCollector> base;31public:32GCAttrsCollector(MigrationContext &ctx,33std::vector<ObjCPropertyDecl *> &AllProps)34: MigrateCtx(ctx), FullyMigratable(false),35AllProps(AllProps) { }3637bool shouldWalkTypesOfTypeLocs() const { return false; }3839bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {40handleAttr(TL);41return true;42}4344bool TraverseDecl(Decl *D) {45if (!D || D->isImplicit())46return true;4748SaveAndRestore Save(FullyMigratable, isMigratable(D));4950if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {51lookForAttribute(PropD, PropD->getTypeSourceInfo());52AllProps.push_back(PropD);53} else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {54lookForAttribute(DD, DD->getTypeSourceInfo());55}56return base::TraverseDecl(D);57}5859void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {60if (!TInfo)61return;62TypeLoc TL = TInfo->getTypeLoc();63while (TL) {64if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {65TL = QL.getUnqualifiedLoc();66} else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {67if (handleAttr(Attr, D))68break;69TL = Attr.getModifiedLoc();70} else if (MacroQualifiedTypeLoc MDTL =71TL.getAs<MacroQualifiedTypeLoc>()) {72TL = MDTL.getInnerLoc();73} else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {74TL = Arr.getElementLoc();75} else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {76TL = PT.getPointeeLoc();77} else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())78TL = RT.getPointeeLoc();79else80break;81}82}8384bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {85auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();86if (!OwnershipAttr)87return false;8889SourceLocation Loc = OwnershipAttr->getLocation();90SourceLocation OrigLoc = Loc;91if (MigrateCtx.AttrSet.count(OrigLoc))92return true;9394ASTContext &Ctx = MigrateCtx.Pass.Ctx;95SourceManager &SM = Ctx.getSourceManager();96if (Loc.isMacroID())97Loc = SM.getImmediateExpansionRange(Loc).getBegin();98StringRef Spell = OwnershipAttr->getKind()->getName();99MigrationContext::GCAttrOccurrence::AttrKind Kind;100if (Spell == "strong")101Kind = MigrationContext::GCAttrOccurrence::Strong;102else if (Spell == "weak")103Kind = MigrationContext::GCAttrOccurrence::Weak;104else105return false;106107MigrateCtx.AttrSet.insert(OrigLoc);108MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());109MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();110111Attr.Kind = Kind;112Attr.Loc = Loc;113Attr.ModifiedType = TL.getModifiedLoc().getType();114Attr.Dcl = D;115Attr.FullyMigratable = FullyMigratable;116return true;117}118119bool isMigratable(Decl *D) {120if (isa<TranslationUnitDecl>(D))121return false;122123if (isInMainFile(D))124return true;125126if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))127return FD->hasBody();128129if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))130return hasObjCImpl(ContD);131132if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {133for (const auto *MI : RD->methods()) {134if (MI->isOutOfLine())135return true;136}137return false;138}139140return isMigratable(cast<Decl>(D->getDeclContext()));141}142143static bool hasObjCImpl(Decl *D) {144if (!D)145return false;146if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {147if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))148return ID->getImplementation() != nullptr;149if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))150return CD->getImplementation() != nullptr;151return isa<ObjCImplDecl>(ContD);152}153return false;154}155156bool isInMainFile(Decl *D) {157if (!D)158return false;159160for (auto *I : D->redecls())161if (!isInMainFile(I->getLocation()))162return false;163164return true;165}166167bool isInMainFile(SourceLocation Loc) {168if (Loc.isInvalid())169return false;170171SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();172return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());173}174};175176} // anonymous namespace177178static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {179TransformActions &TA = MigrateCtx.Pass.TA;180181for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {182MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];183if (Attr.FullyMigratable && Attr.Dcl) {184if (Attr.ModifiedType.isNull())185continue;186if (!Attr.ModifiedType->isObjCRetainableType()) {187TA.reportError("GC managed memory will become unmanaged in ARC",188Attr.Loc);189}190}191}192}193194static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {195TransformActions &TA = MigrateCtx.Pass.TA;196197for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {198MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];199if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {200if (Attr.ModifiedType.isNull() ||201!Attr.ModifiedType->isObjCRetainableType())202continue;203if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,204/*AllowOnUnknownClass=*/true)) {205Transaction Trans(TA);206if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc))207TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");208TA.clearDiagnostic(diag::err_arc_weak_no_runtime,209diag::err_arc_unsupported_weak_class,210Attr.Loc);211}212}213}214}215216typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;217218static void checkAllAtProps(MigrationContext &MigrateCtx,219SourceLocation AtLoc,220IndivPropsTy &IndProps) {221if (IndProps.empty())222return;223224for (IndivPropsTy::iterator225PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {226QualType T = (*PI)->getType();227if (T.isNull() || !T->isObjCRetainableType())228return;229}230231SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;232bool hasWeak = false, hasStrong = false;233ObjCPropertyAttribute::Kind Attrs = ObjCPropertyAttribute::kind_noattr;234for (IndivPropsTy::iterator235PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {236ObjCPropertyDecl *PD = *PI;237Attrs = PD->getPropertyAttributesAsWritten();238TypeSourceInfo *TInfo = PD->getTypeSourceInfo();239if (!TInfo)240return;241TypeLoc TL = TInfo->getTypeLoc();242if (AttributedTypeLoc ATL =243TL.getAs<AttributedTypeLoc>()) {244ATLs.push_back(std::make_pair(ATL, PD));245if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {246hasWeak = true;247} else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)248hasStrong = true;249else250return;251}252}253if (ATLs.empty())254return;255if (hasWeak && hasStrong)256return;257258TransformActions &TA = MigrateCtx.Pass.TA;259Transaction Trans(TA);260261if (GCAttrsCollector::hasObjCImpl(262cast<Decl>(IndProps.front()->getDeclContext()))) {263if (hasWeak)264MigrateCtx.AtPropsWeak.insert(AtLoc);265266} else {267StringRef toAttr = "strong";268if (hasWeak) {269if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),270/*AllowOnUnknownClass=*/true))271toAttr = "weak";272else273toAttr = "unsafe_unretained";274}275if (Attrs & ObjCPropertyAttribute::kind_assign)276MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);277else278MigrateCtx.addPropertyAttribute(toAttr, AtLoc);279}280281for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {282SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();283if (Loc.isMacroID())284Loc = MigrateCtx.Pass.Ctx.getSourceManager()285.getImmediateExpansionRange(Loc)286.getBegin();287TA.remove(Loc);288TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);289TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,290ATLs[i].second->getLocation());291MigrateCtx.RemovedAttrSet.insert(Loc);292}293}294295static void checkAllProps(MigrationContext &MigrateCtx,296std::vector<ObjCPropertyDecl *> &AllProps) {297typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;298llvm::DenseMap<SourceLocation, IndivPropsTy> AtProps;299300for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {301ObjCPropertyDecl *PD = AllProps[i];302if (PD->getPropertyAttributesAsWritten() &303(ObjCPropertyAttribute::kind_assign |304ObjCPropertyAttribute::kind_readonly)) {305SourceLocation AtLoc = PD->getAtLoc();306if (AtLoc.isInvalid())307continue;308AtProps[AtLoc].push_back(PD);309}310}311312for (auto I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {313SourceLocation AtLoc = I->first;314IndivPropsTy &IndProps = I->second;315checkAllAtProps(MigrateCtx, AtLoc, IndProps);316}317}318319void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {320std::vector<ObjCPropertyDecl *> AllProps;321GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(322MigrateCtx.Pass.Ctx.getTranslationUnitDecl());323324errorForGCAttrsOnNonObjC(MigrateCtx);325checkAllProps(MigrateCtx, AllProps);326checkWeakGCAttrs(MigrateCtx);327}328329void MigrationContext::dumpGCAttrs() {330llvm::errs() << "\n################\n";331for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {332GCAttrOccurrence &Attr = GCAttrs[i];333llvm::errs() << "KIND: "334<< (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");335llvm::errs() << "\nLOC: ";336Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());337llvm::errs() << "\nTYPE: ";338Attr.ModifiedType.dump();339if (Attr.Dcl) {340llvm::errs() << "DECL:\n";341Attr.Dcl->dump();342} else {343llvm::errs() << "DECL: NONE";344}345llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;346llvm::errs() << "\n----------------\n";347}348llvm::errs() << "\n################\n";349}350351352