aboutsummaryrefslogtreecommitdiff
path: root/lib/ARCMigrate
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
commit56d91b49b13fe55c918afbda19f6165b5fbff87a (patch)
tree9abb1a658a297776086f4e0dfa6ca533de02104e /lib/ARCMigrate
parent41e20f564abdb05101d6b2b29c59459a966c22cc (diff)
Vendor import of clang trunk r161861:vendor/clang/clang-trunk-r161861
Notes
Notes: svn path=/vendor/clang/dist/; revision=239313 svn path=/vendor/clang/clang-trunk-r161861/; revision=239314; tag=vendor/clang/clang-trunk-r161861
Diffstat (limited to 'lib/ARCMigrate')
-rw-r--r--lib/ARCMigrate/ARCMT.cpp67
-rw-r--r--lib/ARCMigrate/CMakeLists.txt18
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp4
-rw-r--r--lib/ARCMigrate/Internals.h4
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp2
-rw-r--r--lib/ARCMigrate/TransAPIUses.cpp1
-rw-r--r--lib/ARCMigrate/TransARCAssign.cpp1
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp3
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp19
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp7
-rw-r--r--lib/ARCMigrate/TransGCAttrs.cpp9
-rw-r--r--lib/ARCMigrate/TransGCCalls.cpp9
-rw-r--r--lib/ARCMigrate/TransProperties.cpp11
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp99
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp85
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp3
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp1
-rw-r--r--lib/ARCMigrate/TransformActions.cpp1
-rw-r--r--lib/ARCMigrate/Transforms.cpp59
-rw-r--r--lib/ARCMigrate/Transforms.h14
20 files changed, 331 insertions, 86 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 9354dc38b8c6..f291dec21fda 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -91,11 +91,40 @@ namespace {
class CaptureDiagnosticConsumer : public DiagnosticConsumer {
DiagnosticsEngine &Diags;
+ DiagnosticConsumer &DiagClient;
CapturedDiagList &CapturedDiags;
+ bool HasBegunSourceFile;
public:
CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
- CapturedDiagList &capturedDiags)
- : Diags(diags), CapturedDiags(capturedDiags) { }
+ DiagnosticConsumer &client,
+ CapturedDiagList &capturedDiags)
+ : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
+ HasBegunSourceFile(false) { }
+
+ virtual void BeginSourceFile(const LangOptions &Opts,
+ const Preprocessor *PP) {
+ // Pass BeginSourceFile message onto DiagClient on first call.
+ // The corresponding EndSourceFile call will be made from an
+ // explicit call to FinishCapture.
+ if (!HasBegunSourceFile) {
+ DiagClient.BeginSourceFile(Opts, PP);
+ HasBegunSourceFile = true;
+ }
+ }
+
+ void FinishCapture() {
+ // Call EndSourceFile on DiagClient on completion of capture to
+ // enable VerifyDiagnosticConsumer to check diagnostics *after*
+ // it has received the diagnostic list.
+ if (HasBegunSourceFile) {
+ DiagClient.EndSourceFile();
+ HasBegunSourceFile = false;
+ }
+ }
+
+ virtual ~CaptureDiagnosticConsumer() {
+ assert(!HasBegunSourceFile && "FinishCapture not called!");
+ }
virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
const Diagnostic &Info) {
@@ -195,8 +224,19 @@ createInvocationForMigration(CompilerInvocation &origCI) {
CInvok->getLangOpts()->ObjCAutoRefCount = true;
CInvok->getLangOpts()->setGC(LangOptions::NonGC);
CInvok->getDiagnosticOpts().ErrorLimit = 0;
- CInvok->getDiagnosticOpts().Warnings.push_back(
- "error=arc-unsafe-retained-assign");
+ CInvok->getDiagnosticOpts().PedanticErrors = 0;
+
+ // Ignore -Werror flags when migrating.
+ std::vector<std::string> WarnOpts;
+ for (std::vector<std::string>::iterator
+ I = CInvok->getDiagnosticOpts().Warnings.begin(),
+ E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
+ if (!StringRef(*I).startswith("error"))
+ WarnOpts.push_back(*I);
+ }
+ WarnOpts.push_back("error=arc-unsafe-retained-assign");
+ CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts);
+
CInvok->getLangOpts()->ObjCRuntimeHasWeak = HasARCRuntime(origCI);
return CInvok.take();
@@ -249,13 +289,15 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
- CaptureDiagnosticConsumer errRec(*Diags, capturedDiags);
+ CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags));
- if (!Unit)
+ if (!Unit) {
+ errRec.FinishCapture();
return true;
+ }
// Don't filter diagnostics anymore.
Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
@@ -267,6 +309,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
capturedDiags.reportDiagnostics(*Diags);
DiagClient->EndSourceFile();
+ errRec.FinishCapture();
return true;
}
@@ -304,6 +347,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
capturedDiags.reportDiagnostics(*Diags);
DiagClient->EndSourceFile();
+ errRec.FinishCapture();
// If we are migrating code that gets the '-fobjc-arc' flag, make sure
// to remove it so that we don't get errors from normal compilation.
@@ -480,13 +524,12 @@ public:
class RewritesApplicator : public TransformActions::RewriteReceiver {
Rewriter &rewriter;
- ASTContext &Ctx;
MigrationProcess::RewriteListener *Listener;
public:
RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
MigrationProcess::RewriteListener *listener)
- : rewriter(rewriter), Ctx(ctx), Listener(listener) {
+ : rewriter(rewriter), Listener(listener) {
if (Listener)
Listener->start(ctx);
}
@@ -553,7 +596,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
- CaptureDiagnosticConsumer errRec(*Diags, capturedDiags);
+ CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
OwningPtr<ARCMTMacroTrackerAction> ASTAction;
@@ -562,8 +605,10 @@ bool MigrationProcess::applyTransform(TransformFn trans,
OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags,
ASTAction.get()));
- if (!Unit)
+ if (!Unit) {
+ errRec.FinishCapture();
return true;
+ }
Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
// Don't filter diagnostics anymore.
@@ -576,6 +621,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
capturedDiags.reportDiagnostics(*Diags);
DiagClient->EndSourceFile();
+ errRec.FinishCapture();
return true;
}
@@ -599,6 +645,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
}
DiagClient->EndSourceFile();
+ errRec.FinishCapture();
if (DiagClient->getNumErrors())
return true;
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index fcb7f72ee21d..f602fc8e5f88 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -1,5 +1,3 @@
-set(LLVM_USED_LIBS clangBasic clangAST clangParse clangFrontend clangRewrite)
-
add_clang_library(clangARCMigrate
ARCMT.cpp
ARCMTActions.cpp
@@ -25,5 +23,19 @@ add_clang_library(clangARCMigrate
add_dependencies(clangARCMigrate
ClangAttrClasses
ClangAttrList
+ ClangAttrParsedAttrList
+ ClangCommentNodes
ClangDeclNodes
- ClangStmtNodes)
+ ClangDiagnosticCommon
+ ClangDiagnosticGroups
+ ClangDiagnosticSema
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangARCMigrate
+ clangBasic
+ clangAST
+ clangParse
+ clangFrontend
+ clangRewrite
+ )
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 474ce7dcbaf8..e9b49b3039ba 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -77,7 +77,9 @@ bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
for (unsigned idx = 0; idx+3 <= lines.size(); idx += 3) {
StringRef fromFilename = lines[idx];
unsigned long long timeModified;
- lines[idx+1].getAsInteger(10, timeModified);
+ if (lines[idx+1].getAsInteger(10, timeModified))
+ return report("Invalid file data: '" + lines[idx+1] + "' not a number",
+ Diag);
StringRef toFilename = lines[idx+2];
const FileEntry *origFE = FileMgr->getFile(fromFilename);
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 59177c483ea0..935fc9b52535 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -12,6 +12,7 @@
#include "clang/ARCMigrate/ARCMT.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
namespace clang {
class Sema;
@@ -144,6 +145,7 @@ public:
Sema &SemaRef;
TransformActions &TA;
std::vector<SourceLocation> &ARCMTMacroLocs;
+ llvm::Optional<bool> EnableCFBridgeFns;
MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode,
Sema &sema, TransformActions &TA,
@@ -157,6 +159,8 @@ public:
void setNSAllocReallocError(bool val) { MigOptions.NoNSAllocReallocError = val; }
bool noFinalizeRemoval() const { return MigOptions.NoFinalizeRemoval; }
void setNoFinalizeRemoval(bool val) {MigOptions.NoFinalizeRemoval = val; }
+
+ bool CFBridgingFunctionsDefined();
};
static inline StringRef getARCMTMacroName() {
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index e63527447633..0098f973e63d 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -10,6 +10,7 @@
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/NSAPI.h"
#include "clang/AST/ASTConsumer.h"
@@ -209,6 +210,7 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
}
bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
+ CI.getDiagnostics().setIgnoreAllWarnings(true);
CI.getPreprocessorOpts().DetailedRecord = true;
CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
return true;
diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp
index aaa82d8dfb7a..5336f859052f 100644
--- a/lib/ARCMigrate/TransAPIUses.cpp
+++ b/lib/ARCMigrate/TransAPIUses.cpp
@@ -19,6 +19,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Sema/SemaDiagnostic.h"
using namespace clang;
diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp
index cfa6da1f99f9..b83f85a1fac2 100644
--- a/lib/ARCMigrate/TransARCAssign.cpp
+++ b/lib/ARCMigrate/TransARCAssign.cpp
@@ -23,6 +23,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Sema/SemaDiagnostic.h"
using namespace clang;
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
index 87877242a124..5205ce4a70a9 100644
--- a/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -29,6 +29,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include <map>
@@ -75,7 +76,7 @@ public:
&pass.Ctx.Idents.get("drain"));
}
- void transformBody(Stmt *body) {
+ void transformBody(Stmt *body, Decl *ParentD) {
Body = body;
TraverseStmt(body);
}
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 3be8132e3b7e..2a79c9aeff20 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -9,7 +9,7 @@
//
// rewriteBlockObjCVariable:
//
-// Adding __block to an obj-c variable could be either because the the variable
+// Adding __block to an obj-c variable could be either because the variable
// is used for output storage or the user wanted to break a retain cycle.
// This transformation checks whether a reference of the variable for the block
// is actually needed (it is assigned to or its address is taken) or not.
@@ -27,6 +27,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;
@@ -37,7 +38,6 @@ namespace {
class RootBlockObjCVarRewriter :
public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
- MigrationPass &Pass;
llvm::DenseSet<VarDecl *> &VarsToChange;
class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
@@ -71,9 +71,8 @@ class RootBlockObjCVarRewriter :
};
public:
- RootBlockObjCVarRewriter(MigrationPass &pass,
- llvm::DenseSet<VarDecl *> &VarsToChange)
- : Pass(pass), VarsToChange(VarsToChange) { }
+ RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
+ : VarsToChange(VarsToChange) { }
bool VisitBlockDecl(BlockDecl *block) {
SmallVector<VarDecl *, 4> BlockVars;
@@ -111,16 +110,14 @@ private:
};
class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
- MigrationPass &Pass;
llvm::DenseSet<VarDecl *> &VarsToChange;
public:
- BlockObjCVarRewriter(MigrationPass &pass,
- llvm::DenseSet<VarDecl *> &VarsToChange)
- : Pass(pass), VarsToChange(VarsToChange) { }
+ BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
+ : VarsToChange(VarsToChange) { }
bool TraverseBlockDecl(BlockDecl *block) {
- RootBlockObjCVarRewriter(Pass, VarsToChange).TraverseDecl(block);
+ RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
return true;
}
};
@@ -131,7 +128,7 @@ void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
llvm::DenseSet<VarDecl *> VarsToChange;
- BlockObjCVarRewriter trans(Pass, VarsToChange);
+ BlockObjCVarRewriter trans(VarsToChange);
trans.TraverseStmt(BodyCtx.getTopStmt());
for (llvm::DenseSet<VarDecl *>::iterator
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index 0fb7141544aa..552cb2fa631c 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -21,6 +21,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/SourceManager.h"
@@ -44,7 +45,7 @@ static bool isEmptyARCMTMacroStatement(NullStmt *S,
SourceManager &SM = Ctx.getSourceManager();
std::vector<SourceLocation>::iterator
I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc,
- SourceManager::LocBeforeThanCompare(SM));
+ BeforeThanCompare<SourceLocation>(SM));
--I;
SourceLocation
AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());
@@ -210,8 +211,8 @@ static void cleanupDeallocOrFinalize(MigrationPass &pass) {
ObjCMethodDecl *DeallocM = 0;
ObjCMethodDecl *FinalizeM = 0;
for (ObjCImplementationDecl::instmeth_iterator
- MI = (*I)->instmeth_begin(),
- ME = (*I)->instmeth_end(); MI != ME; ++MI) {
+ MI = I->instmeth_begin(),
+ ME = I->instmeth_end(); MI != ME; ++MI) {
ObjCMethodDecl *MD = *MI;
if (!MD->hasBody())
continue;
diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp
index 9f6066ef77da..eec7306ba74a 100644
--- a/lib/ARCMigrate/TransGCAttrs.cpp
+++ b/lib/ARCMigrate/TransGCAttrs.cpp
@@ -9,12 +9,13 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Lex/Lexer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/SaveAndRestore.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace arcmt;
@@ -136,7 +137,7 @@ public:
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
for (CXXRecordDecl::method_iterator
MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
- if ((*MI)->isOutOfLine())
+ if (MI->isOutOfLine())
return true;
}
return false;
@@ -166,7 +167,7 @@ public:
for (Decl::redecl_iterator
I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
- if (!isInMainFile((*I)->getLocation()))
+ if (!isInMainFile(I->getLocation()))
return false;
return true;
diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp
index 1be902088c62..2ec480c0af64 100644
--- a/lib/ARCMigrate/TransGCCalls.cpp
+++ b/lib/ARCMigrate/TransGCCalls.cpp
@@ -9,6 +9,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Sema/SemaDiagnostic.h"
using namespace clang;
@@ -20,13 +21,12 @@ namespace {
class GCCollectableCallsChecker :
public RecursiveASTVisitor<GCCollectableCallsChecker> {
MigrationContext &MigrateCtx;
- ParentMap &PMap;
IdentifierInfo *NSMakeCollectableII;
IdentifierInfo *CFMakeCollectableII;
public:
- GCCollectableCallsChecker(MigrationContext &ctx, ParentMap &map)
- : MigrateCtx(ctx), PMap(map) {
+ GCCollectableCallsChecker(MigrationContext &ctx)
+ : MigrateCtx(ctx) {
IdentifierTable &Ids = MigrateCtx.Pass.Ctx.Idents;
NSMakeCollectableII = &Ids.get("NSMakeCollectable");
CFMakeCollectableII = &Ids.get("CFMakeCollectable");
@@ -78,7 +78,6 @@ public:
} // anonymous namespace
void GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) {
- GCCollectableCallsChecker(BodyCtx.getMigrationContext(),
- BodyCtx.getParentMap())
+ GCCollectableCallsChecker(BodyCtx.getMigrationContext())
.TraverseStmt(BodyCtx.getTopStmt());
}
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index cc85fe25cca9..fdd6e8863b59 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -309,17 +309,8 @@ private:
if (RE->getDecl() != Ivar)
return true;
- if (ObjCMessageExpr *
- ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
- if (ME->getMethodFamily() == OMF_retain)
+ if (isPlusOneAssign(E))
return false;
-
- ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
- while (implCE && implCE->getCastKind() == CK_BitCast)
- implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
-
- if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
- return false;
}
return true;
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 11a655334144..91d2b399e3f1 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -19,10 +19,11 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
using namespace clang;
using namespace arcmt;
@@ -49,7 +50,7 @@ public:
Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
}
- void transformBody(Stmt *body) {
+ void transformBody(Stmt *body, Decl *ParentD) {
Body = body;
collectRemovables(body, Removables);
StmtMap.reset(new ParentMap(body));
@@ -64,14 +65,16 @@ public:
return true;
case OMF_autorelease:
if (isRemovable(E)) {
- // An unused autorelease is badness. If we remove it the receiver
- // will likely die immediately while previously it was kept alive
- // by the autorelease pool. This is bad practice in general, leave it
- // and emit an error to force the user to restructure his code.
- Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
- "message; its receiver may be destroyed immediately",
- E->getLocStart(), E->getSourceRange());
- return true;
+ if (!isCommonUnusedAutorelease(E)) {
+ // An unused autorelease is badness. If we remove it the receiver
+ // will likely die immediately while previously it was kept alive
+ // by the autorelease pool. This is bad practice in general, leave it
+ // and emit an error to force the user to restructure his code.
+ Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
+ "message; its receiver may be destroyed immediately",
+ E->getLocStart(), E->getSourceRange());
+ return true;
+ }
}
// Pass through.
case OMF_retain:
@@ -156,6 +159,80 @@ public:
}
private:
+ /// \brief Checks for idioms where an unused -autorelease is common.
+ ///
+ /// Currently only returns true for this idiom which is common in property
+ /// setters:
+ ///
+ /// [backingValue autorelease];
+ /// backingValue = [newValue retain]; // in general a +1 assign
+ ///
+ bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
+ Expr *Rec = E->getInstanceReceiver();
+ if (!Rec)
+ return false;
+
+ Decl *RefD = getReferencedDecl(Rec);
+ if (!RefD)
+ return false;
+
+ Stmt *OuterS = E, *InnerS;
+ do {
+ InnerS = OuterS;
+ OuterS = StmtMap->getParent(InnerS);
+ }
+ while (OuterS && (isa<ParenExpr>(OuterS) ||
+ isa<CastExpr>(OuterS) ||
+ isa<ExprWithCleanups>(OuterS)));
+
+ if (!OuterS)
+ return false;
+
+ // Find next statement after the -autorelease.
+
+ Stmt::child_iterator currChildS = OuterS->child_begin();
+ Stmt::child_iterator childE = OuterS->child_end();
+ for (; currChildS != childE; ++currChildS) {
+ if (*currChildS == InnerS)
+ break;
+ }
+ if (currChildS == childE)
+ return false;
+ ++currChildS;
+ if (currChildS == childE)
+ return false;
+
+ Stmt *nextStmt = *currChildS;
+ if (!nextStmt)
+ return false;
+ nextStmt = nextStmt->IgnoreImplicit();
+
+ // Check for "RefD = [+1 retained object];".
+
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(nextStmt)) {
+ if (RefD != getReferencedDecl(Bop->getLHS()))
+ return false;
+ if (isPlusOneAssign(Bop))
+ return true;
+ }
+ return false;
+ }
+
+ Decl *getReferencedDecl(Expr *E) {
+ if (!E)
+ return 0;
+
+ E = E->IgnoreParenCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
+ return IRE->getDecl();
+
+ return 0;
+ }
+
/// \brief Check if the retain/release is due to a GCD/XPC macro that are
/// defined as:
///
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 48437c795fa9..ac18b5d6e739 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -12,7 +12,7 @@
// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
// is from a file-level variable, __bridge cast is used to convert it.
// For the result of a function call that we know is +1/+0,
-// __bridge/__bridge_transfer is used.
+// __bridge/CFBridgingRelease is used.
//
// NSString *str = (NSString *)kUTTypePlainText;
// str = b ? kUTTypeRTF : kUTTypePlainText;
@@ -21,8 +21,8 @@
// ---->
// NSString *str = (__bridge NSString *)kUTTypePlainText;
// str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
-// NSString *_uuidString = (__bridge_transfer NSString *)
-// CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+// NSString *_uuidString = (NSString *)
+// CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
//
// For a C pointer to ObjC, for casting 'self', __bridge is used.
//
@@ -35,9 +35,11 @@
#include "Transforms.h"
#include "Internals.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -50,13 +52,15 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
MigrationPass &Pass;
IdentifierInfo *SelfII;
OwningPtr<ParentMap> StmtMap;
+ Decl *ParentD;
public:
- UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
+ UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
SelfII = &Pass.Ctx.Idents.get("self");
}
- void transformBody(Stmt *body) {
+ void transformBody(Stmt *body, Decl *ParentD) {
+ this->ParentD = ParentD;
StmtMap.reset(new ParentMap(body));
TraverseStmt(body);
}
@@ -155,6 +159,21 @@ private:
}
}
}
+
+ // If returning an ivar or a member of an ivar from a +0 method, use
+ // a __bridge cast.
+ Expr *base = inner->IgnoreParenImpCasts();
+ while (isa<MemberExpr>(base))
+ base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
+ if (isa<ObjCIvarRefExpr>(base) &&
+ isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
+ if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
+ if (!method->hasAttr<NSReturnsRetainedAttr>()) {
+ castToObjCObject(E, /*retained=*/false);
+ return;
+ }
+ }
+ }
}
void castToObjCObject(CastExpr *E, bool retained) {
@@ -191,22 +210,48 @@ private:
TA.clearDiagnostic(diag::err_arc_mismatched_cast,
diag::err_arc_cast_requires_bridge,
E->getLocStart());
- if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
- TA.insertAfterToken(CCE->getLParenLoc(), bridge);
- } else {
- SourceLocation insertLoc = E->getSubExpr()->getLocStart();
- SmallString<128> newCast;
- newCast += '(';
- newCast += bridge;
- newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
- newCast += ')';
-
- if (isa<ParenExpr>(E->getSubExpr())) {
- TA.insert(insertLoc, newCast.str());
+ if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
+ if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
+ TA.insertAfterToken(CCE->getLParenLoc(), bridge);
} else {
+ SourceLocation insertLoc = E->getSubExpr()->getLocStart();
+ SmallString<128> newCast;
newCast += '(';
- TA.insert(insertLoc, newCast.str());
- TA.insertAfterToken(E->getLocEnd(), ")");
+ newCast += bridge;
+ newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
+ newCast += ')';
+
+ if (isa<ParenExpr>(E->getSubExpr())) {
+ TA.insert(insertLoc, newCast.str());
+ } else {
+ newCast += '(';
+ TA.insert(insertLoc, newCast.str());
+ TA.insertAfterToken(E->getLocEnd(), ")");
+ }
+ }
+ } else {
+ assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
+ SmallString<32> BridgeCall;
+
+ Expr *WrapE = E->getSubExpr();
+ SourceLocation InsertLoc = WrapE->getLocStart();
+
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+ char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
+ if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
+ BridgeCall += ' ';
+
+ if (Kind == OBC_BridgeTransfer)
+ BridgeCall += "CFBridgingRelease";
+ else
+ BridgeCall += "CFBridgingRetain";
+
+ if (isa<ParenExpr>(WrapE)) {
+ TA.insert(InsertLoc, BridgeCall);
+ } else {
+ BridgeCall += '(';
+ TA.insert(InsertLoc, BridgeCall);
+ TA.insertAfterToken(WrapE->getLocEnd(), ")");
}
}
}
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index 60ed32aef4ce..3057e391d0a8 100644
--- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
@@ -22,6 +22,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Sema/SemaDiagnostic.h"
using namespace clang;
@@ -40,7 +41,7 @@ public:
UnusedInitRewriter(MigrationPass &pass)
: Body(0), Pass(pass) { }
- void transformBody(Stmt *body) {
+ void transformBody(Stmt *body, Decl *ParentD) {
Body = body;
collectRemovables(body, Removables);
TraverseStmt(body);
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index d1f08aac28c2..a07596d0cb0c 100644
--- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
@@ -15,6 +15,7 @@
#include "Transforms.h"
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
using namespace clang;
using namespace arcmt;
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index 0ecfeb54f85d..783db1c8f3aa 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "Internals.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index d342d1aa0477..1175c363163b 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -9,11 +9,14 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/DenseSet.h"
#include <map>
@@ -24,6 +27,13 @@ using namespace trans;
ASTTraverser::~ASTTraverser() { }
+bool MigrationPass::CFBridgingFunctionsDefined() {
+ if (!EnableCFBridgeFns.hasValue())
+ EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") &&
+ SemaRef.isKnownName("CFBridgingRelease");
+ return *EnableCFBridgeFns;
+}
+
//===----------------------------------------------------------------------===//
// Helpers.
//===----------------------------------------------------------------------===//
@@ -56,6 +66,47 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
return true;
}
+bool trans::isPlusOneAssign(const BinaryOperator *E) {
+ if (E->getOpcode() != BO_Assign)
+ return false;
+
+ if (const ObjCMessageExpr *
+ ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
+ if (ME->getMethodFamily() == OMF_retain)
+ return true;
+
+ if (const CallExpr *
+ callE = dyn_cast<CallExpr>(E->getRHS()->IgnoreParenCasts())) {
+ if (const FunctionDecl *FD = callE->getDirectCallee()) {
+ if (FD->getAttr<CFReturnsRetainedAttr>())
+ return true;
+
+ if (FD->isGlobal() &&
+ FD->getIdentifier() &&
+ FD->getParent()->isTranslationUnit() &&
+ FD->getLinkage() == ExternalLinkage &&
+ ento::cocoa::isRefType(callE->getType(), "CF",
+ FD->getIdentifier()->getName())) {
+ StringRef fname = FD->getIdentifier()->getName();
+ if (fname.endswith("Retain") ||
+ fname.find("Create") != StringRef::npos ||
+ fname.find("Copy") != StringRef::npos) {
+ return true;
+ }
+ }
+ }
+ }
+
+ const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
+ while (implCE && implCE->getCastKind() == CK_BitCast)
+ implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
+
+ if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
+ return true;
+
+ return false;
+}
+
/// \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
@@ -472,8 +523,8 @@ static void GCRewriteFinalize(MigrationPass &pass) {
for (impl_iterator I = impl_iterator(DC->decls_begin()),
E = impl_iterator(DC->decls_end()); I != E; ++I) {
for (ObjCImplementationDecl::instmeth_iterator
- MI = (*I)->instmeth_begin(),
- ME = (*I)->instmeth_end(); MI != ME; ++MI) {
+ MI = I->instmeth_begin(),
+ ME = I->instmeth_end(); MI != ME; ++MI) {
ObjCMethodDecl *MD = *MI;
if (!MD->hasBody())
continue;
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index 445c3e599d65..5d4ac9446045 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -13,6 +13,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/ParentMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/SaveAndRestore.h"
namespace clang {
class Decl;
@@ -154,6 +155,8 @@ public:
bool canApplyWeak(ASTContext &Ctx, QualType type,
bool AllowOnUnknownClass = false);
+bool isPlusOneAssign(const BinaryOperator *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
@@ -174,15 +177,22 @@ 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) { }
+ BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(0) { }
bool TraverseStmt(Stmt *rootS) {
if (rootS)
- BODY_TRANS(Pass).transformBody(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;