Skip to content

Commit

Permalink
[arcmt] Introduce new '-ccc-arcmt-migrate <path>' ARC migration drive…
Browse files Browse the repository at this point in the history
…r 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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134844 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
akyrtzi committed Jul 9, 2011
1 parent 8dd5cdf commit 69325d5
Show file tree
Hide file tree
Showing 31 changed files with 646 additions and 31 deletions.
79 changes: 79 additions & 0 deletions include/clang-c/ARCMigrate.h
Original file line number Diff line number Diff line change
@@ -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

21 changes: 19 additions & 2 deletions include/clang/ARCMigrate/ARCMT.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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:
Expand Down
13 changes: 11 additions & 2 deletions include/clang/ARCMigrate/ARCMTActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,21 @@ class CheckAction : public WrapperFrontendAction {
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);
};

}
Expand Down
4 changes: 4 additions & 0 deletions include/clang/Driver/CC1Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down
4 changes: 4 additions & 0 deletions include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>;
Expand Down
5 changes: 4 additions & 1 deletion include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,12 @@ class FrontendOptions {
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;

Expand Down
65 changes: 59 additions & 6 deletions lib/ARCMigrate/ARCMT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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());
Expand All @@ -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;
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -382,6 +423,18 @@ class RewritesApplicator : public TransformActions::RewriteReceiver {
/// \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;
Expand Down
25 changes: 20 additions & 5 deletions lib/ARCMigrate/ARCMTActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
16 changes: 8 additions & 8 deletions lib/ARCMigrate/FileRemapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -115,20 +112,23 @@ 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);

for (MappingsTy::iterator
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;
Expand Down
8 changes: 7 additions & 1 deletion lib/Driver/Tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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;
}
}
}
Expand Down
Loading

0 comments on commit 69325d5

Please sign in to comment.