123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "Transforms.h"
- #include "Internals.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/Basic/SourceManager.h"
- #include "clang/Lex/Lexer.h"
- #include "clang/Sema/SemaDiagnostic.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/TinyPtrVector.h"
- #include "llvm/Support/SaveAndRestore.h"
- using namespace clang;
- using namespace arcmt;
- using namespace trans;
- namespace {
- /// Collects all the places where GC attributes __strong/__weak occur.
- class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
- MigrationContext &MigrateCtx;
- bool FullyMigratable;
- std::vector<ObjCPropertyDecl *> &AllProps;
- typedef RecursiveASTVisitor<GCAttrsCollector> base;
- public:
- GCAttrsCollector(MigrationContext &ctx,
- std::vector<ObjCPropertyDecl *> &AllProps)
- : MigrateCtx(ctx), FullyMigratable(false),
- AllProps(AllProps) { }
- bool shouldWalkTypesOfTypeLocs() const { return false; }
- bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
- handleAttr(TL);
- return true;
- }
- bool TraverseDecl(Decl *D) {
- if (!D || D->isImplicit())
- return true;
- SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
- if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
- lookForAttribute(PropD, PropD->getTypeSourceInfo());
- AllProps.push_back(PropD);
- } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
- lookForAttribute(DD, DD->getTypeSourceInfo());
- }
- return base::TraverseDecl(D);
- }
- void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
- if (!TInfo)
- return;
- TypeLoc TL = TInfo->getTypeLoc();
- while (TL) {
- if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
- TL = QL.getUnqualifiedLoc();
- } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
- if (handleAttr(Attr, D))
- break;
- TL = Attr.getModifiedLoc();
- } else if (MacroQualifiedTypeLoc MDTL =
- TL.getAs<MacroQualifiedTypeLoc>()) {
- TL = MDTL.getInnerLoc();
- } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
- TL = Arr.getElementLoc();
- } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
- TL = PT.getPointeeLoc();
- } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
- TL = RT.getPointeeLoc();
- else
- break;
- }
- }
- bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
- auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
- if (!OwnershipAttr)
- return false;
- SourceLocation Loc = OwnershipAttr->getLocation();
- SourceLocation OrigLoc = Loc;
- if (MigrateCtx.AttrSet.count(OrigLoc))
- return true;
- ASTContext &Ctx = MigrateCtx.Pass.Ctx;
- SourceManager &SM = Ctx.getSourceManager();
- if (Loc.isMacroID())
- Loc = SM.getImmediateExpansionRange(Loc).getBegin();
- StringRef Spell = OwnershipAttr->getKind()->getName();
- MigrationContext::GCAttrOccurrence::AttrKind Kind;
- if (Spell == "strong")
- Kind = MigrationContext::GCAttrOccurrence::Strong;
- else if (Spell == "weak")
- Kind = MigrationContext::GCAttrOccurrence::Weak;
- else
- return false;
- MigrateCtx.AttrSet.insert(OrigLoc);
- MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
- MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
- Attr.Kind = Kind;
- Attr.Loc = Loc;
- Attr.ModifiedType = TL.getModifiedLoc().getType();
- Attr.Dcl = D;
- Attr.FullyMigratable = FullyMigratable;
- return true;
- }
- bool isMigratable(Decl *D) {
- if (isa<TranslationUnitDecl>(D))
- return false;
- if (isInMainFile(D))
- return true;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->hasBody();
- if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
- return hasObjCImpl(ContD);
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- for (const auto *MI : RD->methods()) {
- if (MI->isOutOfLine())
- return true;
- }
- return false;
- }
- return isMigratable(cast<Decl>(D->getDeclContext()));
- }
- static bool hasObjCImpl(Decl *D) {
- if (!D)
- return false;
- if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
- return ID->getImplementation() != nullptr;
- if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
- return CD->getImplementation() != nullptr;
- return isa<ObjCImplDecl>(ContD);
- }
- return false;
- }
- bool isInMainFile(Decl *D) {
- if (!D)
- return false;
- for (auto I : D->redecls())
- if (!isInMainFile(I->getLocation()))
- return false;
- return true;
- }
- bool isInMainFile(SourceLocation Loc) {
- if (Loc.isInvalid())
- return false;
- SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
- return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
- }
- };
- } // anonymous namespace
- static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
- TransformActions &TA = MigrateCtx.Pass.TA;
- for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
- MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
- if (Attr.FullyMigratable && Attr.Dcl) {
- if (Attr.ModifiedType.isNull())
- continue;
- if (!Attr.ModifiedType->isObjCRetainableType()) {
- TA.reportError("GC managed memory will become unmanaged in ARC",
- Attr.Loc);
- }
- }
- }
- }
- static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
- TransformActions &TA = MigrateCtx.Pass.TA;
- for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
- MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
- if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
- if (Attr.ModifiedType.isNull() ||
- !Attr.ModifiedType->isObjCRetainableType())
- continue;
- if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
- /*AllowOnUnknownClass=*/true)) {
- Transaction Trans(TA);
- if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc))
- TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
- TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
- diag::err_arc_unsupported_weak_class,
- Attr.Loc);
- }
- }
- }
- }
- typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
- static void checkAllAtProps(MigrationContext &MigrateCtx,
- SourceLocation AtLoc,
- IndivPropsTy &IndProps) {
- if (IndProps.empty())
- return;
- for (IndivPropsTy::iterator
- PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
- QualType T = (*PI)->getType();
- if (T.isNull() || !T->isObjCRetainableType())
- return;
- }
- SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
- bool hasWeak = false, hasStrong = false;
- ObjCPropertyAttribute::Kind Attrs = ObjCPropertyAttribute::kind_noattr;
- for (IndivPropsTy::iterator
- PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
- ObjCPropertyDecl *PD = *PI;
- Attrs = PD->getPropertyAttributesAsWritten();
- TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
- if (!TInfo)
- return;
- TypeLoc TL = TInfo->getTypeLoc();
- if (AttributedTypeLoc ATL =
- TL.getAs<AttributedTypeLoc>()) {
- ATLs.push_back(std::make_pair(ATL, PD));
- if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- hasWeak = true;
- } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
- hasStrong = true;
- else
- return;
- }
- }
- if (ATLs.empty())
- return;
- if (hasWeak && hasStrong)
- return;
- TransformActions &TA = MigrateCtx.Pass.TA;
- Transaction Trans(TA);
- if (GCAttrsCollector::hasObjCImpl(
- cast<Decl>(IndProps.front()->getDeclContext()))) {
- if (hasWeak)
- MigrateCtx.AtPropsWeak.insert(AtLoc);
- } else {
- StringRef toAttr = "strong";
- if (hasWeak) {
- if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
- /*AllowOnUnknownClass=*/true))
- toAttr = "weak";
- else
- toAttr = "unsafe_unretained";
- }
- if (Attrs & ObjCPropertyAttribute::kind_assign)
- MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
- else
- MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
- }
- for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
- SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
- if (Loc.isMacroID())
- Loc = MigrateCtx.Pass.Ctx.getSourceManager()
- .getImmediateExpansionRange(Loc)
- .getBegin();
- TA.remove(Loc);
- TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
- TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
- ATLs[i].second->getLocation());
- MigrateCtx.RemovedAttrSet.insert(Loc);
- }
- }
- static void checkAllProps(MigrationContext &MigrateCtx,
- std::vector<ObjCPropertyDecl *> &AllProps) {
- typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
- llvm::DenseMap<SourceLocation, IndivPropsTy> AtProps;
- for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
- ObjCPropertyDecl *PD = AllProps[i];
- if (PD->getPropertyAttributesAsWritten() &
- (ObjCPropertyAttribute::kind_assign |
- ObjCPropertyAttribute::kind_readonly)) {
- SourceLocation AtLoc = PD->getAtLoc();
- if (AtLoc.isInvalid())
- continue;
- AtProps[AtLoc].push_back(PD);
- }
- }
- for (auto I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
- SourceLocation AtLoc = I->first;
- IndivPropsTy &IndProps = I->second;
- checkAllAtProps(MigrateCtx, AtLoc, IndProps);
- }
- }
- void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
- std::vector<ObjCPropertyDecl *> AllProps;
- GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
- MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
- errorForGCAttrsOnNonObjC(MigrateCtx);
- checkAllProps(MigrateCtx, AllProps);
- checkWeakGCAttrs(MigrateCtx);
- }
- void MigrationContext::dumpGCAttrs() {
- llvm::errs() << "\n################\n";
- for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
- GCAttrOccurrence &Attr = GCAttrs[i];
- llvm::errs() << "KIND: "
- << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
- llvm::errs() << "\nLOC: ";
- Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
- llvm::errs() << "\nTYPE: ";
- Attr.ModifiedType.dump();
- if (Attr.Dcl) {
- llvm::errs() << "DECL:\n";
- Attr.Dcl->dump();
- } else {
- llvm::errs() << "DECL: NONE";
- }
- llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
- llvm::errs() << "\n----------------\n";
- }
- llvm::errs() << "\n################\n";
- }
|