diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
commit | 56d91b49b13fe55c918afbda19f6165b5fbff87a (patch) | |
tree | 9abb1a658a297776086f4e0dfa6ca533de02104e /lib/ARCMigrate | |
parent | 41e20f564abdb05101d6b2b29c59459a966c22cc (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.cpp | 67 | ||||
-rw-r--r-- | lib/ARCMigrate/CMakeLists.txt | 18 | ||||
-rw-r--r-- | lib/ARCMigrate/FileRemapper.cpp | 4 | ||||
-rw-r--r-- | lib/ARCMigrate/Internals.h | 4 | ||||
-rw-r--r-- | lib/ARCMigrate/ObjCMT.cpp | 2 | ||||
-rw-r--r-- | lib/ARCMigrate/TransAPIUses.cpp | 1 | ||||
-rw-r--r-- | lib/ARCMigrate/TransARCAssign.cpp | 1 | ||||
-rw-r--r-- | lib/ARCMigrate/TransAutoreleasePool.cpp | 3 | ||||
-rw-r--r-- | lib/ARCMigrate/TransBlockObjCVariable.cpp | 19 | ||||
-rw-r--r-- | lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp | 7 | ||||
-rw-r--r-- | lib/ARCMigrate/TransGCAttrs.cpp | 9 | ||||
-rw-r--r-- | lib/ARCMigrate/TransGCCalls.cpp | 9 | ||||
-rw-r--r-- | lib/ARCMigrate/TransProperties.cpp | 11 | ||||
-rw-r--r-- | lib/ARCMigrate/TransRetainReleaseDealloc.cpp | 99 | ||||
-rw-r--r-- | lib/ARCMigrate/TransUnbridgedCasts.cpp | 85 | ||||
-rw-r--r-- | lib/ARCMigrate/TransUnusedInitDelegate.cpp | 3 | ||||
-rw-r--r-- | lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp | 1 | ||||
-rw-r--r-- | lib/ARCMigrate/TransformActions.cpp | 1 | ||||
-rw-r--r-- | lib/ARCMigrate/Transforms.cpp | 59 | ||||
-rw-r--r-- | lib/ARCMigrate/Transforms.h | 14 |
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; |