Path: blob/main/contrib/llvm-project/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
35236 views
//===--- TransBlockObjCVariable.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//===----------------------------------------------------------------------===//7//8// rewriteBlockObjCVariable:9//10// Adding __block to an obj-c variable could be either because the variable11// is used for output storage or the user wanted to break a retain cycle.12// This transformation checks whether a reference of the variable for the block13// is actually needed (it is assigned to or its address is taken) or not.14// If the reference is not needed it will assume __block was added to break a15// cycle so it will remove '__block' and add __weak/__unsafe_unretained.16// e.g17//18// __block Foo *x;19// bar(^ { [x cake]; });20// ---->21// __weak Foo *x;22// bar(^ { [x cake]; });23//24//===----------------------------------------------------------------------===//2526#include "Transforms.h"27#include "Internals.h"28#include "clang/AST/ASTContext.h"29#include "clang/AST/Attr.h"30#include "clang/Basic/SourceManager.h"3132using namespace clang;33using namespace arcmt;34using namespace trans;3536namespace {3738class RootBlockObjCVarRewriter :39public RecursiveASTVisitor<RootBlockObjCVarRewriter> {40llvm::DenseSet<VarDecl *> &VarsToChange;4142class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {43VarDecl *Var;4445typedef RecursiveASTVisitor<BlockVarChecker> base;46public:47BlockVarChecker(VarDecl *var) : Var(var) { }4849bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {50if (DeclRefExpr *51ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {52if (ref->getDecl() == Var) {53if (castE->getCastKind() == CK_LValueToRValue)54return true; // Using the value of the variable.55if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&56Var->getASTContext().getLangOpts().CPlusPlus)57return true; // Binding to const C++ reference.58}59}6061return base::TraverseImplicitCastExpr(castE);62}6364bool VisitDeclRefExpr(DeclRefExpr *E) {65if (E->getDecl() == Var)66return false; // The reference of the variable, and not just its value,67// is needed.68return true;69}70};7172public:73RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)74: VarsToChange(VarsToChange) { }7576bool VisitBlockDecl(BlockDecl *block) {77SmallVector<VarDecl *, 4> BlockVars;7879for (const auto &I : block->captures()) {80VarDecl *var = I.getVariable();81if (I.isByRef() &&82var->getType()->isObjCObjectPointerType() &&83isImplicitStrong(var->getType())) {84BlockVars.push_back(var);85}86}8788for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {89VarDecl *var = BlockVars[i];9091BlockVarChecker checker(var);92bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());93if (onlyValueOfVarIsNeeded)94VarsToChange.insert(var);95else96VarsToChange.erase(var);97}9899return true;100}101102private:103bool isImplicitStrong(QualType ty) {104if (isa<AttributedType>(ty.getTypePtr()))105return false;106return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;107}108};109110class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {111llvm::DenseSet<VarDecl *> &VarsToChange;112113public:114BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)115: VarsToChange(VarsToChange) { }116117bool TraverseBlockDecl(BlockDecl *block) {118RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);119return true;120}121};122123} // anonymous namespace124125void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {126MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;127llvm::DenseSet<VarDecl *> VarsToChange;128129BlockObjCVarRewriter trans(VarsToChange);130trans.TraverseStmt(BodyCtx.getTopStmt());131132for (llvm::DenseSet<VarDecl *>::iterator133I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {134VarDecl *var = *I;135BlocksAttr *attr = var->getAttr<BlocksAttr>();136if(!attr)137continue;138bool useWeak = canApplyWeak(Pass.Ctx, var->getType());139SourceManager &SM = Pass.Ctx.getSourceManager();140Transaction Trans(Pass.TA);141Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),142"__block",143useWeak ? "__weak" : "__unsafe_unretained");144}145}146147148