From e0ac7454bae910ab3d67a92f6e2e5046d3bb8c1a Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Fri, 4 Nov 2011 15:58:08 +0000 Subject: [PATCH] [arcmt] In GC, transform NSMakeCollectable to CFBridgingRelease. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143698 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/ARCMigrate/ARCMT.h | 2 +- lib/ARCMigrate/ARCMT.cpp | 14 +++++--- lib/ARCMigrate/CMakeLists.txt | 1 + lib/ARCMigrate/Internals.h | 9 +++-- lib/ARCMigrate/TransGCCalls.cpp | 59 ++++++++++++++++++++++++++++++++ lib/ARCMigrate/Transforms.cpp | 55 +++++++++++++++++++++++++++-- lib/ARCMigrate/Transforms.h | 51 +++++++++++++++++++++++++++ test/ARCMT/Common.h | 5 +++ test/ARCMT/GC.m | 9 +++++ test/ARCMT/GC.m.result | 9 +++++ tools/arcmt-test/arcmt-test.cpp | 3 +- 11 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 lib/ARCMigrate/TransGCCalls.cpp create mode 100644 test/ARCMT/GC.m create mode 100644 test/ARCMT/GC.m.result diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h index d8dea0b3ad..48c5130f88 100644 --- a/include/clang/ARCMigrate/ARCMT.h +++ b/include/clang/ARCMigrate/ARCMT.h @@ -78,7 +78,7 @@ bool getFileRemappings(std::vector > &remap, typedef void (*TransformFn)(MigrationPass &pass); -std::vector getAllTransformations(); +std::vector getAllTransformations(LangOptions::GCMode OrigGCMode); class MigrationProcess { CompilerInvocation OrigCI; diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index a588d54b87..f35f2577ed 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -192,6 +192,7 @@ createInvocationForMigration(CompilerInvocation &origCI) { define += '='; CInvok->getPreprocessorOpts().addMacroDef(define); CInvok->getLangOpts().ObjCAutoRefCount = true; + CInvok->getLangOpts().setGC(LangOptions::NonGC); CInvok->getDiagnosticOpts().ErrorLimit = 0; CInvok->getDiagnosticOpts().Warnings.push_back( "error=arc-unsafe-retained-assign"); @@ -226,7 +227,9 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, if (!origCI.getLangOpts().ObjC1) return false; - std::vector transforms = arcmt::getAllTransformations(); + LangOptions::GCMode OrigGCMode = origCI.getLangOpts().getGC(); + + std::vector transforms = arcmt::getAllTransformations(OrigGCMode); assert(!transforms.empty()); llvm::OwningPtr CInvok; @@ -287,7 +290,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, std::vector ARCMTMacroLocs; TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); - MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs); + MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, ARCMTMacroLocs); for (unsigned i=0, e = transforms.size(); i != e; ++i) transforms[i](pass); @@ -316,6 +319,8 @@ static bool applyTransforms(CompilerInvocation &origCI, if (!origCI.getLangOpts().ObjC1) return false; + LangOptions::GCMode OrigGCMode = origCI.getLangOpts().getGC(); + // Make sure checking is successful first. CompilerInvocation CInvokForCheck(origCI); if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient, @@ -328,7 +333,7 @@ static bool applyTransforms(CompilerInvocation &origCI, MigrationProcess migration(CInvok, DiagClient, outputDir); - std::vector transforms = arcmt::getAllTransformations(); + std::vector transforms = arcmt::getAllTransformations(OrigGCMode); assert(!transforms.empty()); for (unsigned i=0, e = transforms.size(); i != e; ++i) { @@ -537,7 +542,8 @@ bool MigrationProcess::applyTransform(TransformFn trans, Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions()); TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); - MigrationPass pass(Ctx, Unit->getSema(), TA, ARCMTMacroLocs); + MigrationPass pass(Ctx, OrigCI.getLangOpts().getGC(), + Unit->getSema(), TA, ARCMTMacroLocs); trans(pass); diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt index f6d404ee13..90c2bbf54e 100644 --- a/lib/ARCMigrate/CMakeLists.txt +++ b/lib/ARCMigrate/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_library(clangARCMigrate TransEmptyStatementsAndDealloc.cpp TransformActions.cpp Transforms.cpp + TransGCCalls.cpp TransProperties.cpp TransRetainReleaseDealloc.cpp TransUnbridgedCasts.cpp diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h index 99b5f59679..06d9f8259f 100644 --- a/lib/ARCMigrate/Internals.h +++ b/lib/ARCMigrate/Internals.h @@ -137,13 +137,18 @@ public: class MigrationPass { public: ASTContext &Ctx; + LangOptions::GCMode OrigGCMode; Sema &SemaRef; TransformActions &TA; std::vector &ARCMTMacroLocs; - MigrationPass(ASTContext &Ctx, Sema &sema, TransformActions &TA, + MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode, + Sema &sema, TransformActions &TA, std::vector &ARCMTMacroLocs) - : Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { } + : Ctx(Ctx), OrigGCMode(OrigGCMode), SemaRef(sema), TA(TA), + ARCMTMacroLocs(ARCMTMacroLocs) { } + + bool isGCMigration() const { return OrigGCMode != LangOptions::NonGC; } }; static inline StringRef getARCMTMacroName() { diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp new file mode 100644 index 0000000000..71dc6dc357 --- /dev/null +++ b/lib/ARCMigrate/TransGCCalls.cpp @@ -0,0 +1,59 @@ +//===--- TransGCCalls.cpp - Tranformations to ARC mode --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; + +namespace { + +class GCCollectableCallsChecker : + public RecursiveASTVisitor { + MigrationContext &MigrateCtx; + ParentMap &PMap; + IdentifierInfo *NSMakeCollectableII; + +public: + GCCollectableCallsChecker(MigrationContext &ctx, ParentMap &map) + : MigrateCtx(ctx), PMap(map) { + NSMakeCollectableII = + &MigrateCtx.getPass().Ctx.Idents.get("NSMakeCollectable"); + } + + bool VisitCallExpr(CallExpr *E) { + Expr *CEE = E->getCallee()->IgnoreParenImpCasts(); + if (DeclRefExpr *DRE = dyn_cast(CEE)) { + if (FunctionDecl *FD = dyn_cast_or_null(DRE->getDecl())) { + if (FD->getDeclContext()->getRedeclContext()->isFileContext() && + FD->getIdentifier() == NSMakeCollectableII) { + TransformActions &TA = MigrateCtx.getPass().TA; + Transaction Trans(TA); + TA.clearDiagnostic(diag::err_unavailable, + diag::err_unavailable_message, + DRE->getSourceRange()); + TA.replace(DRE->getSourceRange(), "CFBridgingRelease"); + } + } + } + + return true; + } +}; + +} // anonymous namespace + +void GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) { + GCCollectableCallsChecker(BodyCtx.getMigrationContext(), + BodyCtx.getParentMap()) + .TraverseStmt(BodyCtx.getTopStmt()); +} diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 4244fafe07..792bb0cc9a 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -12,7 +12,6 @@ #include "clang/Sema/SemaDiagnostic.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" -#include "clang/AST/ParentMap.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/SourceManager.h" @@ -24,6 +23,8 @@ using namespace clang; using namespace arcmt; using namespace trans; +ASTTraverser::~ASTTraverser() { } + //===----------------------------------------------------------------------===// // Helpers. //===----------------------------------------------------------------------===// @@ -289,10 +290,58 @@ void trans::collectRemovables(Stmt *S, ExprSet &exprs) { RemovablesCollector(exprs).TraverseStmt(S); } +//===----------------------------------------------------------------------===// +// MigrationContext +//===----------------------------------------------------------------------===// + +namespace { + +class ASTTransform : public RecursiveASTVisitor { + MigrationContext &MigrateCtx; + +public: + ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { } + + bool TraverseStmt(Stmt *rootS) { + if (!rootS) + return true; + + BodyContext BodyCtx(MigrateCtx, rootS); + for (MigrationContext::traverser_iterator + I = MigrateCtx.traversers_begin(), + E = MigrateCtx.traversers_end(); I != E; ++I) + (*I)->traverseBody(BodyCtx); + + return true; + } +}; + +} + +MigrationContext::~MigrationContext() { + for (traverser_iterator + I = traversers_begin(), E = traversers_end(); I != E; ++I) + delete *I; +} + +void MigrationContext::traverse(TranslationUnitDecl *TU) { + ASTTransform(*this).TraverseDecl(TU); +} + //===----------------------------------------------------------------------===// // getAllTransformations. //===----------------------------------------------------------------------===// +static void traverseAST(MigrationPass &pass) { + MigrationContext MigrateCtx(pass); + + if (pass.isGCMigration()) { + MigrateCtx.addTraverser(new GCCollectableCallsTraverser); + } + + MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); +} + static void independentTransforms(MigrationPass &pass) { rewriteAutoreleasePool(pass); rewriteProperties(pass); @@ -303,9 +352,11 @@ static void independentTransforms(MigrationPass &pass) { rewriteUnbridgedCasts(pass); rewriteBlockObjCVariable(pass); checkAPIUses(pass); + traverseAST(pass); } -std::vector arcmt::getAllTransformations() { +std::vector arcmt::getAllTransformations( + LangOptions::GCMode OrigGCMode) { std::vector transforms; transforms.push_back(independentTransforms); diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index 5e4db56dc8..0eabb21196 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/ParentMap.h" #include "llvm/ADT/DenseSet.h" namespace clang { @@ -25,6 +26,8 @@ namespace arcmt { namespace trans { + class MigrationContext; + //===----------------------------------------------------------------------===// // Transformations. //===----------------------------------------------------------------------===// @@ -41,6 +44,54 @@ void checkAPIUses(MigrationPass &pass); void removeEmptyStatementsAndDealloc(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 ASTTraverser { +public: + virtual ~ASTTraverser(); + virtual void traverseBody(BodyContext &BodyCtx) { } +}; + +class MigrationContext { + MigrationPass &Pass; + std::vector Traversers; + +public: + explicit MigrationContext(MigrationPass &pass) : Pass(pass) {} + ~MigrationContext(); + + MigrationPass &getPass() { return Pass; } + + typedef std::vector::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); + } + + void traverse(TranslationUnitDecl *TU); +}; + +// GC transformations + +class GCCollectableCallsTraverser : public ASTTraverser { +public: + virtual void traverseBody(BodyContext &BodyCtx); +}; + //===----------------------------------------------------------------------===// // Helpers. //===----------------------------------------------------------------------===// diff --git a/test/ARCMT/Common.h b/test/ARCMT/Common.h index 2603730cad..16856ed1b4 100644 --- a/test/ARCMT/Common.h +++ b/test/ARCMT/Common.h @@ -4,8 +4,10 @@ #define NS_AUTOMATED_REFCOUNT_UNAVAILABLE #endif +#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) #define CF_CONSUMED __attribute__((cf_consumed)) +#define NS_INLINE static __inline__ __attribute__((always_inline)) #define nil ((void*) 0) typedef int BOOL; @@ -19,6 +21,9 @@ typedef struct _NSZone NSZone; typedef const void * CFTypeRef; CFTypeRef CFRetain(CFTypeRef cf); +id CFBridgingRelease(CFTypeRef CF_CONSUMED X); + +NS_INLINE NS_RETURNS_RETAINED id NSMakeCollectable(CFTypeRef CF_CONSUMED cf) NS_AUTOMATED_REFCOUNT_UNAVAILABLE; @protocol NSObject - (BOOL)isEqual:(id)object; diff --git a/test/ARCMT/GC.m b/test/ARCMT/GC.m new file mode 100644 index 0000000000..90e0b458b2 --- /dev/null +++ b/test/ARCMT/GC.m @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result +// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-gc-only -x objective-c %s > %t +// RUN: diff %t %s.result + +#include "Common.h" + +void test1(CFTypeRef *cft) { + id x = NSMakeCollectable(cft); +} diff --git a/test/ARCMT/GC.m.result b/test/ARCMT/GC.m.result new file mode 100644 index 0000000000..1055aa3338 --- /dev/null +++ b/test/ARCMT/GC.m.result @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result +// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-gc-only -x objective-c %s > %t +// RUN: diff %t %s.result + +#include "Common.h" + +void test1(CFTypeRef *cft) { + id x = CFBridgingRelease(cft); +} diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp index d27483f291..e47e815d35 100644 --- a/tools/arcmt-test/arcmt-test.cpp +++ b/tools/arcmt-test/arcmt-test.cpp @@ -172,7 +172,8 @@ static bool performTransformations(StringRef resourcesPath, MigrationProcess migration(origCI, DiagClient); - std::vector transforms = arcmt::getAllTransformations(); + std::vector + transforms = arcmt::getAllTransformations(origCI.getLangOpts().getGC()); assert(!transforms.empty()); llvm::OwningPtr transformPrinter; -- 2.50.1