xref: /freebsd-src/contrib/llvm-project/clang/lib/ARCMigrate/Transforms.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
10b57cec5SDimitry Andric //===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===//
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 #ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
100b57cec5SDimitry Andric #define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
130b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
140b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
150b57cec5SDimitry Andric #include "llvm/Support/SaveAndRestore.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace clang {
180b57cec5SDimitry Andric   class Decl;
190b57cec5SDimitry Andric   class Stmt;
200b57cec5SDimitry Andric   class BlockDecl;
210b57cec5SDimitry Andric   class ObjCMethodDecl;
220b57cec5SDimitry Andric   class FunctionDecl;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace arcmt {
250b57cec5SDimitry Andric   class MigrationPass;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace trans {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   class MigrationContext;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
320b57cec5SDimitry Andric // Transformations.
330b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric void rewriteAutoreleasePool(MigrationPass &pass);
360b57cec5SDimitry Andric void rewriteUnbridgedCasts(MigrationPass &pass);
370b57cec5SDimitry Andric void makeAssignARCSafe(MigrationPass &pass);
380b57cec5SDimitry Andric void removeRetainReleaseDeallocFinalize(MigrationPass &pass);
390b57cec5SDimitry Andric void removeZeroOutPropsInDeallocFinalize(MigrationPass &pass);
400b57cec5SDimitry Andric void rewriteUnusedInitDelegate(MigrationPass &pass);
410b57cec5SDimitry Andric void checkAPIUses(MigrationPass &pass);
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric void removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass);
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric class BodyContext {
460b57cec5SDimitry Andric   MigrationContext &MigrateCtx;
470b57cec5SDimitry Andric   ParentMap PMap;
480b57cec5SDimitry Andric   Stmt *TopStmt;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric public:
BodyContext(MigrationContext & MigrateCtx,Stmt * S)510b57cec5SDimitry Andric   BodyContext(MigrationContext &MigrateCtx, Stmt *S)
520b57cec5SDimitry Andric     : MigrateCtx(MigrateCtx), PMap(S), TopStmt(S) {}
530b57cec5SDimitry Andric 
getMigrationContext()540b57cec5SDimitry Andric   MigrationContext &getMigrationContext() { return MigrateCtx; }
getParentMap()550b57cec5SDimitry Andric   ParentMap &getParentMap() { return PMap; }
getTopStmt()560b57cec5SDimitry Andric   Stmt *getTopStmt() { return TopStmt; }
570b57cec5SDimitry Andric };
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric class ObjCImplementationContext {
600b57cec5SDimitry Andric   MigrationContext &MigrateCtx;
610b57cec5SDimitry Andric   ObjCImplementationDecl *ImpD;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric public:
ObjCImplementationContext(MigrationContext & MigrateCtx,ObjCImplementationDecl * D)640b57cec5SDimitry Andric   ObjCImplementationContext(MigrationContext &MigrateCtx,
650b57cec5SDimitry Andric                             ObjCImplementationDecl *D)
660b57cec5SDimitry Andric     : MigrateCtx(MigrateCtx), ImpD(D) {}
670b57cec5SDimitry Andric 
getMigrationContext()680b57cec5SDimitry Andric   MigrationContext &getMigrationContext() { return MigrateCtx; }
getImplementationDecl()690b57cec5SDimitry Andric   ObjCImplementationDecl *getImplementationDecl() { return ImpD; }
700b57cec5SDimitry Andric };
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric class ASTTraverser {
730b57cec5SDimitry Andric public:
740b57cec5SDimitry Andric   virtual ~ASTTraverser();
traverseTU(MigrationContext & MigrateCtx)750b57cec5SDimitry Andric   virtual void traverseTU(MigrationContext &MigrateCtx) { }
traverseBody(BodyContext & BodyCtx)760b57cec5SDimitry Andric   virtual void traverseBody(BodyContext &BodyCtx) { }
traverseObjCImplementation(ObjCImplementationContext & ImplCtx)770b57cec5SDimitry Andric   virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) {}
780b57cec5SDimitry Andric };
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric class MigrationContext {
810b57cec5SDimitry Andric   std::vector<ASTTraverser *> Traversers;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric public:
840b57cec5SDimitry Andric   MigrationPass &Pass;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   struct GCAttrOccurrence {
870b57cec5SDimitry Andric     enum AttrKind { Weak, Strong } Kind;
880b57cec5SDimitry Andric     SourceLocation Loc;
890b57cec5SDimitry Andric     QualType ModifiedType;
900b57cec5SDimitry Andric     Decl *Dcl;
910b57cec5SDimitry Andric     /// true if the attribute is owned, e.g. it is in a body and not just
920b57cec5SDimitry Andric     /// in an interface.
930b57cec5SDimitry Andric     bool FullyMigratable;
940b57cec5SDimitry Andric   };
950b57cec5SDimitry Andric   std::vector<GCAttrOccurrence> GCAttrs;
96*e8d8bef9SDimitry Andric   llvm::DenseSet<SourceLocation> AttrSet;
97*e8d8bef9SDimitry Andric   llvm::DenseSet<SourceLocation> RemovedAttrSet;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   /// Set of raw '@' locations for 'assign' properties group that contain
1000b57cec5SDimitry Andric   /// GC __weak.
101*e8d8bef9SDimitry Andric   llvm::DenseSet<SourceLocation> AtPropsWeak;
1020b57cec5SDimitry Andric 
MigrationContext(MigrationPass & pass)1030b57cec5SDimitry Andric   explicit MigrationContext(MigrationPass &pass) : Pass(pass) {}
1040b57cec5SDimitry Andric   ~MigrationContext();
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   typedef std::vector<ASTTraverser *>::iterator traverser_iterator;
traversers_begin()1070b57cec5SDimitry Andric   traverser_iterator traversers_begin() { return Traversers.begin(); }
traversers_end()1080b57cec5SDimitry Andric   traverser_iterator traversers_end() { return Traversers.end(); }
1090b57cec5SDimitry Andric 
addTraverser(ASTTraverser * traverser)1100b57cec5SDimitry Andric   void addTraverser(ASTTraverser *traverser) {
1110b57cec5SDimitry Andric     Traversers.push_back(traverser);
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   bool isGCOwnedNonObjC(QualType T);
removePropertyAttribute(StringRef fromAttr,SourceLocation atLoc)1150b57cec5SDimitry Andric   bool removePropertyAttribute(StringRef fromAttr, SourceLocation atLoc) {
1160b57cec5SDimitry Andric     return rewritePropertyAttribute(fromAttr, StringRef(), atLoc);
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric   bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr,
1190b57cec5SDimitry Andric                                 SourceLocation atLoc);
1200b57cec5SDimitry Andric   bool addPropertyAttribute(StringRef attr, SourceLocation atLoc);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   void traverse(TranslationUnitDecl *TU);
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   void dumpGCAttrs();
1250b57cec5SDimitry Andric };
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric class PropertyRewriteTraverser : public ASTTraverser {
1280b57cec5SDimitry Andric public:
1290b57cec5SDimitry Andric   void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) override;
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric class BlockObjCVariableTraverser : public ASTTraverser {
1330b57cec5SDimitry Andric public:
1340b57cec5SDimitry Andric   void traverseBody(BodyContext &BodyCtx) override;
1350b57cec5SDimitry Andric };
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric class ProtectedScopeTraverser : public ASTTraverser {
1380b57cec5SDimitry Andric public:
1390b57cec5SDimitry Andric   void traverseBody(BodyContext &BodyCtx) override;
1400b57cec5SDimitry Andric };
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric // GC transformations
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric class GCAttrsTraverser : public ASTTraverser {
1450b57cec5SDimitry Andric public:
1460b57cec5SDimitry Andric   void traverseTU(MigrationContext &MigrateCtx) override;
1470b57cec5SDimitry Andric };
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric class GCCollectableCallsTraverser : public ASTTraverser {
1500b57cec5SDimitry Andric public:
1510b57cec5SDimitry Andric   void traverseBody(BodyContext &BodyCtx) override;
1520b57cec5SDimitry Andric };
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1550b57cec5SDimitry Andric // Helpers.
1560b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric /// Determine whether we can add weak to the given type.
1590b57cec5SDimitry Andric bool canApplyWeak(ASTContext &Ctx, QualType type,
1600b57cec5SDimitry Andric                   bool AllowOnUnknownClass = false);
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric bool isPlusOneAssign(const BinaryOperator *E);
1630b57cec5SDimitry Andric bool isPlusOne(const Expr *E);
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric /// 'Loc' is the end of a statement range. This returns the location
1660b57cec5SDimitry Andric /// immediately after the semicolon following the statement.
1670b57cec5SDimitry Andric /// If no semicolon is found or the location is inside a macro, the returned
1680b57cec5SDimitry Andric /// source location will be invalid.
1690b57cec5SDimitry Andric SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx,
1700b57cec5SDimitry Andric                                      bool IsDecl = false);
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric /// 'Loc' is the end of a statement range. This returns the location
1730b57cec5SDimitry Andric /// of the semicolon following the statement.
1740b57cec5SDimitry Andric /// If no semicolon is found or the location is inside a macro, the returned
1750b57cec5SDimitry Andric /// source location will be invalid.
1760b57cec5SDimitry Andric SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx,
1770b57cec5SDimitry Andric                                      bool IsDecl = false);
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric bool hasSideEffects(Expr *E, ASTContext &Ctx);
1800b57cec5SDimitry Andric bool isGlobalVar(Expr *E);
1810b57cec5SDimitry Andric /// Returns "nil" or "0" if 'nil' macro is not actually defined.
1820b57cec5SDimitry Andric StringRef getNilString(MigrationPass &Pass);
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric template <typename BODY_TRANS>
1850b57cec5SDimitry Andric class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
1860b57cec5SDimitry Andric   MigrationPass &Pass;
1870b57cec5SDimitry Andric   Decl *ParentD;
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base;
1900b57cec5SDimitry Andric public:
BodyTransform(MigrationPass & pass)1910b57cec5SDimitry Andric   BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(nullptr) { }
1920b57cec5SDimitry Andric 
TraverseStmt(Stmt * rootS)1930b57cec5SDimitry Andric   bool TraverseStmt(Stmt *rootS) {
1940b57cec5SDimitry Andric     if (rootS)
1950b57cec5SDimitry Andric       BODY_TRANS(Pass).transformBody(rootS, ParentD);
1960b57cec5SDimitry Andric     return true;
1970b57cec5SDimitry Andric   }
1980b57cec5SDimitry Andric 
TraverseObjCMethodDecl(ObjCMethodDecl * D)1990b57cec5SDimitry Andric   bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
2000b57cec5SDimitry Andric     SaveAndRestore<Decl *> SetParent(ParentD, D);
2010b57cec5SDimitry Andric     return base::TraverseObjCMethodDecl(D);
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric };
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric typedef llvm::DenseSet<Expr *> ExprSet;
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric void clearRefsIn(Stmt *S, ExprSet &refs);
2080b57cec5SDimitry Andric template <typename iterator>
clearRefsIn(iterator begin,iterator end,ExprSet & refs)2090b57cec5SDimitry Andric void clearRefsIn(iterator begin, iterator end, ExprSet &refs) {
2100b57cec5SDimitry Andric   for (; begin != end; ++begin)
2110b57cec5SDimitry Andric     clearRefsIn(*begin, refs);
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs);
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric void collectRemovables(Stmt *S, ExprSet &exprs);
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric } // end namespace trans
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric } // end namespace arcmt
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric } // end namespace clang
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric #endif
225