llvm-project/clang/lib/ARCMigrate/Transforms.h

226 lines
6.7 KiB
C
Raw Normal View History

2012-11-14 23:08:31 +08:00
//===-- 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);
[arcmt] More automatic transformations and safety improvements; rdar://9615812 : - Replace calling -zone with 'nil'. -zone is obsolete in ARC. - Allow removing retain/release on a static global var. - Fix assertion hit when scanning for name references outside a NSAutoreleasePool scope. - Automatically add bridged casts for results of objc method calls and when calling CFRetain, for example: NSString *s; CFStringRef ref = [s string]; -> CFStringRef ref = (__bridge CFStringRef)([s string]); ref = s.string; -> ref = (__bridge CFStringRef)(s.string); ref = [NSString new]; -> ref = (__bridge_retained CFStringRef)([NSString new]); ref = [s newString]; -> ref = (__bridge_retained CFStringRef)([s newString]); ref = [[NSString alloc] init]; -> ref = (__bridge_retained CFStringRef)([[NSString alloc] init]); ref = [[s string] retain]; -> ref = (__bridge_retained CFStringRef)([s string]); ref = CFRetain(s); -> ref = (__bridge_retained CFTypeRef)(s); ref = [s retain]; -> ref = (__bridge_retained CFStringRef)(s); - Emit migrator error when trying to cast to CF type the result of autorelease/release: for CFStringRef f3() { return (CFStringRef)[[[NSString alloc] init] autorelease]; } emits: t.m:12:10: error: [rewriter] it is not safe to cast to 'CFStringRef' the result of 'autorelease' message; a __bridge cast may result in a pointer to a destroyed object and a __bridge_retained may leak the object return (CFStringRef)[[[NSString alloc] init] autorelease]; ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ t.m:12:3: note: [rewriter] remove the cast and change return type of function to 'NSString *' to have the object automatically autoreleased return (CFStringRef)[[[NSString alloc] init] autorelease]; ^ - Before changing attributes to weak/unsafe_unretained, check if the backing ivar is set to a +1 object, in which case use 'strong' instead. llvm-svn: 136208
2011-07-27 13:28:18 +08:00
/// \brief Returns "nil" or "0" if 'nil' macro is not actually defined.
StringRef getNilString(MigrationPass &Pass);
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