aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang.xcodeproj/project.pbxproj41
-rw-r--r--include/clang/ARCMigrate/ARCMT.h83
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h76
-rw-r--r--lib/ARCMigrate/ARCMT.cpp484
-rw-r--r--lib/ARCMigrate/CMakeLists.txt14
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp290
-rw-r--r--lib/ARCMigrate/Internals.h146
-rw-r--r--lib/ARCMigrate/Makefile18
-rw-r--r--lib/ARCMigrate/TransformActions.cpp699
-rw-r--r--lib/ARCMigrate/Transforms.cpp2094
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/Driver/Tools.cpp20
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInstance.cpp29
-rw-r--r--lib/Frontend/CompilerInvocation.cpp32
-rwxr-xr-xlib/Makefile4
-rw-r--r--test/ARCMT/Common.h72
-rw-r--r--test/ARCMT/alloc-with-zone-check.m80
-rw-r--r--test/ARCMT/alloc-with-zone.m42
-rw-r--r--test/ARCMT/alloc-with-zone.m.result40
-rw-r--r--test/ARCMT/assign-prop-no-arc-runtime.m19
-rw-r--r--test/ARCMT/assign-prop-no-arc-runtime.m.result19
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m23
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m.result23
-rw-r--r--test/ARCMT/atautorelease-2.m29
-rw-r--r--test/ARCMT/atautorelease-2.m.result28
-rw-r--r--test/ARCMT/atautorelease-3.m40
-rw-r--r--test/ARCMT/atautorelease-3.m.result31
-rw-r--r--test/ARCMT/atautorelease-check.m144
-rw-r--r--test/ARCMT/atautorelease.m47
-rw-r--r--test/ARCMT/atautorelease.m.result46
-rw-r--r--test/ARCMT/autoreleases.m48
-rw-r--r--test/ARCMT/autoreleases.m.result48
-rw-r--r--test/ARCMT/checking.m255
-rw-r--r--test/ARCMT/cxx-checking.mm105
-rw-r--r--test/ARCMT/dealloc.m24
-rw-r--r--test/ARCMT/dealloc.m.result20
-rw-r--r--test/ARCMT/init.m37
-rw-r--r--test/ARCMT/init.m.result37
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast-2.m14
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m32
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m.result32
-rw-r--r--test/ARCMT/releases.m80
-rw-r--r--test/ARCMT/releases.m.result72
-rw-r--r--test/ARCMT/remove-dealloc-method.m26
-rw-r--r--test/ARCMT/remove-dealloc-method.m.result20
-rw-r--r--test/ARCMT/remove-dealloc-zerouts.m44
-rw-r--r--test/ARCMT/remove-dealloc-zerouts.m.result39
-rw-r--r--test/ARCMT/remove-statements.m45
-rw-r--r--test/ARCMT/remove-statements.m.result38
-rw-r--r--test/ARCMT/retains.m71
-rw-r--r--test/ARCMT/retains.m.result65
-rw-r--r--test/ARCMT/rewrite-block-var.m25
-rw-r--r--test/ARCMT/rewrite-block-var.m.result25
-rw-r--r--test/ARCMT/safe-arc-assign.m14
-rw-r--r--test/ARCMT/safe-arc-assign.m.result14
-rw-r--r--test/ARCMT/with-working-dir.m47
-rw-r--r--test/ARCMT/with-working-dir.m.result43
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/Makefile4
-rw-r--r--tools/arcmt-test/CMakeLists.txt14
-rw-r--r--tools/arcmt-test/Makefile24
-rw-r--r--tools/arcmt-test/arcmt-test.cpp253
-rw-r--r--tools/driver/CMakeLists.txt1
-rw-r--r--tools/driver/Makefile2
-rwxr-xr-xtools/scan-build/ccc-analyzer19
-rw-r--r--unittests/Frontend/Makefile2
67 files changed, 6340 insertions, 15 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 1612d122f5..fda6d6f0fa 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -373,6 +373,12 @@
90FD6D90103C3D80005F5B73 /* TypeXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeXML.def; path = clang/Frontend/TypeXML.def; sourceTree = "<group>"; };
90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
+ BB20603B131EDDBF003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+ BB20603C131EDDBF003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
+ BB206041131EDDDA003C3343 /* ARRMT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARRMT.h; sourceTree = "<group>"; };
+ BB206043131EDE03003C3343 /* arrmt-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "arrmt-test.cpp"; sourceTree = "<group>"; };
+ BB206044131EDE03003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+ BB206045131EDE03003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
BB5C372812A5057500259F53 /* DumpXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DumpXML.cpp; path = /Volumes/Data/llvm/tools/clang/lib/AST/DumpXML.cpp; sourceTree = "<absolute>"; };
BBA5AB141309C2FA000B38F1 /* AdjustedReturnValueChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdjustedReturnValueChecker.cpp; sourceTree = "<group>"; };
BBA5AB151309C2FA000B38F1 /* AnalyzerStatsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalyzerStatsChecker.cpp; sourceTree = "<group>"; };
@@ -777,6 +783,7 @@
08FB7795FE84155DC02AAC07 /* Libraries */ = {
isa = PBXGroup;
children = (
+ BB20603A131EDDBF003C3343 /* ARRMigrate */,
BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */,
57EB5660121B034300ECA335 /* Serialization */,
BFE2F67911DA95590007EDC0 /* Rewrite */,
@@ -1105,6 +1112,38 @@
name = "index-test";
sourceTree = "<group>";
};
+ BB20603A131EDDBF003C3343 /* ARRMigrate */ = {
+ isa = PBXGroup;
+ children = (
+ BB20603B131EDDBF003C3343 /* CMakeLists.txt */,
+ BB20603C131EDDBF003C3343 /* Makefile */,
+ BDDF60E91337BF40009F1764 /* Transforms.cpp */,
+ );
+ name = ARRMigrate;
+ path = lib/ARRMigrate;
+ sourceTree = "<group>";
+ };
+ BB206040131EDDDA003C3343 /* ARRMigrate */ = {
+ isa = PBXGroup;
+ children = (
+ BB206041131EDDDA003C3343 /* ARRMT.h */,
+ );
+ name = ARRMigrate;
+ path = clang/ARRMigrate;
+ sourceTree = "<group>";
+ };
+ BB206042131EDE03003C3343 /* arrmt-test */ = {
+ isa = PBXGroup;
+ children = (
+ BD8A47E7133D32660066FE40 /* ARRMT.cpp */,
+ BB206043131EDE03003C3343 /* arrmt-test.cpp */,
+ BB206044131EDE03003C3343 /* CMakeLists.txt */,
+ BB206045131EDE03003C3343 /* Makefile */,
+ );
+ name = "arrmt-test";
+ path = "tools/arrmt-test";
+ sourceTree = "<group>";
+ };
BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */ = {
isa = PBXGroup;
children = (
@@ -1575,6 +1614,7 @@
DED7D72E0A524295003AD0FB /* include */ = {
isa = PBXGroup;
children = (
+ BB206040131EDDDA003C3343 /* ARRMigrate */,
DED7D7300A524295003AD0FB /* Basic */,
DED7D7390A524295003AD0FB /* Lex */,
DE1F21F20A7D84E800FBF588 /* Parse */,
@@ -1724,6 +1764,7 @@
DEDFE61F0F7B3AE10035BD10 /* Tools */ = {
isa = PBXGroup;
children = (
+ BB206042131EDE03003C3343 /* arrmt-test */,
90F9EFA8104ABDC400D09A15 /* c-index-test */,
9012911E104812DA0083456D /* CIndex */,
90FD6DB4103D9763005F5B73 /* index-test */,
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
new file mode 100644
index 0000000000..013f46b7d7
--- /dev/null
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -0,0 +1,83 @@
+//===-- ARCMT.h - ARC Migration Rewriter ------------------------*- 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_ARCMIGRATE_ARCMT_H
+#define LLVM_CLANG_ARCMIGRATE_ARCMT_H
+
+#include "clang/ARCMigrate/FileRemapper.h"
+#include "clang/Frontend/CompilerInvocation.h"
+
+namespace clang {
+ class ASTContext;
+ class DiagnosticClient;
+
+namespace arcmt {
+ class MigrationPass;
+
+/// \brief Creates an AST with the provided CompilerInvocation but with these
+/// changes:
+/// -if a PCH/PTH is set, the original header is used instead
+/// -Automatic Reference Counting mode is enabled
+///
+/// It then checks the AST and produces errors/warning for ARC migration issues
+/// that the user needs to handle manually.
+///
+/// \returns false if no error is produced, true otherwise.
+bool checkForManualIssues(CompilerInvocation &CI,
+ llvm::StringRef Filename, InputKind Kind,
+ DiagnosticClient *DiagClient);
+
+/// \brief Works similar to checkForManualIssues but instead of checking, it
+/// applies automatic modifications to source files to conform to ARC.
+///
+/// \returns false if no error is produced, true otherwise.
+bool applyTransformations(CompilerInvocation &origCI,
+ llvm::StringRef Filename, InputKind Kind,
+ DiagnosticClient *DiagClient);
+
+/// \brief Like applyTransformations but no source file is modified, compilation
+/// happens using in-memory buffers.
+bool applyTransformationsInMemory(CompilerInvocation &origCI,
+ llvm::StringRef Filename, InputKind Kind,
+ DiagnosticClient *DiagClient);
+
+typedef void (*TransformFn)(MigrationPass &pass);
+
+std::vector<TransformFn> getAllTransformations();
+
+class MigrationProcess {
+ CompilerInvocation OrigCI;
+ DiagnosticClient *DiagClient;
+ FileRemapper Remapper;
+
+public:
+ MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient)
+ : OrigCI(CI), DiagClient(diagClient) { }
+
+ class RewriteListener {
+ public:
+ virtual ~RewriteListener();
+
+ virtual void start(ASTContext &Ctx) { }
+ virtual void finish() { }
+
+ virtual void insert(SourceLocation loc, llvm::StringRef text) { }
+ virtual void remove(CharSourceRange range) { }
+ };
+
+ bool applyTransform(TransformFn trans, RewriteListener *listener = 0);
+
+ FileRemapper &getRemapper() { return Remapper; }
+};
+
+} // end namespace arcmt
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
new file mode 100644
index 0000000000..809f6a5f71
--- /dev/null
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -0,0 +1,76 @@
+//===-- FileRemapper.h - File Remapping Helper ------------------*- 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_ARCMIGRATE_FILEREMAPPER_H
+#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+ class MemoryBuffer;
+}
+
+namespace clang {
+ class FileManager;
+ class FileEntry;
+ class Diagnostic;
+ class CompilerInvocation;
+
+namespace arcmt {
+
+class FileRemapper {
+ // FIXME: Reuse the same FileManager for multiple ASTContexts.
+ llvm::OwningPtr<FileManager> FileMgr;
+
+ typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
+ typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
+ MappingsTy FromToMappings;
+
+ llvm::DenseMap<const FileEntry *, const FileEntry *> ToFromMappings;
+
+public:
+ FileRemapper();
+ ~FileRemapper();
+
+ bool initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
+ bool ignoreIfFilesChanged);
+ bool flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag);
+
+ bool overwriteOriginal(Diagnostic &Diag,
+ llvm::StringRef outputDir = llvm::StringRef());
+
+ void remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf);
+ void remap(llvm::StringRef filePath, llvm::StringRef newPath);
+
+ void applyMappings(CompilerInvocation &CI) const;
+
+ void transferMappingsAndClear(CompilerInvocation &CI);
+
+ void clear(llvm::StringRef outputDir = llvm::StringRef());
+
+private:
+ void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf);
+ void remap(const FileEntry *file, const FileEntry *newfile);
+
+ const FileEntry *getOriginalFile(llvm::StringRef filePath);
+ void resetTarget(Target &targ);
+
+ bool report(const std::string &err, Diagnostic &Diag);
+
+ std::string getRemapInfoFile(llvm::StringRef outputDir);
+};
+
+} // end namespace arcmt
+
+} // end namespace clang
+
+#endif
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
new file mode 100644
index 0000000000..bb66da6a71
--- /dev/null
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -0,0 +1,484 @@
+//===--- ARCMT.cpp - Migration 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 "Internals.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Basic/DiagnosticCategories.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace clang;
+using namespace arcmt;
+using llvm::StringRef;
+
+bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+ SourceRange range) {
+ if (range.isInvalid())
+ return false;
+
+ bool cleared = false;
+ ListTy::iterator I = List.begin();
+ while (I != List.end()) {
+ FullSourceLoc diagLoc = I->getLocation();
+ if ((IDs.empty() || // empty means clear all diagnostics in the range.
+ std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
+ !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
+ (diagLoc == range.getEnd() ||
+ diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
+ cleared = true;
+ ListTy::iterator eraseS = I++;
+ while (I != List.end() && I->getLevel() == Diagnostic::Note)
+ ++I;
+ // Clear the diagnostic and any notes following it.
+ List.erase(eraseS, I);
+ continue;
+ }
+
+ ++I;
+ }
+
+ return cleared;
+}
+
+bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs,
+ SourceRange range) {
+ if (range.isInvalid())
+ return false;
+
+ ListTy::iterator I = List.begin();
+ while (I != List.end()) {
+ FullSourceLoc diagLoc = I->getLocation();
+ if ((IDs.empty() || // empty means any diagnostic in the range.
+ std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
+ !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
+ (diagLoc == range.getEnd() ||
+ diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
+ return true;
+ }
+
+ ++I;
+ }
+
+ return false;
+}
+
+void CapturedDiagList::reportDiagnostics(Diagnostic &Diags) {
+ for (ListTy::iterator I = List.begin(), E = List.end(); I != E; ++I)
+ Diags.Report(*I);
+}
+
+namespace {
+
+class CaptureDiagnosticClient : public DiagnosticClient {
+ Diagnostic &Diags;
+ CapturedDiagList &CapturedDiags;
+public:
+ CaptureDiagnosticClient(Diagnostic &diags,
+ CapturedDiagList &capturedDiags)
+ : Diags(diags), CapturedDiags(capturedDiags) { }
+
+ virtual void HandleDiagnostic(Diagnostic::Level level,
+ const DiagnosticInfo &Info) {
+ if (arcmt::isARCDiagnostic(Info.getID(), Diags) ||
+ level >= Diagnostic::Error || level == Diagnostic::Note) {
+ CapturedDiags.push_back(StoredDiagnostic(level, Info));
+ return;
+ }
+
+ // Non-ARC warnings are ignored.
+ Diags.setLastDiagnosticIgnored();
+ }
+};
+
+} // end anonymous namespace
+
+CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) {
+ llvm::OwningPtr<CompilerInvocation> CInvok;
+ CInvok.reset(new CompilerInvocation(origCI));
+ CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string();
+ CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string();
+ std::string define = getARCMTMacroName();
+ define += '=';
+ CInvok->getPreprocessorOpts().addMacroDef(define);
+ CInvok->getLangOpts().ObjCAutoRefCount = true;
+ CInvok->getDiagnosticOpts().ErrorLimit = 0;
+
+ // FIXME: Hackety hack! Try to find out if there is an ARC runtime.
+ bool hasARCRuntime = false;
+ llvm::SmallVector<std::string, 16> args;
+ args.push_back("-x");
+ args.push_back("objective-c");
+ args.push_back("-fobjc-arc");
+
+ llvm::Triple triple(CInvok->getTargetOpts().Triple);
+ if (triple.getOS() == llvm::Triple::IOS ||
+ triple.getOS() == llvm::Triple::MacOSX) {
+ unsigned Major, Minor, Micro;
+ triple.getOSVersion(Major, Minor, Micro);
+ llvm::SmallString<100> flag;
+ if (triple.getOS() == llvm::Triple::IOS)
+ flag += "-miphoneos-version-min=";
+ else
+ flag += "-mmacosx-version-min=";
+ llvm::raw_svector_ostream(flag) << Major << '.' << Minor << '.' << Micro;
+ args.push_back(flag.str());
+ }
+
+ args.push_back(origCI.getFrontendOpts().Inputs[0].second.c_str());
+ // Also push all defines to deal with the iOS simulator hack.
+ for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size();
+ i != e; ++i) {
+ std::string &def = origCI.getPreprocessorOpts().Macros[i].first;
+ bool isUndef = origCI.getPreprocessorOpts().Macros[i].second;
+ if (!isUndef) {
+ std::string newdef = "-D";
+ newdef += def;
+ args.push_back(newdef);
+ }
+ }
+
+ llvm::SmallVector<const char *, 16> cargs;
+ for (unsigned i = 0, e = args.size(); i != e; ++i)
+ cargs.push_back(args[i].c_str());
+
+ llvm::OwningPtr<CompilerInvocation> checkCI;
+ checkCI.reset(clang::createInvocationFromCommandLine(cargs));
+ if (checkCI)
+ hasARCRuntime = !checkCI->getLangOpts().ObjCNoAutoRefCountRuntime;
+
+ CInvok->getLangOpts().ObjCNoAutoRefCountRuntime = !hasARCRuntime;
+
+ return CInvok.take();
+}
+
+//===----------------------------------------------------------------------===//
+// checkForManualIssues.
+//===----------------------------------------------------------------------===//
+
+bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
+ llvm::StringRef Filename, InputKind Kind,
+ DiagnosticClient *DiagClient) {
+ if (!origCI.getLangOpts().ObjC1)
+ return false;
+
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+ assert(!transforms.empty());
+
+ llvm::OwningPtr<CompilerInvocation> CInvok;
+ CInvok.reset(createInvocationForMigration(origCI));
+ CInvok->getFrontendOpts().Inputs.clear();
+ CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
+
+ CapturedDiagList capturedDiags;
+
+ assert(DiagClient);
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+