//===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H #define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H #include "clang/AST/ParentMap.h" #include "clang/AST/RecursiveASTVisitor.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/SaveAndRestore.h" namespace clang { class Decl; class Stmt; class BlockDecl; class ObjCMethodDecl; class FunctionDecl; namespace arcmt { class MigrationPass; namespace trans { class MigrationContext; //===----------------------------------------------------------------------===// // Transformations. //===----------------------------------------------------------------------===// void rewriteAutoreleasePool(MigrationPass &pass); void rewriteUnbridgedCasts(MigrationPass &pass); void makeAssignARCSafe(MigrationPass &pass); void removeRetainReleaseDeallocFinalize(MigrationPass &pass); void removeZeroOutPropsInDeallocFinalize(MigrationPass &pass); void rewriteUnusedInitDelegate(MigrationPass &pass); void checkAPIUses(MigrationPass &pass); void removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass); class BodyContext { MigrationContext &MigrateCtx; ParentMap PMap; Stmt *TopStmt; public: BodyContext(MigrationContext &MigrateCtx, Stmt *S) : MigrateCtx(MigrateCtx), PMap(S), TopStmt(S) {} MigrationContext &getMigrationContext() { return MigrateCtx; } ParentMap &getParentMap() { return PMap; } Stmt *getTopStmt() { return TopStmt; } }; class ObjCImplementationContext { MigrationContext &MigrateCtx; ObjCImplementationDecl *ImpD; public: ObjCImplementationContext(MigrationContext &MigrateCtx, ObjCImplementationDecl *D) : MigrateCtx(MigrateCtx), ImpD(D) {} MigrationContext &getMigrationContext() { return MigrateCtx; } ObjCImplementationDecl *getImplementationDecl() { return ImpD; } }; class ASTTraverser { public: virtual ~ASTTraverser(); virtual void traverseTU(MigrationContext &MigrateCtx) { } virtual void traverseBody(BodyContext &BodyCtx) { } virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) {} }; class MigrationContext { std::vector<ASTTraverser *> Traversers; public: MigrationPass &Pass; struct GCAttrOccurrence { enum AttrKind { Weak, Strong } Kind; SourceLocation Loc; QualType ModifiedType; Decl *Dcl; /// \brief true if the attribute is owned, e.g. it is in a body and not just /// in an interface. bool FullyMigratable; }; std::vector<GCAttrOccurrence> GCAttrs; llvm::DenseSet<unsigned> AttrSet; llvm::DenseSet<unsigned> RemovedAttrSet; /// \brief Set of raw '@' locations for 'assign' properties group that contain /// GC __weak. llvm::DenseSet<unsigned> AtPropsWeak; explicit MigrationContext(MigrationPass &pass) : Pass(pass) {} ~MigrationContext(); typedef std::vector<ASTTraverser *>::iterator traverser_iterator; traverser_iterator traversers_begin() { return Traversers.begin(); } traverser_iterator traversers_end() { return Traversers.end(); } void addTraverser(ASTTraverser *traverser) { Traversers.push_back(traverser); } bool isGCOwnedNonObjC(QualType T); bool removePropertyAttribute(StringRef fromAttr, SourceLocation atLoc) { return rewritePropertyAttribute(fromAttr, StringRef(), atLoc); } bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc); bool addPropertyAttribute(StringRef attr, SourceLocation atLoc); void traverse(TranslationUnitDecl *TU); void dumpGCAttrs(); }; class PropertyRewriteTraverser : public ASTTraverser { public: void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) override; }; class BlockObjCVariableTraverser : public ASTTraverser { public: void traverseBody(BodyContext &BodyCtx) override; }; class ProtectedScopeTraverser : public ASTTraverser { public: void traverseBody(BodyContext &BodyCtx) override; }; // GC transformations class GCAttrsTraverser : public ASTTraverser { public: void traverseTU(MigrationContext &MigrateCtx) override; }; class GCCollectableCallsTraverser : public ASTTraverser { public: void traverseBody(BodyContext &BodyCtx) override; }; //===----------------------------------------------------------------------===// // Helpers. //===----------------------------------------------------------------------===// /// \brief Determine whether we can add weak to the given type. bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass = false); bool isPlusOneAssign(const BinaryOperator *E); bool isPlusOne(const Expr *E); /// \brief 'Loc' is the end of a statement range. This returns the location /// immediately after the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx, bool IsDecl = false); /// \brief 'Loc' is the end of a statement range. This returns the location /// of the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx, bool IsDecl = false); bool hasSideEffects(Expr *E, ASTContext &Ctx); bool isGlobalVar(Expr *E); /// \brief Returns "nil" or "0" if 'nil' macro is not actually defined. StringRef getNilString(ASTContext &Ctx); template <typename BODY_TRANS> class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > { MigrationPass &Pass; Decl *ParentD; typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base; public: BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(nullptr) { } bool TraverseStmt(Stmt *rootS) { if (rootS) BODY_TRANS(Pass).transformBody(rootS, ParentD); return true; } bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { SaveAndRestore<Decl *> SetParent(ParentD, D); return base::TraverseObjCMethodDecl(D); } }; typedef llvm::DenseSet<Expr *> ExprSet; void clearRefsIn(Stmt *S, ExprSet &refs); template <typename iterator> void clearRefsIn(iterator begin, iterator end, ExprSet &refs) { for (; begin != end; ++begin) clearRefsIn(*begin, refs); } void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs); void collectRemovables(Stmt *S, ExprSet &exprs); } // end namespace trans } // end namespace arcmt } // end namespace clang #endif