[arcmt] Introduce new '-ccc-arcmt-migrate <path>' ARC migration driver option.

This is a new mode of migration, where we avoid modifying the original files but
we emit temporary files instead.

<path> will be used to keep migration process metadata. Currently the temporary files
that are produced are put in the system's temp directory but we can put them
in the <path> if is necessary.

Also introduce new ARC migration functions in libclang whose only purpose,
currently, is to accept <path> and provide pairs of original file/transformed file
to map from the originals to the files after transformations are applied.

Finally introduce the c-arcmt-test utility that exercises the new libclang functions,
update arcmt-test, and add tests for the whole process.

rdar://9735086.

llvm-svn: 134844
This commit is contained in:
Argyrios Kyrtzidis 2011-07-09 20:00:58 +00:00
parent 25659e93c7
commit 7fbd97f641
31 changed files with 646 additions and 31 deletions

View File

@ -0,0 +1,79 @@
/*===-- clang-c/ARCMigrate.h - ARC Migration Public C Interface ---*- C -*-===*\
|* *|
|* The LLVM Compiler Infrastructure *|
|* *|
|* This file is distributed under the University of Illinois Open Source *|
|* License. See LICENSE.TXT for details. *|
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
|* This header provides a public interface to a Clang library for migrating *|
|* objective-c source files to ARC mode. *|
|* *|
\*===----------------------------------------------------------------------===*/
#ifndef CLANG_C_ARCMIGRATE_H
#define CLANG_C_ARCMIGRATE_H
#include "clang-c/Index.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup CARCMT libclang: C Interface to Clang ARC migration library
*
* The C Interface provides a small API that exposes facilities for translating
* objective-c source files of a project to Automatic Reference Counting mode.
*
* To avoid namespace pollution, data types are prefixed with "CMT" and
* functions are prefixed with "arcmt_".
*
* @{
*/
/**
* \brief A remapping of original source files and their translated files.
*/
typedef void *CMTRemap;
/**
* \brief Retrieve a remapping.
*
* \param migrate_dir_path the path that clang used during the migration process.
*
* \returns the requested remapping. This remapping must be freed
* via a call to \c arcmt_remap_dispose(). Can return NULL if an error occurred.
*/
CINDEX_LINKAGE CMTRemap arcmt_getRemappings(const char *migrate_dir_path);
/**
* \brief Determine the number of remappings.
*/
CINDEX_LINKAGE unsigned arcmt_remap_getNumFiles(CMTRemap);
/**
* \brief Get the original filename.
*/
CINDEX_LINKAGE CXString arcmt_remap_getOriginalFile(CMTRemap, unsigned index);
/**
* \brief Get the filename that the original file was translated into.
*/
CINDEX_LINKAGE
CXString arcmt_remap_getTransformedFile(CMTRemap, unsigned index);
/**
* \brief Dispose the remapping.
*/
CINDEX_LINKAGE void arcmt_remap_dispose(CMTRemap);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -41,6 +41,23 @@ bool applyTransformations(CompilerInvocation &origCI,
llvm::StringRef Filename, InputKind Kind,
DiagnosticClient *DiagClient);
/// \brief Applies automatic modifications and produces temporary files
/// and metadata into the \arg outputDir path.
///
/// \returns false if no error is produced, true otherwise.
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
llvm::StringRef Filename, InputKind Kind,
DiagnosticClient *DiagClient,
llvm::StringRef outputDir);
/// \brief Get the set of file remappings from the \arg outputDir path that
/// migrateWithTemporaryFiles produced.
///
/// \returns false if no error is produced, true otherwise.
bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
llvm::StringRef outputDir,
DiagnosticClient *DiagClient);
typedef void (*TransformFn)(MigrationPass &pass);
std::vector<TransformFn> getAllTransformations();
@ -51,8 +68,8 @@ class MigrationProcess {
FileRemapper Remapper;
public:
MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient)
: OrigCI(CI), DiagClient(diagClient) { }
MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient,
llvm::StringRef outputDir = llvm::StringRef());
class RewriteListener {
public:

View File

@ -24,12 +24,21 @@ public:
CheckAction(FrontendAction *WrappedAction);
};
class TransformationAction : public WrapperFrontendAction {
class ModifyAction : public WrapperFrontendAction {
protected:
virtual bool BeginInvocation(CompilerInstance &CI);
public:
TransformationAction(FrontendAction *WrappedAction);
ModifyAction(FrontendAction *WrappedAction);
};
class MigrateAction : public WrapperFrontendAction {
std::string MigrateDir;
protected:
virtual bool BeginInvocation(CompilerInstance &CI);
public:
MigrateAction(FrontendAction *WrappedAction, llvm::StringRef migrateDir);
};
}

View File

@ -389,6 +389,10 @@ def arcmt_check : Flag<"-arcmt-check">,
HelpText<"Check for ARC migration issues that need manual handling">;
def arcmt_modify : Flag<"-arcmt-modify">,
HelpText<"Apply modifications to files to conform to ARC">;
def arcmt_migrate : Flag<"-arcmt-migrate">,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">,
HelpText<"Directory for temporary files produced during ARC migration">;
def import_module : Separate<"-import-module">,
HelpText<"Import a module definition file">;

View File

@ -118,6 +118,10 @@ def ccc_arcmt_modify : Flag<"-ccc-arcmt-modify">, CCCDriverOpt,
HelpText<"Apply modifications to files to conform to ARC">;
def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, Alias<ccc_arcmt_check>;
def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias<ccc_arcmt_modify>;
def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt,
Alias<ccc_arcmt_migrate>;
// Make sure all other -ccc- options are rejected.
def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;

View File

@ -79,9 +79,12 @@ public:
enum {
ARCMT_None,
ARCMT_Check,
ARCMT_Modify
ARCMT_Modify,
ARCMT_Migrate
} ARCMTAction;
std::string ARCMTMigrateDir;
/// The input files and their types.
std::vector<std::pair<InputKind, std::string> > Inputs;

View File

@ -269,9 +269,10 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
// applyTransformations.
//===----------------------------------------------------------------------===//
bool arcmt::applyTransformations(CompilerInvocation &origCI,
llvm::StringRef Filename, InputKind Kind,
DiagnosticClient *DiagClient) {
static bool applyTransforms(CompilerInvocation &origCI,
llvm::StringRef Filename, InputKind Kind,
DiagnosticClient *DiagClient,
llvm::StringRef outputDir) {
if (!origCI.getLangOpts().ObjC1)
return false;
@ -284,7 +285,7 @@ bool arcmt::applyTransformations(CompilerInvocation &origCI,
CInvok.getFrontendOpts().Inputs.clear();
CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
MigrationProcess migration(CInvok, DiagClient);
MigrationProcess migration(CInvok, DiagClient, outputDir);
std::vector<TransformFn> transforms = arcmt::getAllTransformations();
assert(!transforms.empty());
@ -294,12 +295,52 @@ bool arcmt::applyTransformations(CompilerInvocation &origCI,
if (err) return true;
}
origCI.getLangOpts().ObjCAutoRefCount = true;
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
if (outputDir.empty()) {
origCI.getLangOpts().ObjCAutoRefCount = true;
return migration.getRemapper().overwriteOriginal(*Diags);
} else
return migration.getRemapper().flushToDisk(outputDir, *Diags);
}
bool arcmt::applyTransformations(CompilerInvocation &origCI,
llvm::StringRef Filename, InputKind Kind,
DiagnosticClient *DiagClient) {
return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef());
}
bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI,
llvm::StringRef Filename, InputKind Kind,
DiagnosticClient *DiagClient,
llvm::StringRef outputDir) {
assert(!outputDir.empty() && "Expected output directory path");
return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir);
}
bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
remap,
llvm::StringRef outputDir,
DiagnosticClient *DiagClient) {
assert(!outputDir.empty());
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
return migration.getRemapper().overwriteOriginal(*Diags);
FileRemapper remapper;
bool err = remapper.initFromDisk(outputDir, *Diags,
/*ignoreIfFilesChanged=*/true);
if (err)
return true;
CompilerInvocation CI;
remapper.applyMappings(CI);
remap = CI.getPreprocessorOpts().RemappedFiles;
return false;
}
//===----------------------------------------------------------------------===//
@ -382,6 +423,18 @@ public:
/// \brief Anchor for VTable.
MigrationProcess::RewriteListener::~RewriteListener() { }
MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
DiagnosticClient *diagClient,
llvm::StringRef outputDir)
: OrigCI(CI), DiagClient(diagClient) {
if (!outputDir.empty()) {
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
}
}
bool MigrationProcess::applyTransform(TransformFn trans,
RewriteListener *listener) {
llvm::OwningPtr<CompilerInvocation> CInvok;

View File

@ -28,11 +28,26 @@ bool CheckAction::BeginInvocation(CompilerInstance &CI) {
CheckAction::CheckAction(FrontendAction *WrappedAction)
: WrapperFrontendAction(WrappedAction) {}
bool TransformationAction::BeginInvocation(CompilerInstance &CI) {
return !arcmt::applyTransformations(CI.getInvocation(), getCurrentFile(),
getCurrentFileKind(),
CI.getDiagnostics().getClient());
bool ModifyAction::BeginInvocation(CompilerInstance &CI) {
return !arcmt::applyTransformations(CI.getInvocation(),
getCurrentFile(), getCurrentFileKind(),
CI.getDiagnostics().getClient());
}
TransformationAction::TransformationAction(FrontendAction *WrappedAction)
ModifyAction::ModifyAction(FrontendAction *WrappedAction)
: WrapperFrontendAction(WrappedAction) {}
bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
return !arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
getCurrentFile(),
getCurrentFileKind(),
CI.getDiagnostics().getClient(),
MigrateDir);
}
MigrateAction::MigrateAction(FrontendAction *WrappedAction,
llvm::StringRef migrateDir)
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
}

View File

@ -71,11 +71,8 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
fin >> fromFilename >> timeModified >> toFilename;
if (fin.eof())
break;
if (!fin.good()) {
if (ignoreIfFilesChanged)
return false;
if (!fin.good())
return report(std::string("Error in format of file: ") + infoFile, Diag);
}
const FileEntry *origFE = FileMgr->getFile(fromFilename);
if (!origFE) {
@ -115,8 +112,7 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
std::string errMsg;
std::string infoFile = getRemapInfoFile(outputDir);
llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
llvm::raw_fd_ostream::F_Binary);
llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg);
if (!errMsg.empty() || infoOut.has_error())
return report(errMsg, Diag);
@ -124,11 +120,15 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
const FileEntry *origFE = I->first;
infoOut << origFE->getName() << '\n';
llvm::SmallString<200> origPath = llvm::StringRef(origFE->getName());
fs::make_absolute(origPath);
infoOut << origPath << '\n';
infoOut << (uint64_t)origFE->getModificationTime() << '\n';
if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
infoOut << FE->getName() << '\n';
llvm::SmallString<200> newPath = llvm::StringRef(FE->getName());
fs::make_absolute(newPath);
infoOut << newPath << '\n';
} else {
llvm::SmallString<64> tempPath;

View File

@ -1423,7 +1423,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_fno_objc_arc)) {
if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
options::OPT_ccc_arcmt_modify)) {
options::OPT_ccc_arcmt_modify,
options::OPT_ccc_arcmt_migrate)) {
switch (A->getOption().getID()) {
default:
llvm_unreachable("missed a case");
@ -1433,6 +1434,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case options::OPT_ccc_arcmt_modify:
CmdArgs.push_back("-arcmt-modify");
break;
case options::OPT_ccc_arcmt_migrate:
CmdArgs.push_back("-arcmt-migrate");
CmdArgs.push_back("-arcmt-migrate-directory");
CmdArgs.push_back(A->getValue(Args));
break;
}
}
}

View File

@ -431,6 +431,13 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
case FrontendOptions::ARCMT_Modify:
Res.push_back("-arcmt-modify");
break;
case FrontendOptions::ARCMT_Migrate:
Res.push_back("-arcmt-migrate");
break;
}
if (!Opts.ARCMTMigrateDir.empty()) {
Res.push_back("-arcmt-migrate-directory");
Res.push_back(Opts.ARCMTMigrateDir);
}
bool NeedLang = false;
@ -1251,7 +1258,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ARCMTAction = FrontendOptions::ARCMT_None;
if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
OPT_arcmt_modify)) {
OPT_arcmt_modify,
OPT_arcmt_migrate)) {
switch (A->getOption().getID()) {
default:
llvm_unreachable("missed a case");
@ -1261,8 +1269,12 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
case OPT_arcmt_modify:
Opts.ARCMTAction = FrontendOptions::ARCMT_Modify;
break;
case OPT_arcmt_migrate:
Opts.ARCMTAction = FrontendOptions::ARCMT_Migrate;
break;
}
}
Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory);
InputKind DashX = IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {

View File

@ -97,7 +97,10 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
Act = new arcmt::CheckAction(Act);
break;
case FrontendOptions::ARCMT_Modify:
Act = new arcmt::TransformationAction(Act);
Act = new arcmt::ModifyAction(Act);
break;
case FrontendOptions::ARCMT_Migrate:
Act = new arcmt::MigrateAction(Act, CI.getFrontendOpts().ARCMTMigrateDir);
break;
}

View File

@ -0,0 +1,15 @@
@protocol NSObject
- (oneway void)release;
@end
#ifdef PART1
static inline void part1(id p) {
[p release];
}
#endif
#ifdef PART2
static inline void part2(id p) {
[p release];
}
#endif

View File

@ -0,0 +1,13 @@
@protocol NSObject
- (oneway void)release;
@end
#ifdef PART1
static inline void part1(id p) {
}
#endif
#ifdef PART2
static inline void part2(id p) {
}
#endif

View File

@ -0,0 +1,6 @@
#define PART1
#include "test.h"
void test1(id p) {
[p release];
}

View File

@ -0,0 +1,5 @@
#define PART1
#include "test.h"
void test1(id p) {
}

View File

@ -0,0 +1,6 @@
#define PART2
#include "test.h"
void test2(id p) {
[p release];
}

View File

@ -0,0 +1,5 @@
#define PART2
#include "test.h"
void test2(id p) {
}

View File

@ -0,0 +1,3 @@
// RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: "-arcmt-migrate" "-arcmt-migrate-directory" "/foo/bar"

View File

@ -0,0 +1,4 @@
// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c -fobjc-nonfragile-abi
// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c -fobjc-nonfragile-abi
// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
// RUN: rm -rf %t

View File

@ -1,4 +1,5 @@
add_subdirectory(libclang)
add_subdirectory(c-index-test)
add_subdirectory(arcmt-test)
add_subdirectory(c-arcmt-test)
add_subdirectory(driver)

View File

@ -8,7 +8,7 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
DIRS := driver libclang c-index-test arcmt-test
DIRS := driver libclang c-index-test arcmt-test c-arcmt-test
include $(CLANG_LEVEL)/../../Makefile.config

View File

@ -14,7 +14,9 @@
#include "clang/Frontend/Utils.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
using namespace clang;
using namespace arcmt;
@ -37,6 +39,20 @@ VerifyDiags("verify",llvm::cl::desc("Verify emitted diagnostics and warnings"));
static llvm::cl::opt<bool>
VerboseOpt("v", llvm::cl::desc("Enable verbose output"));
static llvm::cl::opt<bool>
VerifyTransformedFiles("verify-transformed-files",
llvm::cl::desc("Read pairs of file mappings (typically the output of "
"c-arcmt-test) and compare their contents with the filenames "
"provided in command-line"));
static llvm::cl::opt<std::string>
RemappingsFile("remappings-file",
llvm::cl::desc("Pairs of file mappings (typically the output of "
"c-arcmt-test)"));
static llvm::cl::list<std::string>
ResultFiles(llvm::cl::Positional, llvm::cl::desc("<filename>..."));
static llvm::cl::extrahelp extraHelp(
"\nusage with compiler args: arcmt-test [options] --args [compiler flags]\n");
@ -183,6 +199,105 @@ static bool performTransformations(llvm::StringRef resourcesPath,
return false;
}
static bool filesCompareEqual(llvm::StringRef fname1, llvm::StringRef fname2) {
using namespace llvm;
OwningPtr<MemoryBuffer> file1;
MemoryBuffer::getFile(fname1, file1);
if (!file1)
return false;
OwningPtr<MemoryBuffer> file2;
MemoryBuffer::getFile(fname2, file2);
if (!file2)
return false;
return file1->getBuffer() == file2->getBuffer();
}
static bool verifyTransformedFiles(llvm::ArrayRef<std::string> resultFiles) {
using namespace llvm;
assert(!resultFiles.empty());
std::map<StringRef, StringRef> resultMap;
for (ArrayRef<std::string>::iterator
I = resultFiles.begin(), E = resultFiles.end(); I != E; ++I) {
StringRef fname(*I);
if (!fname.endswith(".result")) {
errs() << "error: filename '" << fname
<< "' does not have '.result' extension\n";
return true;
}
resultMap[sys::path::stem(fname)] = fname;
}
OwningPtr<MemoryBuffer> inputBuf;
if (RemappingsFile.empty())
MemoryBuffer::getSTDIN(inputBuf);
else
MemoryBuffer::getFile(RemappingsFile, inputBuf);
if (!inputBuf) {
errs() << "error: could not read remappings input\n";
return true;
}
SmallVector<StringRef, 8> strs;
inputBuf->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
if (strs.empty()) {
errs() << "error: no files to verify from stdin\n";
return true;
}
if (strs.size() % 2 != 0) {
errs() << "error: files to verify are not original/result pairs\n";
return true;
}
for (unsigned i = 0, e = strs.size(); i != e; i += 2) {
StringRef inputOrigFname = strs[i];
StringRef inputResultFname = strs[i+1];
std::map<StringRef, StringRef>::iterator It;
It = resultMap.find(sys::path::filename(inputOrigFname));
if (It == resultMap.end()) {
errs() << "error: '" << inputOrigFname << "' is not in the list of "
<< "transformed files to verify\n";
return true;
}
bool exists = false;
sys::fs::exists(It->second, exists);
if (!exists) {
errs() << "error: '" << It->second << "' does not exist\n";
return true;
}
sys::fs::exists(inputResultFname, exists);
if (!exists) {
errs() << "error: '" << inputResultFname << "' does not exist\n";
return true;
}
if (!filesCompareEqual(It->second, inputResultFname)) {
errs() << "error: '" << It->second << "' is different than "
<< "'" << inputResultFname << "'\n";
return true;
}
resultMap.erase(It);
}
if (!resultMap.empty()) {
for (std::map<StringRef, StringRef>::iterator
I = resultMap.begin(), E = resultMap.end(); I != E; ++I)
errs() << "error: '" << I->second << "' was not verified!\n";
return true;
}
return false;
}
//===----------------------------------------------------------------------===//
// Misc. functions.
//===----------------------------------------------------------------------===//
@ -236,7 +351,15 @@ int main(int argc, const char **argv) {
break;
}
llvm::cl::ParseCommandLineOptions(optargc, const_cast<char **>(argv), "arcmt-test");
if (VerifyTransformedFiles) {
if (ResultFiles.empty()) {
llvm::cl::PrintHelpMessage();
return 1;
}
return verifyTransformedFiles(ResultFiles);
}
if (optargc == argc) {
llvm::cl::PrintHelpMessage();
return 1;

View File

@ -0,0 +1,14 @@
set(LLVM_USED_LIBS libclang)
set( LLVM_LINK_COMPONENTS
support
mc
)
add_clang_executable(c-arcmt-test
c-arcmt-test.cpp
)
set_target_properties(c-arcmt-test
PROPERTIES
LINKER_LANGUAGE CXX)

View File

@ -0,0 +1,24 @@
##===- tools/c-arcmt-test/Makefile -------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../..
TOOLNAME = c-arcmt-test
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
# Don't install this. It is used for tests.
NO_INSTALL = 1
LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
clangRewrite.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile

View File

@ -0,0 +1,82 @@
/* c-arcmt-test.c */
#include "clang-c/ARCMigrate.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static int print_remappings(const char *path) {
CMTRemap remap;
unsigned i, N;
CXString origFname;
CXString transFname;
remap = arcmt_getRemappings(path);
if (!remap)
return 1;
N = arcmt_remap_getNumFiles(remap);
for (i = 0; i != N; ++i) {
origFname = arcmt_remap_getOriginalFile(remap, i);
transFname = arcmt_remap_getTransformedFile(remap, i);
fprintf(stdout, "%s\n", clang_getCString(origFname));
fprintf(stdout, "%s\n", clang_getCString(transFname));
clang_disposeString(origFname);
clang_disposeString(transFname);
}
arcmt_remap_dispose(remap);
return 0;
}
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
static void print_usage(void) {
fprintf(stderr,
"usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n");
}
/***/
int carcmttest_main(int argc, const char **argv) {
clang_enableStackTraces();
if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0)
return print_remappings(argv[2]);
print_usage();
return 1;
}
/***/
/* We intentionally run in a separate thread to ensure we at least minimal
* testing of a multithreaded environment (for example, having a reduced stack
* size). */
typedef struct thread_info {
int argc;
const char **argv;
int result;
} thread_info;
void thread_runner(void *client_data_v) {
thread_info *client_data = client_data_v;
client_data->result = carcmttest_main(client_data->argc, client_data->argv);
}
int main(int argc, const char **argv) {
thread_info client_data;
setenv("LIBCLANG_LOGGING", "1", /*overwrite=*/0);
if (getenv("CINDEXTEST_NOTHREADS"))
return carcmttest_main(argc, argv);
client_data.argc = argc;
client_data.argv = argv;
clang_executeOnThread(thread_runner, &client_data, 0);
return client_data.result;
}

View File

@ -0,0 +1,96 @@
//===- ARCMigrate.cpp - Clang-C ARC Migration Library ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the main API hooks in the Clang-C ARC Migration library.
//
//===----------------------------------------------------------------------===//
#include "clang-c/ARCMigrate.h"
#include "CXString.h"
#include "clang/ARCMigrate/ARCMT.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "llvm/Support/FileSystem.h"
using namespace clang;
using namespace arcmt;
namespace {
struct Remap {
std::vector<std::pair<std::string, std::string> > Vec;
};
} // anonymous namespace.
//===----------------------------------------------------------------------===//
// libClang public APIs.
//===----------------------------------------------------------------------===//
extern "C" {
CMTRemap arcmt_getRemappings(const char *migrate_dir_path) {
bool Logging = ::getenv("LIBCLANG_LOGGING");
if (!migrate_dir_path) {
if (Logging)
llvm::errs() << "arcmt_getRemappings was called with NULL parameter\n";
return 0;
}
bool exists = false;
llvm::sys::fs::exists(migrate_dir_path, exists);
if (!exists) {
if (Logging) {
llvm::errs() << "Error by arcmt_getRemappings(\"" << migrate_dir_path
<< "\")\n";
llvm::errs() << "\"" << migrate_dir_path << "\" does not exist\n";
}
return 0;
}
TextDiagnosticBuffer diagBuffer;
llvm::OwningPtr<Remap> remap(new Remap());
bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer);
if (err) {
if (Logging) {
llvm::errs() << "Error by arcmt_getRemappings(\"" << migrate_dir_path
<< "\")\n";
for (TextDiagnosticBuffer::const_iterator
I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I)
llvm::errs() << I->second << '\n';
}
return 0;
}
return remap.take();
}
unsigned arcmt_remap_getNumFiles(CMTRemap map) {
return static_cast<Remap *>(map)->Vec.size();
}
CXString arcmt_remap_getOriginalFile(CMTRemap map, unsigned index) {
return cxstring::createCXString(static_cast<Remap *>(map)->Vec[index].first,
/*DupString =*/ true);
}
CXString arcmt_remap_getTransformedFile(CMTRemap map, unsigned index) {
return cxstring::createCXString(static_cast<Remap *>(map)->Vec[index].second,
/*DupString =*/ true);
}
void arcmt_remap_dispose(CMTRemap map) {
delete static_cast<Remap *>(map);
}
} // end: extern "C"

View File

@ -1,4 +1,5 @@
set(LLVM_USED_LIBS
clangARCMigrate
clangFrontend
clangDriver
clangSerialization
@ -14,6 +15,7 @@ set( LLVM_LINK_COMPONENTS
)
set(SOURCES
ARCMigrate.cpp
CIndex.cpp
CIndexCXX.cpp
CIndexCodeCompletion.cpp
@ -25,6 +27,7 @@ set(SOURCES
CXString.cpp
CXType.cpp
../../include/clang-c/Index.h
../../include/clang-c/ARCMigrate.h
)
if( LLVM_ENABLE_PIC )

View File

@ -16,8 +16,8 @@ LINK_LIBS_IN_SHARED = 1
SHARED_LIBRARY = 1
LINK_COMPONENTS := support mc
USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
USEDLIBS = clangARCMigrate.a clangFrontend.a clangDriver.a clangSerialization.a \
clangParse.a clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile

View File

@ -137,3 +137,8 @@ _clang_toggleCrashRecovery
_clang_tokenize
_clang_visitChildren
_clang_visitChildrenWithBlock
_arcmt_getRemappings
_arcmt_remap_getNumFiles
_arcmt_remap_getOriginalFile
_arcmt_remap_getTransformedFile
_arcmt_remap_dispose

View File

@ -137,3 +137,8 @@ clang_toggleCrashRecovery
clang_tokenize
clang_visitChildren
clang_visitChildrenWithBlock
arcmt_getRemappings
arcmt_remap_getNumFiles
arcmt_remap_getOriginalFile
arcmt_remap_getTransformedFile
arcmt_remap_dispose