Revert "cpp11-migrate: Fixing autoconf build after adding libclangReplace dependency"

Revert "cpp11-migrate: Refactor for driver model of operation"

This reverts commit r189691.
This reverts commit r189689.

This was breaking the phase 1 OS X build for ~2 hours.

https://smooshbase.apple.com/buildbot-internal/builders/phase1%20-%20sanity/builds/9559

I reverted the latter commit since I think the latter depended on the former.

llvm-svn: 189700
This commit is contained in:
Michael Gottesman 2013-08-30 22:09:03 +00:00
parent 79917a913e
commit 92d9cb4dd1
49 changed files with 743 additions and 711 deletions

View File

@ -29,13 +29,13 @@ static cl::opt<bool> DetectMacros(
cl::desc("Detect and use macros that expand to the 'override' keyword."), cl::desc("Detect and use macros that expand to the 'override' keyword."),
cl::cat(TransformsOptionsCategory)); cl::cat(TransformsOptionsCategory));
int AddOverrideTransform::apply(const FileOverrides &InputStates, int AddOverrideTransform::apply(FileOverrides &InputStates,
const CompilationDatabase &Database, const CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) { const std::vector<std::string> &SourcePaths) {
ClangTool AddOverrideTool(Database, SourcePaths); ClangTool AddOverrideTool(Database, SourcePaths);
unsigned AcceptedChanges = 0; unsigned AcceptedChanges = 0;
MatchFinder Finder; MatchFinder Finder;
AddOverrideFixer Fixer(AcceptedChanges, DetectMacros, AddOverrideFixer Fixer(getReplacements(), AcceptedChanges, DetectMacros,
/*Owner=*/ *this); /*Owner=*/ *this);
Finder.addMatcher(makeCandidateForOverrideAttrMatcher(), &Fixer); Finder.addMatcher(makeCandidateForOverrideAttrMatcher(), &Fixer);

View File

@ -31,7 +31,7 @@ public:
: Transform("AddOverride", Options) {} : Transform("AddOverride", Options) {}
/// \see Transform::run(). /// \see Transform::run().
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;

View File

@ -95,7 +95,6 @@ void AddOverrideFixer::run(const MatchFinder::MatchResult &Result) {
if (!MacroName.empty()) if (!MacroName.empty())
ReplacementText = (" " + MacroName).str(); ReplacementText = (" " + MacroName).str();
} }
Owner.addReplacementForCurrentTU( Replace.insert(tooling::Replacement(SM, StartLoc, 0, ReplacementText));
tooling::Replacement(SM, StartLoc, 0, ReplacementText));
++AcceptedChanges; ++AcceptedChanges;
} }

View File

@ -25,10 +25,11 @@ class Transform;
/// ///
class AddOverrideFixer : public clang::ast_matchers::MatchFinder::MatchCallback { class AddOverrideFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
AddOverrideFixer(unsigned &AcceptedChanges, bool DetectMacros, AddOverrideFixer(clang::tooling::Replacements &Replace,
Transform &Owner) unsigned &AcceptedChanges, bool DetectMacros,
: AcceptedChanges(AcceptedChanges), DetectMacros(DetectMacros), const Transform &Owner)
Owner(Owner) {} : Replace(Replace), AcceptedChanges(AcceptedChanges),
DetectMacros(DetectMacros), Owner(Owner) {}
/// \brief Entry point to the callback called when matches are made. /// \brief Entry point to the callback called when matches are made.
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result); virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result);
@ -37,9 +38,10 @@ public:
private: private:
clang::Preprocessor *PP; clang::Preprocessor *PP;
clang::tooling::Replacements &Replace;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
bool DetectMacros; bool DetectMacros;
Transform &Owner; const Transform &Owner;
}; };
#endif // CPP11_MIGRATE_ADD_OVERRIDE_ACTIONS_H #endif // CPP11_MIGRATE_ADD_OVERRIDE_ACTIONS_H

View File

@ -1,10 +1,4 @@
get_filename_component(ClangReplaceLocation include_directories(${CMAKE_CURRENT_SOURCE_DIR})
"${CMAKE_CURRENT_SOURCE_DIR}/../clang-replace/include" ABSOLUTE)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${ClangReplaceLocation}
)
add_subdirectory(tool) add_subdirectory(tool)
add_subdirectory(Core) add_subdirectory(Core)

View File

@ -29,14 +29,157 @@
using namespace clang; using namespace clang;
using namespace clang::tooling; using namespace clang::tooling;
bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, void HeaderOverride::recordReplacements(
llvm::SmallVectorImpl<char> &Result, const clang::tooling::Replacements &Replaces) {
llvm::SmallVectorImpl<char> &Error) { Replacements.Replacements.resize(Replaces.size());
std::copy(Replaces.begin(), Replaces.end(),
Replacements.Replacements.begin());
}
SourceOverrides::SourceOverrides(llvm::StringRef MainFileName,
bool TrackChanges)
: MainFileName(MainFileName), TrackChanges(TrackChanges) {}
void
SourceOverrides::applyReplacements(clang::tooling::Replacements &Replaces) {
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
new DiagnosticOptions());
DiagnosticsEngine Diagnostics(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
DiagOpts.getPtr());
FileManager Files((FileSystemOptions()));
SourceManager SM(Diagnostics, Files);
applyReplacements(Replaces, SM);
}
void SourceOverrides::applyReplacements(clang::tooling::Replacements &Replaces,
clang::SourceManager &SM) {
applyOverrides(SM);
Rewriter Rewrites(SM, LangOptions());
// FIXME: applyAllReplacements will indicate if it couldn't apply all
// replacements. Handle that case.
bool Success = tooling::applyAllReplacements(Replaces, Rewrites);
if (!Success)
llvm::errs() << "error: failed to apply some replacements.";
std::string ResultBuf;
for (Rewriter::buffer_iterator I = Rewrites.buffer_begin(),
E = Rewrites.buffer_end();
I != E; ++I) {
const FileEntry *Entry =
Rewrites.getSourceMgr().getFileEntryForID(I->first);
assert(Entry != NULL && "unexpected null FileEntry");
assert(Entry->getName() != NULL &&
"unexpected null return from FileEntry::getName()");
llvm::StringRef FileName = Entry->getName();
// Get a copy of the rewritten buffer from the Rewriter.
ResultBuf.clear();
llvm::raw_string_ostream StringStream(ResultBuf);
I->second.write(StringStream);
StringStream.flush();
if (MainFileName == FileName) {
MainFileOverride.swap(ResultBuf);
continue;
}
// Header overrides are treated differently. Eventually, raw replacements
// will be stored as well for later output to disk. Applying replacements
// in memory will always be necessary as the source goes down the transform
// pipeline.
HeaderOverride &HeaderOv = Headers[FileName];
// "Create" HeaderOverride if not already existing
if (HeaderOv.getHeaderPath().empty())
HeaderOv = HeaderOverride(FileName, MainFileName);
HeaderOv.swapContentOverride(ResultBuf);
}
// Separate replacements to header files
Replacements MainFileReplaces;
ReplacementsMap HeadersReplaces;
for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
I != E; ++I) {
llvm::StringRef ReplacementFileName = I->getFilePath();
if (ReplacementFileName == MainFileName) {
MainFileReplaces.insert(*I);
continue;
}
HeadersReplaces[ReplacementFileName].insert(*I);
}
// Record all replacements to headers.
for (ReplacementsMap::const_iterator I = HeadersReplaces.begin(),
E = HeadersReplaces.end();
I != E; ++I) {
HeaderOverride &HeaderOv = Headers[I->getKey()];
HeaderOv.recordReplacements(I->getValue());
}
if (TrackChanges)
adjustChangedRanges(MainFileReplaces, HeadersReplaces);
}
void
SourceOverrides::adjustChangedRanges(const Replacements &MainFileReplaces,
const ReplacementsMap &HeadersReplaces) {
// Adjust the changed ranges for each individual file
MainFileChanges.adjustChangedRanges(MainFileReplaces);
for (ReplacementsMap::const_iterator I = HeadersReplaces.begin(),
E = HeadersReplaces.end();
I != E; ++I) {
Headers[I->getKey()].adjustChangedRanges(I->getValue());
}
}
void SourceOverrides::applyOverrides(SourceManager &SM) const {
FileManager &FM = SM.getFileManager();
if (isSourceOverriden())
SM.overrideFileContents(FM.getFile(MainFileName),
llvm::MemoryBuffer::getMemBuffer(MainFileOverride));
for (HeaderOverrides::const_iterator I = Headers.begin(), E = Headers.end();
I != E; ++I) {
assert(!I->second.getContentOverride().empty() &&
"Header override should not be empty!");
SM.overrideFileContents(
FM.getFile(I->second.getHeaderPath()),
llvm::MemoryBuffer::getMemBuffer(I->second.getContentOverride()));
}
}
bool generateReplacementsFileName(llvm::StringRef SourceFile,
llvm::StringRef HeaderFile,
llvm::SmallVectorImpl<char> &Result,
llvm::SmallVectorImpl<char> &Error) {
using namespace llvm::sys; using namespace llvm::sys;
std::string UniqueHeaderNameModel;
// Get the filename portion of the path.
llvm::StringRef SourceFileRef(path::filename(SourceFile));
llvm::StringRef HeaderFileRef(path::filename(HeaderFile));
// Get the actual path for the header file.
llvm::SmallString<128> HeaderPath(HeaderFile);
path::remove_filename(HeaderPath);
// Build the model of the filename.
llvm::raw_string_ostream UniqueHeaderNameStream(UniqueHeaderNameModel);
UniqueHeaderNameStream << SourceFileRef << "_" << HeaderFileRef
<< "_%%_%%_%%_%%_%%_%%" << ".yaml";
path::append(HeaderPath, UniqueHeaderNameStream.str());
Error.clear(); Error.clear();
if (llvm::error_code EC = fs::createUniqueFile( if (llvm::error_code EC =
MainSourceFile + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { fs::createUniqueFile(HeaderPath.c_str(), Result)) {
Error.append(EC.message().begin(), EC.message().end()); Error.append(EC.message().begin(), EC.message().end());
return false; return false;
} }
@ -44,6 +187,20 @@ bool generateReplacementsFileName(const llvm::StringRef MainSourceFile,
return true; return true;
} }
FileOverrides::~FileOverrides() {
for (SourceOverridesMap::iterator I = Overrides.begin(), E = Overrides.end();
I != E; ++I)
delete I->getValue();
}
SourceOverrides &FileOverrides::getOrCreate(llvm::StringRef Filename) {
SourceOverrides *&Override = Overrides[Filename];
if (Override == NULL)
Override = new SourceOverrides(Filename, TrackChanges);
return *Override;
}
namespace { namespace {
/// \brief Comparator to be able to order tooling::Range based on their offset. /// \brief Comparator to be able to order tooling::Range based on their offset.
@ -90,11 +247,10 @@ struct RangeReplacedAdjuster {
} // end anonymous namespace } // end anonymous namespace
void void ChangedRanges::adjustChangedRanges(const tooling::Replacements &Replaces) {
ChangedRanges::adjustChangedRanges(const tooling::ReplacementsVec &Replaces) {
// first adjust existing ranges in case they overlap with the replacements // first adjust existing ranges in case they overlap with the replacements
for (ReplacementsVec::const_iterator I = Replaces.begin(), E = Replaces.end(); for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
I != E; ++I) { ++I) {
const tooling::Replacement &Replace = *I; const tooling::Replacement &Replace = *I;
std::transform(Ranges.begin(), Ranges.end(), Ranges.begin(), std::transform(Ranges.begin(), Ranges.end(), Ranges.begin(),
@ -109,8 +265,8 @@ ChangedRanges::adjustChangedRanges(const tooling::ReplacementsVec &Replaces) {
} }
// then generate the new ranges from the replacements // then generate the new ranges from the replacements
for (ReplacementsVec::const_iterator I = Replaces.begin(), E = Replaces.end(); for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
I != E; ++I) { ++I) {
const tooling::Replacement &R = *I; const tooling::Replacement &R = *I;
unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset()); unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset());
unsigned Length = R.getReplacementText().size(); unsigned Length = R.getReplacementText().size();
@ -147,52 +303,3 @@ void ChangedRanges::coalesceRanges() {
std::mem_fun_ref(&Range::contains)), std::mem_fun_ref(&Range::contains)),
Ranges.end()); Ranges.end());
} }
void FileOverrides::applyOverrides(clang::SourceManager &SM) const {
FileManager &FM = SM.getFileManager();
for (FileStateMap::const_iterator I = FileStates.begin(),
E = FileStates.end();
I != E; ++I) {
SM.overrideFileContents(FM.getFile(I->getKey()),
llvm::MemoryBuffer::getMemBuffer(I->getValue()));
}
}
void FileOverrides::adjustChangedRanges(
const clang::replace::FileToReplacementsMap &Replaces) {
for (replace::FileToReplacementsMap::const_iterator I = Replaces.begin(),
E = Replaces.end(); I != E; ++I) {
ChangeTracking[I->getKey()].adjustChangedRanges(I->getValue());
}
}
void FileOverrides::updateState(const clang::Rewriter &Rewrites) {
for (Rewriter::const_buffer_iterator BufferI = Rewrites.buffer_begin(),
BufferE = Rewrites.buffer_end();
BufferI != BufferE; ++BufferI) {
const char *FileName =
Rewrites.getSourceMgr().getFileEntryForID(BufferI->first)->getName();
const RewriteBuffer &RewriteBuf = BufferI->second;
FileStates[FileName].assign(RewriteBuf.begin(), RewriteBuf.end());
}
}
bool FileOverrides::writeToDisk(DiagnosticsEngine &Diagnostics) const {
bool Errors = false;
for (FileStateMap::const_iterator I = FileStates.begin(),
E = FileStates.end();
I != E; ++I) {
std::string ErrorInfo;
// The extra transform through std::string is to ensure null-termination
// of the filename stored as the key of the StringMap.
llvm::raw_fd_ostream FileStream(I->getKey().str().c_str(), ErrorInfo);
if (!ErrorInfo.empty()) {
llvm::errs() << "Failed to write new state for " << I->getKey() << ".\n";
Errors = true;
}
FileStream << I->getValue();
}
return !Errors;
}

View File

@ -16,8 +16,7 @@
#ifndef CPP11_MIGRATE_FILE_OVERRIDES_H #ifndef CPP11_MIGRATE_FILE_OVERRIDES_H
#define CPP11_MIGRATE_FILE_OVERRIDES_H #define CPP11_MIGRATE_FILE_OVERRIDES_H
#include "Core/Refactoring.h" #include "clang/Tooling/Refactoring.h"
#include "clang-replace/Tooling/ApplyReplacements.h"
#include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/ReplacementsYaml.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
@ -45,13 +44,13 @@ public:
/// to remove replaced parts. /// to remove replaced parts.
/// ///
/// Note that all replacements should come from the same file. /// Note that all replacements should come from the same file.
void adjustChangedRanges(const clang::tooling::ReplacementsVec &Replaces); void adjustChangedRanges(const clang::tooling::Replacements &Replaces);
/// \brief Iterators. /// \brief Iterators.
/// \{ /// @{
const_iterator begin() const { return Ranges.begin(); } const_iterator begin() const { return Ranges.begin(); }
const_iterator end() const { return Ranges.end(); } const_iterator end() const { return Ranges.end(); }
/// \} /// @}
private: private:
void coalesceRanges(); void coalesceRanges();
@ -59,71 +58,178 @@ private:
RangeVec Ranges; RangeVec Ranges;
}; };
/// \brief Maintains current state of transformed files and tracks source ranges /// \brief Container for storing override information for a single headers.
/// where changes have been made. class HeaderOverride {
class FileOverrides {
public: public:
/// \brief Maps file names to file contents. /// \brief Constructors.
typedef llvm::StringMap<std::string> FileStateMap; /// @{
HeaderOverride() {}
HeaderOverride(llvm::StringRef HeaderPath,
llvm::StringRef MainSourceFile) : HeaderPath(HeaderPath) {
Replacements.MainSourceFile = MainSourceFile;
}
/// @}
/// \brief Maps file names to change tracking info for a file. /// \brief Getter for HeaderPath.
typedef llvm::StringMap<ChangedRanges> ChangeMap; llvm::StringRef getHeaderPath() const {
return HeaderPath;
/// \brief Override file contents seen by \c SM for all files stored by this
/// object.
void applyOverrides(clang::SourceManager &SM) const;
/// \brief Update change tracking information based on replacements stored in
/// \c Replaces.
void
adjustChangedRanges(const clang::replace::FileToReplacementsMap &Replaces);
/// \brief Accessor for change tracking information.
const ChangeMap &getChangedRanges() const {
return ChangeTracking;
} }
/// \brief Coalesce changes stored in \c Rewrites and replace file contents /// \brief Accessor for ContentOverride.
/// overrides stored in this object. /// @{
/// llvm::StringRef getContentOverride() const { return ContentOverride; }
/// \param Rewrites Rewriter containing changes to files. void setContentOverride(const llvm::StringRef S) { ContentOverride = S; }
void updateState(const clang::Rewriter &Rewrites); /// @}
/// \brief Accessor for current file state. /// \brief Getter for Changes.
const FileStateMap &getState() const { return FileStates; } const ChangedRanges &getChanges() const { return Changes; }
/// \brief Write all file contents overrides to disk. /// \brief Swaps the content of ContentOverride with \p S.
/// void swapContentOverride(std::string &S) { ContentOverride.swap(S); }
/// \param Diagnostics DiagnosticsEngine for error output.
/// /// \brief Getter for Replacements.
/// \returns \li true if all files with overridden file contents were written const clang::tooling::TranslationUnitReplacements &getReplacements() const {
/// to disk successfully. return Replacements;
/// \li false if any failure occurred. }
bool writeToDisk(clang::DiagnosticsEngine &Diagnostics) const;
/// \brief Stores the replacements made by a transform to the header this
/// object represents.
void recordReplacements(const clang::tooling::Replacements &Replaces);
/// \brief Helper function to adjust the changed ranges.
void adjustChangedRanges(const clang::tooling::Replacements &Replaces) {
Changes.adjustChangedRanges(Replaces);
}
private: private:
FileStateMap FileStates; std::string ContentOverride;
ChangeMap ChangeTracking; ChangedRanges Changes;
std::string HeaderPath;
clang::tooling::TranslationUnitReplacements Replacements;
};
/// \brief Container mapping header file names to override information.
typedef llvm::StringMap<HeaderOverride> HeaderOverrides;
/// \brief Container storing the file content overrides for a source file and
/// any headers included by the source file either directly or indirectly to
/// which changes have been made.
class SourceOverrides {
public:
SourceOverrides(llvm::StringRef MainFileName, bool TrackChanges);
/// \brief Accessors.
/// @{
llvm::StringRef getMainFileName() const { return MainFileName; }
llvm::StringRef getMainFileContent() const { return MainFileOverride; }
const ChangedRanges &getChangedRanges() const { return MainFileChanges; }
/// \brief Is file change tracking enabled?
///
/// Tracking file changes can be useful to reformat the code for example.
bool isTrackingFileChanges() const { return TrackChanges; }
/// @}
/// \brief Indicates if the source file has been overridden.
///
/// It's possible for a source to remain unchanged while only headers are
/// changed.
bool isSourceOverriden() const { return !MainFileOverride.empty(); }
/// \brief Override the file contents by applying all the replacements.
///
/// \param Replaces The replacements to apply.
/// \param SM A user provided SourceManager to be used when applying rewrites.
void applyReplacements(clang::tooling::Replacements &Replaces,
clang::SourceManager &SM);
void applyReplacements(clang::tooling::Replacements &Replaces);
/// \brief Convenience function for applying this source's overrides to
/// the given SourceManager.
void applyOverrides(clang::SourceManager &SM) const;
/// \brief Iterators.
/// @{
HeaderOverrides::iterator headers_begin() { return Headers.begin(); }
HeaderOverrides::iterator headers_end() { return Headers.end(); }
HeaderOverrides::const_iterator headers_begin() const {
return Headers.begin();
}
HeaderOverrides::const_iterator headers_end() const { return Headers.end(); }
/// @}
private:
typedef llvm::StringMap<clang::tooling::Replacements> ReplacementsMap;
/// \brief Flatten the Rewriter buffers of \p Rewrite and store results as
/// file content overrides.
void applyRewrites(clang::Rewriter &Rewrite);
/// \brief Adjust the changed ranges to reflect the parts of the files that
/// have been replaced.
void adjustChangedRanges(const clang::tooling::Replacements &Replaces,
const ReplacementsMap &HeadersReplaces);
const std::string MainFileName;
std::string MainFileOverride;
const bool TrackChanges;
ChangedRanges MainFileChanges;
HeaderOverrides Headers;
};
/// \brief Maps source file names to content override information.
class FileOverrides {
public:
typedef llvm::StringMap<SourceOverrides *> SourceOverridesMap;
typedef SourceOverridesMap::const_iterator const_iterator;
/// \brief Construct the SourceOverrides manager.
///
/// \param TrackChanges Wether or not the \c SourceOverrides should keep track
/// of changes. See \c SourceOverrides::isTrackingFileChanges().
FileOverrides(bool TrackChanges) : TrackChanges(TrackChanges) {}
~FileOverrides();
const_iterator find(llvm::StringRef Filename) const {
return Overrides.find(Filename);
}
/// \brief Get the \c SourceOverrides for \p Filename, creating it if
/// necessary.
SourceOverrides &getOrCreate(llvm::StringRef Filename);
/// \brief Iterators.
/// @{
const_iterator begin() const { return Overrides.begin(); }
const_iterator end() const { return Overrides.end(); }
/// @}
private:
FileOverrides(const FileOverrides &) LLVM_DELETED_FUNCTION;
FileOverrides &operator=(const FileOverrides &) LLVM_DELETED_FUNCTION;
SourceOverridesMap Overrides;
const bool TrackChanges;
}; };
/// \brief Generate a unique filename to store the replacements. /// \brief Generate a unique filename to store the replacements.
/// ///
/// Generates a unique filename in the same directory as \c MainSourceFile. The /// Generates a unique filename in the same directory as the header file. The
/// filename is generated following this pattern: /// filename is based on the following model:
/// ///
/// MainSourceFile_%%_%%_%%_%%_%%_%%.yaml /// source.cpp_header.h_%%_%%_%%_%%_%%_%%.yaml
/// ///
/// where all '%' will be replaced by a randomly chosen hex number. /// where all '%' will be replaced by a randomly chosen hex number.
/// ///
/// \param[in] MainSourceFile Full path to the source file. /// @param SourceFile Full path to the source file.
/// \param[out] Result The resulting unique filename in the same directory as /// @param HeaderFile Full path to the header file.
/// the \c MainSourceFile. /// @param Result The resulting unique filename in the same directory as the
/// \param[out] Error If an error occurs a description of that error is /// header file.
/// placed in this string. /// @param Error Description of the error if there is any.
/// \returns true on success, false if a unique file name could not be created. /// @returns true if succeeded, false otherwise.
bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, bool generateReplacementsFileName(llvm::StringRef SourceFile,
llvm::SmallVectorImpl<char> &Result, llvm::StringRef HeaderFile,
llvm::SmallVectorImpl<char> &Error); llvm::SmallVectorImpl<char> &Result,
llvm::SmallVectorImpl<char> &Error);
#endif // CPP11_MIGRATE_FILE_OVERRIDES_H #endif // CPP11_MIGRATE_FILE_OVERRIDES_H

View File

@ -11,4 +11,4 @@ LIBRARYNAME := migrateCore
include $(CLANG_LEVEL)/Makefile include $(CLANG_LEVEL)/Makefile
CPP.Flags += -I$(PROJ_SRC_DIR)/.. -I$(PROJ_SRC_DIR)/../../clang-replace/include CPP.Flags += -I$(PROJ_SRC_DIR)/..

View File

@ -1,31 +0,0 @@
//===-- Core/Refactoring.h - Stand-in for Tooling/Refactoring.h -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file is meant to be used instead of clang/Tooling/Refactoring.h
/// until such time as clang::tooling::Replacements is re-implemented as a
/// vector instead of a set.
///
//===----------------------------------------------------------------------===//
#ifndef CPP11_MIGRATE_REPLACEMENTS_VEC_H
#define CPP11_MIGRATE_REPLACEMENTS_VEC_H
#include "clang/Tooling/Refactoring.h"
// FIXME: Remove this file when clang::tooling::Replacements becomes a vector
// instead of a set.
namespace clang {
namespace tooling {
typedef std::vector<clang::tooling::Replacement> ReplacementsVec;
}
}
#endif // CPP11_MIGRATE_REPLACEMENTS_VEC_H

View File

@ -22,23 +22,39 @@
using namespace clang; using namespace clang;
void Reformatter::reformatChanges(const FileOverrides &FileStates, void Reformatter::reformatChanges(SourceOverrides &Overrides) {
clang::SourceManager &SM, llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
clang::tooling::ReplacementsVec &Replaces) { new DiagnosticOptions());
FileStates.applyOverrides(SM); DiagnosticsEngine Diagnostics(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
DiagOpts.getPtr());
FileManager Files((FileSystemOptions()));
SourceManager SM(Diagnostics, Files);
for (FileOverrides::ChangeMap::const_iterator reformatChanges(Overrides, SM);
I = FileStates.getChangedRanges().begin(),
E = FileStates.getChangedRanges().end();
I != E; ++I) {
reformatSingleFile(I->getKey(), I->getValue(), SM, Replaces);
}
} }
void Reformatter::reformatSingleFile( void Reformatter::reformatChanges(SourceOverrides &Overrides,
const llvm::StringRef FileName, const ChangedRanges &Changes, clang::SourceManager &SM) {
SourceManager &SM, clang::tooling::ReplacementsVec &FormatReplacements) { tooling::Replacements Replaces;
Overrides.applyOverrides(SM);
if (Overrides.isSourceOverriden())
Replaces = reformatSingleFile(Overrides.getMainFileName(),
Overrides.getChangedRanges(), SM);
for (HeaderOverrides::const_iterator I = Overrides.headers_begin(),
E = Overrides.headers_end();
I != E; ++I) {
const HeaderOverride &Header = I->getValue();
const tooling::Replacements &HeaderReplaces =
reformatSingleFile(Header.getHeaderPath(), Header.getChanges(), SM);
Replaces.insert(HeaderReplaces.begin(), HeaderReplaces.end());
}
Overrides.applyReplacements(Replaces, SM);
}
tooling::Replacements Reformatter::reformatSingleFile(
llvm::StringRef FileName, const ChangedRanges &Changes, SourceManager &SM) {
const clang::FileEntry *Entry = SM.getFileManager().getFile(FileName); const clang::FileEntry *Entry = SM.getFileManager().getFile(FileName);
assert(Entry && "expected an existing file"); assert(Entry && "expected an existing file");
@ -56,7 +72,5 @@ void Reformatter::reformatSingleFile(
} }
Lexer Lex(ID, SM.getBuffer(ID), SM, getFormattingLangOpts(Style.Standard)); Lexer Lex(ID, SM.getBuffer(ID), SM, getFormattingLangOpts(Style.Standard));
const tooling::Replacements &R = return format::reformat(Style, Lex, SM, ReformatRanges);
format::reformat(Style, Lex, SM, ReformatRanges);
std::copy(R.begin(), R.end(), std::back_inserter(FormatReplacements));
} }

View File

@ -16,10 +16,9 @@
#ifndef CPP11_MIGRATE_REFORMATTING_H #ifndef CPP11_MIGRATE_REFORMATTING_H
#define CPP11_MIGRATE_REFORMATTING_H #define CPP11_MIGRATE_REFORMATTING_H
#include "Core/Refactoring.h"
#include "clang/Format/Format.h" #include "clang/Format/Format.h"
class FileOverrides; class SourceOverrides;
class ChangedRanges; class ChangedRanges;
class Reformatter { class Reformatter {
@ -28,30 +27,31 @@ public:
/// \brief Reformat the changes made to the file overrides. /// \brief Reformat the changes made to the file overrides.
/// ///
/// This function will apply the state of files stored in \c FileState to \c /// \param Overrides Overriden source files to reformat. Note that since only
/// SM. /// the changes are reformatted, file change tracking has to be enabled.
/// \param SM A SourceManager where the overridens files can be found.
/// ///
/// \param[in] FileState Files to reformat. /// \sa \c SourceOverrides::isTrackingFileChanges()
/// \param[in] SM SourceManager for access to source files. void reformatChanges(SourceOverrides &Overrides, clang::SourceManager &SM);
/// \param[out] Replaces Container to store all reformatting replacements.
void reformatChanges(const FileOverrides &FileState, clang::SourceManager &SM, /// \brief Overload of \c reformatChanges() providing it's own
clang::tooling::ReplacementsVec &Replaces); /// \c SourceManager.
void reformatChanges(SourceOverrides &Overrides);
/// \brief Produce a list of replacements to apply on \p FileName, only the /// \brief Produce a list of replacements to apply on \p FileName, only the
/// ranges in \p Changes are replaced. /// ranges in \p Changes are replaced.
/// ///
/// Since this routine use \c clang::format::reformat() the rules that /// Since this routine use \c clang::format::reformat() the rules that applies
/// function applies to ranges also apply here. /// on the ranges are identical:
/// ///
/// \param[in] FileName Name of file to reformat. /// \par
/// \param[in] Changes Description of where changes were made to the file. /// Each range is extended on either end to its next bigger logic
/// \param[in] SM SourceManager required to create replacements. /// unit, i.e. everything that might influence its formatting or might be
/// \param[out] FormatReplacements New reformatting replacements are appended /// influenced by its formatting.
/// to this container. /// -- \c clang::format::reformat()
void reformatSingleFile(const llvm::StringRef FileName, clang::tooling::Replacements reformatSingleFile(llvm::StringRef FileName,
const ChangedRanges &Changes, const ChangedRanges &Changes,
clang::SourceManager &SM, clang::SourceManager &SM);
clang::tooling::ReplacementsVec &FormatReplacements);
private: private:
clang::format::FormatStyle Style; clang::format::FormatStyle Style;

View File

@ -30,7 +30,9 @@ public:
if (!SyntaxOnlyAction::BeginSourceFileAction(CI, Filename)) if (!SyntaxOnlyAction::BeginSourceFileAction(CI, Filename))
return false; return false;
Overrides.applyOverrides(CI.getSourceManager()); FileOverrides::const_iterator I = Overrides.find(Filename);
if (I != Overrides.end())
I->second->applyOverrides(CI.getSourceManager());
return true; return true;
} }

View File

@ -100,8 +100,13 @@ bool Transform::isFileModifiable(const SourceManager &SM,
bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) {
assert(Overrides != 0 && "Subclass transform didn't provide InputState"); assert(Overrides != 0 && "Subclass transform didn't provide InputState");
Overrides->applyOverrides(CI.getSourceManager()); CurrentSource = Filename.str();
CurrentSource = Filename;
FileOverrides::const_iterator I = Overrides->find(CurrentSource);
if (I != Overrides->end())
I->second->applyOverrides(CI.getSourceManager());
Replace.clear();
if (Options().EnableTiming) { if (Options().EnableTiming) {
Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord())); Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord()));
@ -111,7 +116,11 @@ bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) {
} }
void Transform::handleEndSource() { void Transform::handleEndSource() {
CurrentSource.clear(); if (!getReplacements().empty()) {
SourceOverrides &SO = Overrides->getOrCreate(CurrentSource);
SO.applyReplacements(getReplacements());
}
if (Options().EnableTiming) if (Options().EnableTiming)
Timings.back().second += llvm::TimeRecord::getCurrentTime(false); Timings.back().second += llvm::TimeRecord::getCurrentTime(false);
} }
@ -120,19 +129,6 @@ void Transform::addTiming(llvm::StringRef Label, llvm::TimeRecord Duration) {
Timings.push_back(std::make_pair(Label.str(), Duration)); Timings.push_back(std::make_pair(Label.str(), Duration));
} }
bool
Transform::addReplacementForCurrentTU(const clang::tooling::Replacement &R) {
if (CurrentSource.empty())
return false;
TranslationUnitReplacements &TU = Replacements[CurrentSource];
if (TU.MainSourceFile.empty())
TU.MainSourceFile = CurrentSource;
TU.Replacements.push_back(R);
return true;
}
FrontendActionFactory *Transform::createActionFactory(MatchFinder &Finder) { FrontendActionFactory *Transform::createActionFactory(MatchFinder &Finder) {
return new ActionFactory(Finder, /*Owner=*/ *this); return new ActionFactory(Finder, /*Owner=*/ *this);
} }

View File

@ -17,7 +17,7 @@
#define CPP11_MIGRATE_TRANSFORM_H #define CPP11_MIGRATE_TRANSFORM_H
#include "Core/IncludeExcludeInfo.h" #include "Core/IncludeExcludeInfo.h"
#include "Core/Refactoring.h" #include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Registry.h" #include "llvm/Support/Registry.h"
@ -52,12 +52,6 @@ class MatchFinder;
class FileOverrides; class FileOverrides;
// \brief Maps main source file names to a TranslationUnitReplacements
// structure storing replacements for that translation unit.
typedef llvm::StringMap<clang::tooling::TranslationUnitReplacements>
TUReplacementsMap;
/// \brief To group transforms' options together when printing the help. /// \brief To group transforms' options together when printing the help.
extern llvm::cl::OptionCategory TransformsOptionsCategory; extern llvm::cl::OptionCategory TransformsOptionsCategory;
@ -105,7 +99,7 @@ public:
/// SourcePaths and should take precedence over content of files on disk. /// SourcePaths and should take precedence over content of files on disk.
/// Upon return, \p ResultStates shall contain the result of performing this /// Upon return, \p ResultStates shall contain the result of performing this
/// transform on the files listed in \p SourcePaths. /// transform on the files listed in \p SourcePaths.
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) = 0; const std::vector<std::string> &SourcePaths) = 0;
@ -178,17 +172,6 @@ public:
/// \brief Return an iterator to the start of collected timing data. /// \brief Return an iterator to the start of collected timing data.
TimingVec::const_iterator timing_end() const { return Timings.end(); } TimingVec::const_iterator timing_end() const { return Timings.end(); }
/// \brief Add a Replacement to the list for the current translation unit.
///
/// \returns \li true on success
/// \li false if there is no current translation unit
bool addReplacementForCurrentTU(const clang::tooling::Replacement &R);
/// \brief Accessor to Replacements across all transformed translation units.
const TUReplacementsMap &getAllReplacements() const {
return Replacements;
}
protected: protected:
void setAcceptedChanges(unsigned Changes) { void setAcceptedChanges(unsigned Changes) {
@ -212,12 +195,16 @@ protected:
/// created with. /// created with.
const TransformOptions &Options() { return GlobalOptions; } const TransformOptions &Options() { return GlobalOptions; }
/// \brief Provide access for subclasses for the container to store
/// translation unit replacements.
clang::tooling::Replacements &getReplacements() { return Replace; }
/// \brief Affords a subclass to provide file contents overrides before /// \brief Affords a subclass to provide file contents overrides before
/// applying frontend actions. /// applying frontend actions.
/// ///
/// It is an error not to call this function before calling ClangTool::run() /// It is an error not to call this function before calling ClangTool::run()
/// with the factory provided by createActionFactory(). /// with the factory provided by createActionFactory().
void setOverrides(const FileOverrides &Overrides) { void setOverrides(FileOverrides &Overrides) {
this->Overrides = &Overrides; this->Overrides = &Overrides;
} }
@ -232,8 +219,8 @@ protected:
private: private:
const std::string Name; const std::string Name;
const TransformOptions &GlobalOptions; const TransformOptions &GlobalOptions;
const FileOverrides *Overrides; FileOverrides *Overrides;
TUReplacementsMap Replacements; clang::tooling::Replacements Replace;
std::string CurrentSource; std::string CurrentSource;
TimingVec Timings; TimingVec Timings;
unsigned AcceptedChanges; unsigned AcceptedChanges;

View File

@ -815,9 +815,9 @@ void LoopFixer::doConversion(ASTContext *Context,
// the declaration of the alias variable. This is probably a bug. // the declaration of the alias variable. This is probably a bug.
ReplacementText = ";"; ReplacementText = ";";
Owner.addReplacementForCurrentTU(Replacement( Replace->insert(Replacement(Context->getSourceManager(),
Context->getSourceManager(), CharSourceRange::getTokenRange(ReplaceRange),
CharSourceRange::getTokenRange(ReplaceRange), ReplacementText)); ReplacementText));
// No further replacements are made to the loop, since the iterator or index // No further replacements are made to the loop, since the iterator or index
// was used exactly once - in the initialization of AliasVar. // was used exactly once - in the initialization of AliasVar.
} else { } else {
@ -830,9 +830,10 @@ void LoopFixer::doConversion(ASTContext *Context,
I != E; ++I) { I != E; ++I) {
std::string ReplaceText = I->IsArrow ? VarName + "." : VarName; std::string ReplaceText = I->IsArrow ? VarName + "." : VarName;
ReplacedVarRanges->insert(std::make_pair(TheLoop, IndexVar)); ReplacedVarRanges->insert(std::make_pair(TheLoop, IndexVar));
Owner.addReplacementForCurrentTU( Replace->insert(
Replacement(Context->getSourceManager(), Replacement(Context->getSourceManager(),
CharSourceRange::getTokenRange(I->Range), ReplaceText)); CharSourceRange::getTokenRange(I->Range),
ReplaceText));
} }
} }
@ -861,9 +862,9 @@ void LoopFixer::doConversion(ASTContext *Context,
std::string TypeString = AutoRefType.getAsString(); std::string TypeString = AutoRefType.getAsString();
std::string Range = ("(" + TypeString + " " + VarName + " : " std::string Range = ("(" + TypeString + " " + VarName + " : "
+ MaybeDereference + ContainerString + ")").str(); + MaybeDereference + ContainerString + ")").str();
Owner.addReplacementForCurrentTU( Replace->insert(Replacement(Context->getSourceManager(),
Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(ParenRange),
CharSourceRange::getTokenRange(ParenRange), Range)); Range));
GeneratedDecls->insert(make_pair(TheLoop, VarName)); GeneratedDecls->insert(make_pair(TheLoop, VarName));
} }

View File

@ -41,11 +41,12 @@ enum LoopFixerKind {
class LoopFixer : public clang::ast_matchers::MatchFinder::MatchCallback { class LoopFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
LoopFixer(StmtAncestorASTVisitor *ParentFinder, LoopFixer(StmtAncestorASTVisitor *ParentFinder,
clang::tooling::Replacements *Replace,
StmtGeneratedVarNameMap *GeneratedDecls, StmtGeneratedVarNameMap *GeneratedDecls,
ReplacedVarsMap *ReplacedVarRanges, unsigned *AcceptedChanges, ReplacedVarsMap *ReplacedVarRanges, unsigned *AcceptedChanges,
unsigned *DeferredChanges, unsigned *RejectedChanges, unsigned *DeferredChanges, unsigned *RejectedChanges,
RiskLevel MaxRisk, LoopFixerKind FixerKind, Transform &Owner) RiskLevel MaxRisk, LoopFixerKind FixerKind, const Transform &Owner)
: ParentFinder(ParentFinder), : ParentFinder(ParentFinder), Replace(Replace),
GeneratedDecls(GeneratedDecls), ReplacedVarRanges(ReplacedVarRanges), GeneratedDecls(GeneratedDecls), ReplacedVarRanges(ReplacedVarRanges),
AcceptedChanges(AcceptedChanges), DeferredChanges(DeferredChanges), AcceptedChanges(AcceptedChanges), DeferredChanges(DeferredChanges),
RejectedChanges(RejectedChanges), MaxRisk(MaxRisk), RejectedChanges(RejectedChanges), MaxRisk(MaxRisk),
@ -56,6 +57,7 @@ class LoopFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
private: private:
StmtAncestorASTVisitor *ParentFinder; StmtAncestorASTVisitor *ParentFinder;
clang::tooling::Replacements *Replace;
StmtGeneratedVarNameMap *GeneratedDecls; StmtGeneratedVarNameMap *GeneratedDecls;
ReplacedVarsMap *ReplacedVarRanges; ReplacedVarsMap *ReplacedVarRanges;
unsigned *AcceptedChanges; unsigned *AcceptedChanges;
@ -63,7 +65,7 @@ class LoopFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
unsigned *RejectedChanges; unsigned *RejectedChanges;
RiskLevel MaxRisk; RiskLevel MaxRisk;
LoopFixerKind FixerKind; LoopFixerKind FixerKind;
Transform &Owner; const Transform &Owner;
/// \brief Computes the changes needed to convert a given for loop, and /// \brief Computes the changes needed to convert a given for loop, and
/// applies it. /// applies it.

View File

@ -24,7 +24,7 @@ using clang::ast_matchers::MatchFinder;
using namespace clang::tooling; using namespace clang::tooling;
using namespace clang; using namespace clang;
int LoopConvertTransform::apply(const FileOverrides &InputStates, int LoopConvertTransform::apply(FileOverrides &InputStates,
const CompilationDatabase &Database, const CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) { const std::vector<std::string> &SourcePaths) {
ClangTool LoopTool(Database, SourcePaths); ClangTool LoopTool(Database, SourcePaths);
@ -37,20 +37,20 @@ int LoopConvertTransform::apply(const FileOverrides &InputStates,
unsigned RejectedChanges = 0; unsigned RejectedChanges = 0;
MatchFinder Finder; MatchFinder Finder;
LoopFixer ArrayLoopFixer(&ParentFinder, &GeneratedDecls, &ReplacedVars, LoopFixer ArrayLoopFixer(&ParentFinder, &getReplacements(), &GeneratedDecls,
&AcceptedChanges, &DeferredChanges, &RejectedChanges, &ReplacedVars, &AcceptedChanges, &DeferredChanges,
Options().MaxRiskLevel, LFK_Array, &RejectedChanges, Options().MaxRiskLevel, LFK_Array,
/*Owner=*/ *this); /*Owner=*/ *this);
Finder.addMatcher(makeArrayLoopMatcher(), &ArrayLoopFixer); Finder.addMatcher(makeArrayLoopMatcher(), &ArrayLoopFixer);
LoopFixer IteratorLoopFixer(&ParentFinder, &GeneratedDecls, &ReplacedVars, LoopFixer IteratorLoopFixer(
&AcceptedChanges, &DeferredChanges, &ParentFinder, &getReplacements(), &GeneratedDecls, &ReplacedVars,
&RejectedChanges, Options().MaxRiskLevel, &AcceptedChanges, &DeferredChanges, &RejectedChanges,
LFK_Iterator, /*Owner=*/ *this); Options().MaxRiskLevel, LFK_Iterator, /*Owner=*/ *this);
Finder.addMatcher(makeIteratorLoopMatcher(), &IteratorLoopFixer); Finder.addMatcher(makeIteratorLoopMatcher(), &IteratorLoopFixer);
LoopFixer PseudoarrrayLoopFixer(&ParentFinder, &GeneratedDecls, &ReplacedVars, LoopFixer PseudoarrrayLoopFixer(
&AcceptedChanges, &DeferredChanges, &ParentFinder, &getReplacements(), &GeneratedDecls, &ReplacedVars,
&RejectedChanges, Options().MaxRiskLevel, &AcceptedChanges, &DeferredChanges, &RejectedChanges,
LFK_PseudoArray, /*Owner=*/ *this); Options().MaxRiskLevel, LFK_PseudoArray, /*Owner=*/ *this);
Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer); Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer);
setOverrides(InputStates); setOverrides(InputStates);

View File

@ -28,7 +28,7 @@ public:
: Transform("LoopConvert", Options) {} : Transform("LoopConvert", Options) {}
/// \see Transform::run(). /// \see Transform::run().
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;
}; };

View File

@ -21,14 +21,15 @@ using namespace clang;
using namespace clang::tooling; using namespace clang::tooling;
using namespace clang::ast_matchers; using namespace clang::ast_matchers;
int PassByValueTransform::apply(const FileOverrides &InputStates, int PassByValueTransform::apply(
const tooling::CompilationDatabase &Database, FileOverrides &InputStates, const tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) { const std::vector<std::string> &SourcePaths) {
ClangTool Tool(Database, SourcePaths); ClangTool Tool(Database, SourcePaths);
unsigned AcceptedChanges = 0; unsigned AcceptedChanges = 0;
unsigned RejectedChanges = 0; unsigned RejectedChanges = 0;
MatchFinder Finder; MatchFinder Finder;
ConstructorParamReplacer Replacer(AcceptedChanges, RejectedChanges, ConstructorParamReplacer Replacer(getReplacements(), AcceptedChanges,
RejectedChanges,
/*Owner=*/ *this); /*Owner=*/ *this);
Finder.addMatcher(makePassByValueCtorParamMatcher(), &Replacer); Finder.addMatcher(makePassByValueCtorParamMatcher(), &Replacer);

View File

@ -58,7 +58,7 @@ public:
: Transform("PassByValue", Options), Replacer(0) {} : Transform("PassByValue", Options), Replacer(0) {}
/// \see Transform::apply(). /// \see Transform::apply().
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;

View File

@ -151,21 +151,17 @@ void ConstructorParamReplacer::run(const MatchFinder::MatchResult &Result) {
const tooling::Replacement &IncludeReplace = const tooling::Replacement &IncludeReplace =
IncludeManager->addAngledInclude(STDMoveFile, "utility"); IncludeManager->addAngledInclude(STDMoveFile, "utility");
if (IncludeReplace.isApplicable()) { if (IncludeReplace.isApplicable()) {
Owner.addReplacementForCurrentTU(IncludeReplace); Replaces.insert(IncludeReplace);
AcceptedChanges++; AcceptedChanges++;
} }
// const-ref params becomes values (const Foo & -> Foo) // const-ref params becomes values (const Foo & -> Foo)
for (const Replacement *I = ParamReplaces.begin(), *E = ParamReplaces.end(); Replaces.insert(ParamReplaces.begin(), ParamReplaces.end());
I != E; ++I) {
Owner.addReplacementForCurrentTU(*I);
}
AcceptedChanges += ParamReplaces.size(); AcceptedChanges += ParamReplaces.size();
// move the value in the init-list // move the value in the init-list
Owner.addReplacementForCurrentTU(Replacement( Replaces.insert(Replacement(
SM, Initializer->getLParenLoc().getLocWithOffset(1), 0, "std::move(")); SM, Initializer->getLParenLoc().getLocWithOffset(1), 0, "std::move("));
Owner.addReplacementForCurrentTU( Replaces.insert(Replacement(SM, Initializer->getRParenLoc(), 0, ")"));
Replacement(SM, Initializer->getRParenLoc(), 0, ")"));
AcceptedChanges += 2; AcceptedChanges += 2;
} }

View File

@ -51,10 +51,11 @@ class IncludeDirectives;
class ConstructorParamReplacer class ConstructorParamReplacer
: public clang::ast_matchers::MatchFinder::MatchCallback { : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
ConstructorParamReplacer(unsigned &AcceptedChanges, unsigned &RejectedChanges, ConstructorParamReplacer(clang::tooling::Replacements &Replaces,
Transform &Owner) unsigned &AcceptedChanges, unsigned &RejectedChanges,
: AcceptedChanges(AcceptedChanges), RejectedChanges(RejectedChanges), const Transform &Owner)
Owner(Owner), IncludeManager(0) {} : Replaces(Replaces), AcceptedChanges(AcceptedChanges),
RejectedChanges(RejectedChanges), Owner(Owner), IncludeManager(0) {}
void setIncludeDirectives(IncludeDirectives *Includes) { void setIncludeDirectives(IncludeDirectives *Includes) {
IncludeManager = Includes; IncludeManager = Includes;
@ -65,9 +66,10 @@ private:
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
LLVM_OVERRIDE; LLVM_OVERRIDE;
clang::tooling::Replacements &Replaces;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
unsigned &RejectedChanges; unsigned &RejectedChanges;
Transform &Owner; const Transform &Owner;
IncludeDirectives *IncludeManager; IncludeDirectives *IncludeManager;
}; };

View File

@ -22,14 +22,16 @@ using namespace clang::tooling;
using namespace clang::ast_matchers; using namespace clang::ast_matchers;
int int
ReplaceAutoPtrTransform::apply(const FileOverrides &InputStates, ReplaceAutoPtrTransform::apply(FileOverrides &InputStates,
const CompilationDatabase &Database, const CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) { const std::vector<std::string> &SourcePaths) {
ClangTool Tool(Database, SourcePaths); ClangTool Tool(Database, SourcePaths);
unsigned AcceptedChanges = 0; unsigned AcceptedChanges = 0;
MatchFinder Finder; MatchFinder Finder;
AutoPtrReplacer Replacer(AcceptedChanges, /*Owner=*/ *this); AutoPtrReplacer Replacer(getReplacements(), AcceptedChanges,
OwnershipTransferFixer Fixer(AcceptedChanges, /*Owner=*/ *this); /*Owner=*/*this);
OwnershipTransferFixer Fixer(getReplacements(), AcceptedChanges,
/*Owner=*/*this);
Finder.addMatcher(makeAutoPtrTypeLocMatcher(), &Replacer); Finder.addMatcher(makeAutoPtrTypeLocMatcher(), &Replacer);
Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer); Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer);

View File

@ -47,7 +47,7 @@ public:
: Transform("ReplaceAutoPtr", Options) {} : Transform("ReplaceAutoPtr", Options) {}
/// \see Transform::run(). /// \see Transform::run().
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;
}; };

View File

@ -66,7 +66,7 @@ void AutoPtrReplacer::run(const MatchFinder::MatchResult &Result) {
if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions())) if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions()))
return; return;
Owner.addReplacementForCurrentTU( Replace.insert(
Replacement(SM, IdentifierLoc, strlen("auto_ptr"), "unique_ptr")); Replacement(SM, IdentifierLoc, strlen("auto_ptr"), "unique_ptr"));
++AcceptedChanges; ++AcceptedChanges;
} }
@ -101,8 +101,7 @@ void OwnershipTransferFixer::run(const MatchFinder::MatchResult &Result) {
if (!Owner.isFileModifiable(SM, Range.getBegin())) if (!Owner.isFileModifiable(SM, Range.getBegin()))
return; return;
Owner.addReplacementForCurrentTU( Replace.insert(Replacement(SM, Range.getBegin(), 0, "std::move("));
Replacement(SM, Range.getBegin(), 0, "std::move(")); Replace.insert(Replacement(SM, Range.getEnd(), 0, ")"));
Owner.addReplacementForCurrentTU(Replacement(SM, Range.getEnd(), 0, ")"));
AcceptedChanges += 2; AcceptedChanges += 2;
} }

View File

@ -25,8 +25,9 @@ class Transform;
/// using declarations. /// using declarations.
class AutoPtrReplacer : public clang::ast_matchers::MatchFinder::MatchCallback { class AutoPtrReplacer : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
AutoPtrReplacer(unsigned &AcceptedChanges, Transform &Owner) AutoPtrReplacer(clang::tooling::Replacements &Replace,
: AcceptedChanges(AcceptedChanges), Owner(Owner) {} unsigned &AcceptedChanges, const Transform &Owner)
: Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {}
/// \brief Entry point to the callback called when matches are made. /// \brief Entry point to the callback called when matches are made.
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
@ -62,8 +63,9 @@ private:
const clang::SourceManager &SM); const clang::SourceManager &SM);
private: private:
clang::tooling::Replacements &Replace;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
Transform &Owner; const Transform &Owner;
}; };
/// \brief The callback to be used to fix the ownership transfers of /// \brief The callback to be used to fix the ownership transfers of
@ -84,16 +86,18 @@ private:
class OwnershipTransferFixer class OwnershipTransferFixer
: public clang::ast_matchers::MatchFinder::MatchCallback { : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
OwnershipTransferFixer(unsigned &AcceptedChanges, Transform &Owner) OwnershipTransferFixer(clang::tooling::Replacements &Replace,
: AcceptedChanges(AcceptedChanges), Owner(Owner) {} unsigned &AcceptedChanges, const Transform &Owner)
: Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {}
/// \brief Entry point to the callback called when matches are made. /// \brief Entry point to the callback called when matches are made.
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
LLVM_OVERRIDE; LLVM_OVERRIDE;
private: private:
clang::tooling::Replacements &Replace;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
Transform &Owner; const Transform &Owner;
}; };
#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H #endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H

View File

@ -20,7 +20,7 @@ using clang::ast_matchers::MatchFinder;
using namespace clang; using namespace clang;
using namespace clang::tooling; using namespace clang::tooling;
int UseAutoTransform::apply(const FileOverrides &InputStates, int UseAutoTransform::apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) { const std::vector<std::string> &SourcePaths) {
ClangTool UseAutoTool(Database, SourcePaths); ClangTool UseAutoTool(Database, SourcePaths);
@ -28,11 +28,10 @@ int UseAutoTransform::apply(const FileOverrides &InputStates,
unsigned AcceptedChanges = 0; unsigned AcceptedChanges = 0;
MatchFinder Finder; MatchFinder Finder;
ReplacementsVec Replaces; IteratorReplacer ReplaceIterators(getReplacements(), AcceptedChanges,
IteratorReplacer ReplaceIterators(AcceptedChanges, Options().MaxRiskLevel, Options().MaxRiskLevel, /*Owner=*/ *this);
/*Owner=*/ *this); NewReplacer ReplaceNew(getReplacements(), AcceptedChanges,
NewReplacer ReplaceNew(AcceptedChanges, Options().MaxRiskLevel, Options().MaxRiskLevel, /*Owner=*/ *this);
/*Owner=*/ *this);
Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators); Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators);
Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew); Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew);

View File

@ -34,7 +34,7 @@ public:
: Transform("UseAuto", Options) {} : Transform("UseAuto", Options) {}
/// \see Transform::run(). /// \see Transform::run().
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;
}; };

View File

@ -73,7 +73,7 @@ void IteratorReplacer::run(const MatchFinder::MatchResult &Result) {
// iterators but something to keep in mind in the future. // iterators but something to keep in mind in the future.
CharSourceRange Range(TL.getSourceRange(), true); CharSourceRange Range(TL.getSourceRange(), true);
Owner.addReplacementForCurrentTU(tooling::Replacement(SM, Range, "auto")); Replace.insert(tooling::Replacement(SM, Range, "auto"));
++AcceptedChanges; ++AcceptedChanges;
} }
@ -131,9 +131,8 @@ void NewReplacer::run(const MatchFinder::MatchResult &Result) {
for (std::vector<SourceLocation>::iterator I = StarLocations.begin(), for (std::vector<SourceLocation>::iterator I = StarLocations.begin(),
E = StarLocations.end(); E = StarLocations.end();
I != E; ++I) { I != E; ++I) {
Owner.addReplacementForCurrentTU(tooling::Replacement(SM, *I, 1, "")); Replace.insert(tooling::Replacement(SM, *I, 1, ""));
} }
// FIXME: There is, however, one case we can address: when the VarDecl // FIXME: There is, however, one case we can address: when the VarDecl
// pointee is the same as the initializer, just more CV-qualified. However, // pointee is the same as the initializer, just more CV-qualified. However,
// TypeLoc information is not reliable where CV qualifiers are concerned so // TypeLoc information is not reliable where CV qualifiers are concerned so
@ -142,6 +141,6 @@ void NewReplacer::run(const MatchFinder::MatchResult &Result) {
FirstDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange(), true); FirstDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange(), true);
// Space after 'auto' to handle cases where the '*' in the pointer type // Space after 'auto' to handle cases where the '*' in the pointer type
// is next to the identifier. This avoids changing 'int *p' into 'autop'. // is next to the identifier. This avoids changing 'int *p' into 'autop'.
Owner.addReplacementForCurrentTU(tooling::Replacement(SM, Range, "auto ")); Replace.insert(tooling::Replacement(SM, Range, "auto "));
++AcceptedChanges; ++AcceptedChanges;
} }

View File

@ -25,32 +25,36 @@
class IteratorReplacer class IteratorReplacer
: public clang::ast_matchers::MatchFinder::MatchCallback { : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
IteratorReplacer(unsigned &AcceptedChanges, RiskLevel, Transform &Owner) IteratorReplacer(clang::tooling::Replacements &Replace,
: AcceptedChanges(AcceptedChanges), Owner(Owner) {} unsigned &AcceptedChanges, RiskLevel, const Transform &Owner)
: Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {}
/// \brief Entry point to the callback called when matches are made. /// \brief Entry point to the callback called when matches are made.
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
LLVM_OVERRIDE; LLVM_OVERRIDE;
private: private:
clang::tooling::Replacements &Replace;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
Transform &Owner; const Transform &Owner;
}; };
/// \brief The callback used when replacing type specifiers of variable /// \brief The callback used when replacing type specifiers of variable
/// declarations initialized by a C++ new expression. /// declarations initialized by a C++ new expression.
class NewReplacer : public clang::ast_matchers::MatchFinder::MatchCallback { class NewReplacer : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
NewReplacer(unsigned &AcceptedChanges, RiskLevel, Transform &Owner) NewReplacer(clang::tooling::Replacements &Replace, unsigned &AcceptedChanges,
: AcceptedChanges(AcceptedChanges), Owner(Owner) {} RiskLevel, const Transform &Owner)
: Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {}
/// \brief Entry point to the callback called when matches are made. /// \brief Entry point to the callback called when matches are made.
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result)
LLVM_OVERRIDE; LLVM_OVERRIDE;
private: private:
clang::tooling::Replacements &Replace;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
Transform &Owner; const Transform &Owner;
}; };
#endif // CPP11_MIGRATE_USE_AUTO_ACTIONS_H #endif // CPP11_MIGRATE_USE_AUTO_ACTIONS_H

View File

@ -47,7 +47,7 @@ bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
/// \brief Replaces the provided range with the text "nullptr", but only if /// \brief Replaces the provided range with the text "nullptr", but only if
/// the start and end location are both in main file. /// the start and end location are both in main file.
/// Returns true if and only if a replacement was made. /// Returns true if and only if a replacement was made.
void ReplaceWithNullptr(Transform &Owner, SourceManager &SM, void ReplaceWithNullptr(tooling::Replacements &Replace, SourceManager &SM,
SourceLocation StartLoc, SourceLocation EndLoc) { SourceLocation StartLoc, SourceLocation EndLoc) {
CharSourceRange Range(SourceRange(StartLoc, EndLoc), true); CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
// Add a space if nullptr follows an alphanumeric character. This happens // Add a space if nullptr follows an alphanumeric character. This happens
@ -55,11 +55,9 @@ void ReplaceWithNullptr(Transform &Owner, SourceManager &SM,
// parentheses and right beside a return statement. // parentheses and right beside a return statement.
SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1); SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1);
if (isAlphanumeric(*FullSourceLoc(PreviousLocation, SM).getCharacterData())) if (isAlphanumeric(*FullSourceLoc(PreviousLocation, SM).getCharacterData()))
Owner.addReplacementForCurrentTU( Replace.insert(tooling::Replacement(SM, Range, " nullptr"));
tooling::Replacement(SM, Range, " nullptr"));
else else
Owner.addReplacementForCurrentTU( Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
tooling::Replacement(SM, Range, "nullptr"));
} }
/// \brief Returns the name of the outermost macro. /// \brief Returns the name of the outermost macro.
@ -155,9 +153,10 @@ private:
/// ambiguities. /// ambiguities.
class CastSequenceVisitor : public RecursiveASTVisitor<CastSequenceVisitor> { class CastSequenceVisitor : public RecursiveASTVisitor<CastSequenceVisitor> {
public: public:
CastSequenceVisitor(ASTContext &Context, const UserMacroNames &UserNullMacros, CastSequenceVisitor(tooling::Replacements &R, ASTContext &Context,
unsigned &AcceptedChanges, Transform &Owner) const UserMacroNames &UserNullMacros,
: SM(Context.getSourceManager()), Context(Context), unsigned &AcceptedChanges, const Transform &Owner)
: Replace(R), SM(Context.getSourceManager()), Context(Context),
UserNullMacros(UserNullMacros), AcceptedChanges(AcceptedChanges), UserNullMacros(UserNullMacros), AcceptedChanges(AcceptedChanges),
Owner(Owner), FirstSubExpr(0), PruneSubtree(false) {} Owner(Owner), FirstSubExpr(0), PruneSubtree(false) {}
@ -197,7 +196,7 @@ public:
FileLocEnd = SM.getFileLoc(EndLoc); FileLocEnd = SM.getFileLoc(EndLoc);
if (isReplaceableRange(FileLocStart, FileLocEnd, SM, Owner) && if (isReplaceableRange(FileLocStart, FileLocEnd, SM, Owner) &&
allArgUsesValid(C)) { allArgUsesValid(C)) {
ReplaceWithNullptr(Owner, SM, FileLocStart, FileLocEnd); ReplaceWithNullptr(Replace, SM, FileLocStart, FileLocEnd);
++AcceptedChanges; ++AcceptedChanges;
} }
return skipSubTree(); return skipSubTree();
@ -221,7 +220,7 @@ public:
if (!isReplaceableRange(StartLoc, EndLoc, SM, Owner)) { if (!isReplaceableRange(StartLoc, EndLoc, SM, Owner)) {
return skipSubTree(); return skipSubTree();
} }
ReplaceWithNullptr(Owner, SM, StartLoc, EndLoc); ReplaceWithNullptr(Replace, SM, StartLoc, EndLoc);
++AcceptedChanges; ++AcceptedChanges;
return skipSubTree(); return skipSubTree();
@ -418,19 +417,21 @@ private:
} }
private: private:
tooling::Replacements &Replace;
SourceManager &SM; SourceManager &SM;
ASTContext &Context; ASTContext &Context;
const UserMacroNames &UserNullMacros; const UserMacroNames &UserNullMacros;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
Transform &Owner; const Transform &Owner;
Expr *FirstSubExpr; Expr *FirstSubExpr;
bool PruneSubtree; bool PruneSubtree;
}; };
} // namespace } // namespace
NullptrFixer::NullptrFixer(unsigned &AcceptedChanges, RiskLevel, NullptrFixer::NullptrFixer(clang::tooling::Replacements &Replace,
Transform &Owner) unsigned &AcceptedChanges, RiskLevel,
: AcceptedChanges(AcceptedChanges), Owner(Owner) { const Transform &Owner)
: Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {
if (!UserNullMacroNames.empty()) { if (!UserNullMacroNames.empty()) {
llvm::StringRef S = UserNullMacroNames; llvm::StringRef S = UserNullMacroNames;
S.split(UserNullMacros, ","); S.split(UserNullMacros, ",");
@ -444,7 +445,7 @@ void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) {
// Given an implicit null-ptr cast or an explicit cast with an implicit // Given an implicit null-ptr cast or an explicit cast with an implicit
// null-to-pointer cast within use CastSequenceVisitor to identify sequences // null-to-pointer cast within use CastSequenceVisitor to identify sequences
// of explicit casts that can be converted into 'nullptr'. // of explicit casts that can be converted into 'nullptr'.
CastSequenceVisitor Visitor(*Result.Context, UserNullMacros, AcceptedChanges, CastSequenceVisitor Visitor(Replace, *Result.Context, UserNullMacros,
Owner); AcceptedChanges, Owner);
Visitor.TraverseStmt(const_cast<CastExpr *>(NullCast)); Visitor.TraverseStmt(const_cast<CastExpr *>(NullCast));
} }

View File

@ -27,15 +27,17 @@ typedef llvm::SmallVector<llvm::StringRef, 1> UserMacroNames;
/// ///
class NullptrFixer : public clang::ast_matchers::MatchFinder::MatchCallback { class NullptrFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
public: public:
NullptrFixer(unsigned &AcceptedChanges, RiskLevel, Transform &Owner); NullptrFixer(clang::tooling::Replacements &Replace, unsigned &AcceptedChanges,
RiskLevel, const Transform &Owner);
/// \brief Entry point to the callback called when matches are made. /// \brief Entry point to the callback called when matches are made.
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result); virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result);
private: private:
clang::tooling::Replacements &Replace;
unsigned &AcceptedChanges; unsigned &AcceptedChanges;
UserMacroNames UserNullMacros; UserMacroNames UserNullMacros;
Transform &Owner; const Transform &Owner;
}; };
#endif // CPP11_MIGRATE_NULLPTR_ACTIONS_H #endif // CPP11_MIGRATE_NULLPTR_ACTIONS_H

View File

@ -24,7 +24,7 @@ using clang::ast_matchers::MatchFinder;
using namespace clang::tooling; using namespace clang::tooling;
using namespace clang; using namespace clang;
int UseNullptrTransform::apply(const FileOverrides &InputStates, int UseNullptrTransform::apply(FileOverrides &InputStates,
const CompilationDatabase &Database, const CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) { const std::vector<std::string> &SourcePaths) {
ClangTool UseNullptrTool(Database, SourcePaths); ClangTool UseNullptrTool(Database, SourcePaths);
@ -32,7 +32,8 @@ int UseNullptrTransform::apply(const FileOverrides &InputStates,
unsigned AcceptedChanges = 0; unsigned AcceptedChanges = 0;
MatchFinder Finder; MatchFinder Finder;
NullptrFixer Fixer(AcceptedChanges, Options().MaxRiskLevel, /*Owner=*/ *this); NullptrFixer Fixer(getReplacements(), AcceptedChanges, Options().MaxRiskLevel,
/*Owner=*/ *this);
Finder.addMatcher(makeCastSequenceMatcher(), &Fixer); Finder.addMatcher(makeCastSequenceMatcher(), &Fixer);

View File

@ -28,7 +28,7 @@ public:
: Transform("UseNullptr", Options) {} : Transform("UseNullptr", Options) {}
/// \see Transform::run(). /// \see Transform::run().
virtual int apply(const FileOverrides &InputStates, virtual int apply(FileOverrides &InputStates,
const clang::tooling::CompilationDatabase &Database, const clang::tooling::CompilationDatabase &Database,
const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;
}; };

View File

@ -34,7 +34,6 @@ add_dependencies(cpp11-migrate
) )
target_link_libraries(cpp11-migrate target_link_libraries(cpp11-migrate
clangReplace
migrateCore migrateCore
) )

View File

@ -21,14 +21,9 @@
#include "Core/Transform.h" #include "Core/Transform.h"
#include "Core/Transforms.h" #include "Core/Transforms.h"
#include "Core/Reformatting.h" #include "Core/Reformatting.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendActions.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h" #include "clang/Tooling/Tooling.h"
#include "clang-replace/Tooling/ApplyReplacements.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
@ -127,12 +122,12 @@ static cl::opt<bool, /*ExternalStorage=*/true> EnableHeaderModifications(
cl::location(GlobalOptions.EnableHeaderModifications), cl::location(GlobalOptions.EnableHeaderModifications),
cl::init(false)); cl::init(false));
static cl::opt<bool> static cl::opt<bool> YAMLOnly("yaml-only",
SerializeReplacements("serialize-replacements", cl::Hidden, // Associated with -headers
cl::Hidden, // Associated with -headers cl::desc("Don't change headers on disk. Write "
cl::desc("Serialize translation unit replacements to " "changes to change description files "
"disk instead of changing files."), "only."),
cl::init(false)); cl::init(false));
cl::opt<std::string> SupportedCompilers( cl::opt<std::string> SupportedCompilers(
"for-compilers", cl::value_desc("string"), "for-compilers", cl::value_desc("string"),
@ -230,68 +225,6 @@ static Reformatter *handleFormatStyle(const char *ProgName, bool &Error) {
return 0; return 0;
} }
/// \brief Use \c ChangesReformatter to reformat all changed regions of all
/// files stored in \c Overrides and write the result to disk.
///
/// \returns \li true if reformatting replacements were successfully applied
/// without conflicts and all files were successfully written to
/// disk.
/// \li false if reformatting could not be successfully applied or
/// if at least one file failed to write to disk.
bool reformat(Reformatter &ChangesReformatter, const FileOverrides &Overrides,
DiagnosticsEngine &Diagnostics) {
FileManager Files((FileSystemOptions()));
SourceManager SM(Diagnostics, Files);
replace::TUReplacements AllReplacements(1);
ChangesReformatter.reformatChanges(Overrides, SM,
AllReplacements.front().Replacements);
replace::FileToReplacementsMap GroupedReplacements;
if (!replace::mergeAndDeduplicate(AllReplacements, GroupedReplacements, SM)) {
llvm::errs() << "Warning: Reformatting produced conflicts.\n";
return false;
}
Rewriter DestRewriter(SM, LangOptions());
if (!replace::applyReplacements(GroupedReplacements, DestRewriter)) {
llvm::errs() << "Warning: Failed to apply reformatting conflicts!\n";
return false;
}
return replace::writeFiles(DestRewriter);
}
bool serializeReplacements(const replace::TUReplacements &Replacements) {
bool Errors = false;
for (replace::TUReplacements::const_iterator I = Replacements.begin(),
E = Replacements.end();
I != E; ++I) {
llvm::SmallString<128> ReplacementsFileName;
llvm::SmallString<64> Error;
bool Result = generateReplacementsFileName(I->MainSourceFile,
ReplacementsFileName, Error);
if (!Result) {
llvm::errs() << "Failed to generate replacements filename:" << Error
<< "\n";
Errors = true;
continue;
}
std::string ErrorInfo;
llvm::raw_fd_ostream ReplacementsFile(ReplacementsFileName.c_str(),
ErrorInfo, llvm::sys::fs::F_Binary);
if (!ErrorInfo.empty()) {
llvm::errs() << "Error opening file: " << ErrorInfo << "\n";
Errors = true;
continue;
}
llvm::yaml::Output YAML(ReplacementsFile);
YAML << const_cast<TranslationUnitReplacements &>(*I);
}
return !Errors;
}
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(); llvm::sys::PrintStackTraceOnErrorSignal();
Transforms TransformManager; Transforms TransformManager;
@ -347,15 +280,6 @@ int main(int argc, const char **argv) {
TransformManager.createSelectedTransforms(GlobalOptions, RequiredVersions); TransformManager.createSelectedTransforms(GlobalOptions, RequiredVersions);
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
new DiagnosticOptions());
DiagnosticsEngine Diagnostics(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
DiagOpts.getPtr());
// FIXME: Make this DiagnosticsEngine available to all Transforms probably via
// GlobalOptions.
if (TransformManager.begin() == TransformManager.end()) { if (TransformManager.begin() == TransformManager.end()) {
if (SupportedCompilers.empty()) if (SupportedCompilers.empty())
llvm::errs() << argv[0] << ": no selected transforms\n"; llvm::errs() << argv[0] << ": no selected transforms\n";
@ -365,22 +289,21 @@ int main(int argc, const char **argv) {
return 1; return 1;
} }
// If SerializeReplacements is requested, then change reformatting must be if (std::distance(TransformManager.begin(), TransformManager.end()) > 1 &&
// turned off and only one transform should be requested. Reformatting is YAMLOnly) {
// basically another transform so even if there's only one other transform, llvm::errs() << "Header change description files requested for multiple "
// the reformatting pass would make two.
if (SerializeReplacements &&
(std::distance(TransformManager.begin(), TransformManager.end()) > 1 ||
ChangesReformatter)) {
llvm::errs() << "Serialization of replacements requested for multiple "
"transforms.\nChanges from only one transform can be " "transforms.\nChanges from only one transform can be "
"serialized.\n"; "recorded in a change description file.\n";
return 1; return 1;
} }
// if reformatting is enabled we wants to track file changes so that it's
// possible to reformat them.
bool TrackReplacements = static_cast<bool>(ChangesReformatter);
FileOverrides FileStates(TrackReplacements);
SourcePerfData PerfData; SourcePerfData PerfData;
FileOverrides FileStates;
// Apply transforms.
for (Transforms::const_iterator I = TransformManager.begin(), for (Transforms::const_iterator I = TransformManager.begin(),
E = TransformManager.end(); E = TransformManager.end();
I != E; ++I) { I != E; ++I) {
@ -403,67 +326,79 @@ int main(int argc, const char **argv) {
} }
llvm::outs() << "\n"; llvm::outs() << "\n";
} }
// Collect all TranslationUnitReplacements generated from the translation
// units the transform worked on and store them in AllReplacements.
replace::TUReplacements AllReplacements;
const TUReplacementsMap &ReplacementsMap = T->getAllReplacements();
const TranslationUnitReplacements &(
TUReplacementsMap::value_type::*getValue)() const =
&TUReplacementsMap::value_type::getValue;
std::transform(ReplacementsMap.begin(), ReplacementsMap.end(),
std::back_inserter(AllReplacements),
std::mem_fun_ref(getValue));
if (SerializeReplacements)
serializeReplacements(AllReplacements);
FileManager Files((FileSystemOptions()));
SourceManager SM(Diagnostics, Files);
// Make sure SourceManager is updated to have the same initial state as the
// transforms.
FileStates.applyOverrides(SM);
replace::FileToReplacementsMap GroupedReplacements;
if (!replace::mergeAndDeduplicate(AllReplacements, GroupedReplacements,
SM)) {
llvm::outs() << "Transform " << T->getName()
<< " resulted in conflicts. Discarding all "
<< "replacements.\n";
continue;
}
// Apply replacements and update FileStates with new state.
Rewriter DestRewriter(SM, LangOptions());
if (!replace::applyReplacements(GroupedReplacements, DestRewriter)) {
llvm::outs() << "Some replacements failed to apply. Discarding "
"all replacements.\n";
continue;
}
// Update contents of files in memory to serve as initial state for next
// transform.
FileStates.updateState(DestRewriter);
// Update changed ranges for reformatting
if (ChangesReformatter)
FileStates.adjustChangedRanges(GroupedReplacements);
} }
// Skip writing final file states to disk if we were asked to serialize // Reformat changes if a reformatter is provided.
// replacements. Otherwise reformat changes if reformatting is enabled. If if (ChangesReformatter)
// not enabled or if reformatting fails write un-formated changes to disk for (FileOverrides::const_iterator I = FileStates.begin(),
// instead. reformat() takes care of writing successfully formatted changes. E = FileStates.end();
if (!SerializeReplacements && I != E; ++I) {
(!ChangesReformatter || SourceOverrides &Overrides = *I->second;
!reformat(*ChangesReformatter, FileStates, Diagnostics))) ChangesReformatter->reformatChanges(Overrides);
FileStates.writeToDisk(Diagnostics); }
if (FinalSyntaxCheck) if (FinalSyntaxCheck)
if (!doSyntaxCheck(*Compilations, SourcePaths, FileStates)) if (!doSyntaxCheck(*Compilations, SourcePaths, FileStates))
return 1; return 1;
// Write results to file.
for (FileOverrides::const_iterator I = FileStates.begin(),
E = FileStates.end();
I != E; ++I) {
const SourceOverrides &Overrides = *I->second;
if (Overrides.isSourceOverriden()) {
std::string ErrorInfo;
std::string MainFileName = I->getKey();
llvm::raw_fd_ostream FileStream(MainFileName.c_str(), ErrorInfo,
llvm::sys::fs::F_Binary);
FileStream << Overrides.getMainFileContent();
}
for (HeaderOverrides::const_iterator HeaderI = Overrides.headers_begin(),
HeaderE = Overrides.headers_end();
HeaderI != HeaderE; ++HeaderI) {
std::string ErrorInfo;
if (YAMLOnly) {
// Replacements for header files need to be written in a YAML file for
// every transform and will be merged together with an external tool.
llvm::SmallString<128> ReplacementsHeaderName;
llvm::SmallString<64> Error;
bool Result =
generateReplacementsFileName(I->getKey(), HeaderI->getKey().data(),
ReplacementsHeaderName, Error);
if (!Result) {
llvm::errs() << "Failed to generate replacements filename:" << Error
<< "\n";
continue;
}
llvm::raw_fd_ostream ReplacementsFile(
ReplacementsHeaderName.c_str(), ErrorInfo, llvm::sys::fs::F_Binary);
if (!ErrorInfo.empty()) {
llvm::errs() << "Error opening file: " << ErrorInfo << "\n";
continue;
}
llvm::yaml::Output YAML(ReplacementsFile);
YAML << const_cast<TranslationUnitReplacements &>(
HeaderI->getValue().getReplacements());
} else {
// If -yaml-only was not specified, then change headers on disk.
// FIXME: This is transitional behaviour. Remove this functionality
// when header change description tool is ready.
assert(!HeaderI->second.getContentOverride().empty() &&
"A header override should not be empty");
std::string HeaderFileName = HeaderI->getKey();
llvm::raw_fd_ostream HeaderStream(HeaderFileName.c_str(), ErrorInfo,
llvm::sys::fs::F_Binary);
if (!ErrorInfo.empty()) {
llvm::errs() << "Error opening file: " << ErrorInfo << "\n";
continue;
}
HeaderStream << HeaderI->second.getContentOverride();
}
}
}
// Report execution times. // Report execution times.
if (GlobalOptions.EnableTiming && !PerfData.empty()) { if (GlobalOptions.EnableTiming && !PerfData.empty()) {
std::string DirectoryName = TimingDirectoryName; std::string DirectoryName = TimingDirectoryName;

View File

@ -36,14 +36,14 @@ SOURCES += $(addprefix ../ReplaceAutoPtr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/..
BUILT_SOURCES += $(ObjDir)/../ReplaceAutoPtr/.objdir BUILT_SOURCES += $(ObjDir)/../ReplaceAutoPtr/.objdir
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc mcparser option LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc mcparser option
USEDLIBS = migrateCore.a clangFormat.a clangReplace.a clangTooling.a clangFrontend.a \ USEDLIBS = migrateCore.a clangFormat.a clangTooling.a clangFrontend.a \
clangSerialization.a clangDriver.a clangRewriteFrontend.a \ clangSerialization.a clangDriver.a clangRewriteFrontend.a \
clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \ clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \
clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile include $(CLANG_LEVEL)/Makefile
CPP.Flags += -I$(PROJ_SRC_DIR)/.. -I$(PROJ_SRC_DIR)/../../clang-replace/include CPP.Flags += -I$(PROJ_SRC_DIR)/..
# BUILT_SOURCES gets used as a prereq for many top-level targets. However, at # BUILT_SOURCES gets used as a prereq for many top-level targets. However, at
# the point those targets are defined, $(ObjDir) hasn't been defined and so the # the point those targets are defined, $(ObjDir) hasn't been defined and so the

View File

@ -1,8 +0,0 @@
void update(int (&arr)[10]) {
int val = 1;
for (unsigned i = 0; i < sizeof(arr)/sizeof(int); ++i) {
arr[i] = val++;
// CHECK: for (auto & elem : arr) {
// CHECK-NEXT: elem = val++;
}
}

View File

@ -1,12 +1,12 @@
--- ---
MainSourceFile: "$(path)/main.cpp" MainSourceFile: "$(path)/main.cpp"
Replacements: Replacements:
- FilePath: "$(path)/common.h"
Offset: 506
Length: 2
ReplacementText: "elem"
- FilePath: "$(path)/common.h" - FilePath: "$(path)/common.h"
Offset: 432 Offset: 432
Length: 61 Length: 61
ReplacementText: "(auto & elem : C)" ReplacementText: "(auto & elem : C)"
- FilePath: "$(path)/common.h"
Offset: 506
Length: 2
ReplacementText: "elem"
... ...

View File

@ -1,20 +0,0 @@
---
MainSourceFile: "$(path)/common.cpp"
Replacements:
- FilePath: "$(path)/common.h"
Offset: 506
Length: 2
ReplacementText: "elem"
- FilePath: "$(path)/common.h"
Offset: 432
Length: 61
ReplacementText: "(auto & elem : C)"
- FilePath: "$(path)/common.cpp"
Offset: 289
Length: 2
ReplacementText: "elem"
- FilePath: "$(path)/common.cpp"
Offset: 206
Length: 63
ReplacementText: "(auto & elem : C1)"
...

View File

@ -1,30 +1,44 @@
// The following block tests the following: // The following block tests the following:
// - Only 1 file is generated per translation unit // - Only 1 file is generated per translation unit and header file
// - Replacements are written in YAML that matches the expected YAML file // - Replacements are written in YAML that matches the expected YAML file
// The test is run in %T/SerializeTest so it's easy to create a clean test // RUN: rm -rf %t/Test
// directory. // RUN: mkdir -p %t/Test
// // RUN: cp %S/main.cpp %S/common.cpp %S/common.h %t/Test
// RUN: rm -rf %T/SerializeTest // RUN: cpp11-migrate -loop-convert -headers -yaml-only -include=%t/Test %t/Test/main.cpp %t/Test/common.cpp --
// RUN: mkdir -p %T/SerializeTest // Check that only 1 file is generated per translation unit and header file.
// RUN: cp %S/main.cpp %S/common.cpp %S/common.h %T/SerializeTest // RUN: ls -1 %t/Test | FileCheck %s --check-prefix=MAIN_CPP
// RUN: cpp11-migrate -loop-convert -headers -serialize-replacements -include=%T/SerializeTest %T/SerializeTest/main.cpp %T/SerializeTest/common.cpp -- // RUN: ls -1 %t/Test | FileCheck %s --check-prefix=COMMON_CPP
// Check that only 1 file is generated per translation unit // RUN: cp %S/common.h.yaml %t/Test/main.cpp_common.h.yaml
// RUN: ls -1 %T/SerializeTest | FileCheck %s --check-prefix=MAIN_CPP
// RUN: ls -1 %T/SerializeTest | FileCheck %s --check-prefix=COMMON_CPP
// We need to put the build path to the expected YAML file to diff against the generated one. // We need to put the build path to the expected YAML file to diff against the generated one.
// RUN: sed -e 's#$(path)#%/T/SerializeTest#g' %S/main_expected.yaml > %T/SerializeTest/main_expected.yaml // RUN: sed -e 's#$(path)#%/t/Test#g' %S/common.h.yaml > %t/Test/main.cpp_common.h.yaml
// RUN: sed -i -e 's#\\#/#g' %T/SerializeTest/main.cpp_*.yaml // RUN: sed -i -e 's#\\#/#g' %t/Test/main.cpp_common.h_*.yaml
// RUN: diff -b %T/SerializeTest/main_expected.yaml %T/SerializeTest/main.cpp_*.yaml // RUN: diff -b %t/Test/main.cpp_common.h.yaml %t/Test/main.cpp_common.h_*.yaml
// RUN: sed -e 's#$(path)#%/T/SerializeTest#g' %S/common_expected.yaml > %T/SerializeTest/common_expected.yaml // RUN: sed -e 's#$(path)#%/t/Test#g' -e 's#main.cpp"#common.cpp"#g' %S/common.h.yaml > %t/Test/common.cpp_common.h.yaml
// RUN: sed -i -e 's#\\#/#g' %T/SerializeTest/common.cpp_*.yaml // RUN: sed -i -e 's#\\#/#g' %t/Test/common.cpp_common.h_*.yaml
// RUN: diff -b %T/SerializeTest/common_expected.yaml %T/SerializeTest/common.cpp_*.yaml // RUN: diff -b %t/Test/common.cpp_common.h.yaml %t/Test/common.cpp_common.h_*.yaml
// //
// The following are for FileCheck when used on output of 'ls'. See above. // The following block tests the following:
// MAIN_CPP: {{^main.cpp_.*.yaml$}} // - YAML files are written only when -headers is used
// MAIN_CPP-NOT: {{main.cpp_.*.yaml}} // RUN: rm -rf %t/Test
// RUN: mkdir -p %t/Test
// RUN: cp %S/main.cpp %S/common.cpp %S/common.h %t/Test
// RUN: cpp11-migrate -loop-convert -headers -yaml-only -include=%t/Test %t/Test/main.cpp --
// RUN: cpp11-migrate -loop-convert %t/Test/common.cpp --
// Check that only one YAML file is generated from main.cpp and common.h and not from common.cpp and common.h since -header is not specified
// RUN: ls -1 %t/Test | FileCheck %s --check-prefix=MAIN_CPP
// RUN: ls -1 %t/Test | FileCheck %s --check-prefix=NO_COMMON
// We need to put the build path to the expected YAML file to diff against the generated one.
// RUN: sed -e 's#$(path)#%/t/Test#g' %S/common.h.yaml > %t/Test/main.cpp_common.h.yaml
// RUN: sed -i -e 's#\\#/#g' %t/Test/main.cpp_common.h_*.yaml
// RUN: diff -b %t/Test/main.cpp_common.h.yaml %t/Test/main.cpp_common.h_*.yaml
// //
// COMMON_CPP: {{^common.cpp_.*.yaml$}} // MAIN_CPP: {{^main.cpp_common.h_.*.yaml$}}
// COMMON_CPP-NOT: {{common.cpp_.*.yaml}} // MAIN_CPP-NOT: {{main.cpp_common.h_.*.yaml}}
//
// COMMON_CPP: {{^common.cpp_common.h_.*.yaml$}}
// COMMON_CPP-NOT: {{common.cpp_common.h_.*.yaml}}
//
// NO_COMMON-NOT: {{common.cpp_common.h_.*.yaml}}
#include "common.h" #include "common.h"

View File

@ -1,24 +0,0 @@
// Ensure that if -serialize-replacements is not provided, no serialized
// replacement files should be generated and the changes are made directly.
//
// RUN: mkdir -p %T/Inputs
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/no_yaml.h > %T/Inputs/no_yaml.h
// RUN: cpp11-migrate -loop-convert %t.cpp -headers -include=%T/Inputs -- -I %T/Inputs/no_yaml.h
// RUN: FileCheck --input-file=%t.cpp %s
// RUN: FileCheck --input-file=%T/Inputs/no_yaml.h %S/Inputs/no_yaml.h
// RUN: ls -1 %T | FileCheck %s --check-prefix=NO_YAML
//
// NO_YAML-NOT: {{no_yaml.cpp_.*.yaml}}
#include "Inputs/no_yaml.h"
void func() {
int arr[10];
for (unsigned i = 0; i < sizeof(arr)/sizeof(int); ++i) {
arr[i] = 0;
// CHECK: for (auto & elem : arr) {
// CHECK-NEXT: elem = 0;
}
update(arr);
}

View File

@ -1,31 +1,26 @@
set(LLVM_LINK_COMPONENTS set(LLVM_LINK_COMPONENTS
support support
) )
get_filename_component(CPP11_MIGRATE_SOURCE_DIR get_filename_component(CPP11_MIGRATE_SOURCE_DIR
${CMAKE_CURRENT_SOURCE_DIR}/../../cpp11-migrate REALPATH) ${CMAKE_CURRENT_SOURCE_DIR}/../../cpp11-migrate REALPATH)
get_filename_component(ClangReplaceLocation include_directories(${CPP11_MIGRATE_SOURCE_DIR})
"${CMAKE_CURRENT_SOURCE_DIR}/../../clang-replace/include" REALPATH)
include_directories( add_extra_unittest(Cpp11MigrateTests
${CPP11_MIGRATE_SOURCE_DIR} FileOverridesTest.cpp
${ClangReplaceLocation} ReformattingTest.cpp
) IncludeExcludeTest.cpp
PerfSupportTest.cpp
add_extra_unittest(Cpp11MigrateTests TransformTest.cpp
FileOverridesTest.cpp UniqueHeaderNameTest.cpp
ReformattingTest.cpp IncludeDirectivesTest.cpp
IncludeExcludeTest.cpp )
PerfSupportTest.cpp
TransformTest.cpp target_link_libraries(Cpp11MigrateTests
UniqueHeaderNameTest.cpp migrateCore
IncludeDirectivesTest.cpp clangFormat
) clangTooling
clangBasic
target_link_libraries(Cpp11MigrateTests clangASTMatchers
migrateCore clangRewriteFrontend
clangFormat )
clangTooling
clangBasic
clangASTMatchers
clangRewriteFrontend
)

View File

@ -8,34 +8,56 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "Core/FileOverrides.h" #include "Core/FileOverrides.h"
#include "Core/Refactoring.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "VirtualFileHelper.h" #include "VirtualFileHelper.h"
#include "clang/Rewrite/Core/Rewriter.h"
using namespace clang; using namespace clang;
using namespace clang::tooling; using namespace clang::tooling;
static Replacement makeReplacement(unsigned Offset, unsigned Length, TEST(SourceOverridesTest, Interface) {
unsigned ReplacementLength, llvm::StringRef FileName = "<test-file>";
llvm::StringRef FilePath) { VirtualFileHelper VFHelper;
return Replacement(FilePath, Offset, Length, VFHelper.mapFile(
std::string(ReplacementLength, '~')); FileName,
"std::vector<such_a_long_name_for_a_type>::const_iterator long_type =\n"
" vec.begin();\n");
SourceOverrides Overrides(FileName, /*TrackFileChanges=*/false);
EXPECT_EQ(FileName, Overrides.getMainFileName());
EXPECT_FALSE(Overrides.isSourceOverriden());
EXPECT_FALSE(Overrides.isTrackingFileChanges());
Replacements Replaces;
unsigned ReplacementLength =
strlen("std::vector<such_a_long_name_for_a_type>::const_iterator");
Replaces.insert(
Replacement(FileName, 0, ReplacementLength, "auto"));
Overrides.applyReplacements(Replaces, VFHelper.getNewSourceManager());
EXPECT_TRUE(Overrides.isSourceOverriden());
std::string ExpectedContent = "auto long_type =\n"
" vec.begin();\n";
EXPECT_EQ(ExpectedContent, Overrides.getMainFileContent());
}
namespace {
Replacement makeReplacement(unsigned Offset, unsigned Length,
unsigned ReplacementLength) {
return Replacement("", Offset, Length, std::string(ReplacementLength, '~'));
} }
// generate a set of replacements containing one element // generate a set of replacements containing one element
static ReplacementsVec makeReplacements(unsigned Offset, unsigned Length, Replacements makeReplacements(unsigned Offset, unsigned Length,
unsigned ReplacementLength, unsigned ReplacementLength) {
llvm::StringRef FilePath = "~") { Replacements Replaces;
ReplacementsVec Replaces; Replaces.insert(makeReplacement(Offset, Length, ReplacementLength));
Replaces.push_back(
makeReplacement(Offset, Length, ReplacementLength, FilePath));
return Replaces; return Replaces;
} }
static bool equalRanges(Range A, Range B) { bool equalRanges(Range A, Range B) {
return A.getOffset() == B.getOffset() && A.getLength() == B.getLength(); return A.getOffset() == B.getOffset() && A.getLength() == B.getLength();
} }
} // end anonymous namespace
TEST(ChangedRangesTest, adjustChangedRangesShrink) { TEST(ChangedRangesTest, adjustChangedRangesShrink) {
ChangedRanges Changes; ChangedRanges Changes;
@ -117,71 +139,3 @@ TEST(ChangedRangesTest, adjustChangedRangesRangeResized) {
EXPECT_TRUE( EXPECT_TRUE(
std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges));
} }
TEST(FileOverridesTest, applyOverrides) {
// Set up initial state
VirtualFileHelper VFHelper;
SmallString<128> fileAPath("fileA.cpp");
ASSERT_FALSE(llvm::sys::fs::make_absolute(fileAPath));
SmallString<128> fileBPath("fileB.cpp");
ASSERT_FALSE(llvm::sys::fs::make_absolute(fileBPath));
VFHelper.mapFile(fileAPath, "Content A");
VFHelper.mapFile(fileBPath, "Content B");
SourceManager &SM = VFHelper.getNewSourceManager();
// Fill a Rewriter with changes
Rewriter Rewrites(SM, LangOptions());
ReplacementsVec R(1, Replacement(fileAPath, 0, 7, "Stuff"));
ASSERT_TRUE(applyAllReplacements(R, Rewrites));
FileOverrides Overrides;
Overrides.updateState(Rewrites);
const FileOverrides::FileStateMap &State = Overrides.getState();
// Ensure state updated
ASSERT_TRUE(State.end() == State.find(fileBPath));
ASSERT_TRUE(State.begin() == State.find(fileAPath));
ASSERT_EQ("Stuff A", State.begin()->getValue());
Overrides.applyOverrides(SM);
const FileEntry *EntryA = SM.getFileManager().getFile(fileAPath);
FileID IdA = SM.translateFile(EntryA);
ASSERT_FALSE(IdA.isInvalid());
// Ensure the contents of the buffer matches what we'd expect.
const llvm::MemoryBuffer *BufferA = SM.getBuffer(IdA);
ASSERT_FALSE(0 == BufferA);
ASSERT_EQ("Stuff A", BufferA->getBuffer());
}
TEST(FileOverridesTest, adjustChangedRanges) {
SmallString<128> fileAPath("fileA.cpp");
ASSERT_FALSE(llvm::sys::fs::make_absolute(fileAPath));
SmallString<128> fileBPath("fileB.cpp");
ASSERT_FALSE(llvm::sys::fs::make_absolute(fileBPath));
replace::FileToReplacementsMap GroupedReplacements;
GroupedReplacements[fileAPath] = makeReplacements(0, 5, 4, fileAPath);
GroupedReplacements[fileBPath] = makeReplacements(10, 0, 6, fileBPath);
FileOverrides Overrides;
const FileOverrides::ChangeMap &Map = Overrides.getChangedRanges();
ASSERT_TRUE(Map.empty());
Overrides.adjustChangedRanges(GroupedReplacements);
ASSERT_TRUE(Map.end() != Map.find(fileAPath));
ASSERT_TRUE(Map.end() != Map.find(fileBPath));
const Range &RA = *Map.find(fileAPath)->second.begin();
EXPECT_EQ(0u, RA.getOffset());
EXPECT_EQ(4u, RA.getLength());
const Range &RB = *Map.find(fileBPath)->second.begin();
EXPECT_EQ(10u, RB.getOffset());
EXPECT_EQ(6u, RB.getLength());
}

View File

@ -13,7 +13,7 @@ include $(CLANG_LEVEL)/../../Makefile.config
TESTNAME = Cpp11MigrateTests TESTNAME = Cpp11MigrateTests
LINK_COMPONENTS := asmparser bitreader support MC MCParser option \ LINK_COMPONENTS := asmparser bitreader support MC MCParser option \
TransformUtils TransformUtils
USEDLIBS = migrateCore.a clangFormat.a clangReplace.a clangTooling.a clangFrontend.a \ USEDLIBS = migrateCore.a clangFormat.a clangTooling.a clangFrontend.a \
clangSerialization.a clangDriver.a clangRewriteFrontend.a \ clangSerialization.a clangDriver.a clangRewriteFrontend.a \
clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \ clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \
clangAST.a clangASTMatchers.a clangEdit.a clangLex.a \ clangAST.a clangASTMatchers.a clangEdit.a clangLex.a \
@ -21,5 +21,5 @@ USEDLIBS = migrateCore.a clangFormat.a clangReplace.a clangTooling.a clangFronte
include $(CLANG_LEVEL)/Makefile include $(CLANG_LEVEL)/Makefile
MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1 MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1
CPP.Flags += -I$(PROJ_SRC_DIR)/../../cpp11-migrate -I$(PROJ_SRC_DIR)/../../clang-replace/include CPP.Flags += -I$(PROJ_SRC_DIR)/../../cpp11-migrate
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest

View File

@ -18,7 +18,7 @@ public:
TransformA(const TransformOptions &Options) TransformA(const TransformOptions &Options)
: Transform("TransformA", Options) {} : Transform("TransformA", Options) {}
virtual int apply(const FileOverrides &, virtual int apply(FileOverrides &,
const tooling::CompilationDatabase &, const tooling::CompilationDatabase &,
const std::vector<std::string> &) { const std::vector<std::string> &) {
return 0; return 0;
@ -34,7 +34,7 @@ public:
TransformB(const TransformOptions &Options) TransformB(const TransformOptions &Options)
: Transform("TransformB", Options) {} : Transform("TransformB", Options) {}
virtual int apply(const FileOverrides &, virtual int apply(FileOverrides &,
const tooling::CompilationDatabase &, const tooling::CompilationDatabase &,
const std::vector<std::string> &) { const std::vector<std::string> &) {
return 0; return 0;

View File

@ -9,7 +9,6 @@
#include "Core/Reformatting.h" #include "Core/Reformatting.h"
#include "Core/FileOverrides.h" #include "Core/FileOverrides.h"
#include "Core/Refactoring.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "VirtualFileHelper.h" #include "VirtualFileHelper.h"
@ -20,9 +19,9 @@ namespace {
// convenience function to create a ChangedRanges containing one Range // convenience function to create a ChangedRanges containing one Range
ChangedRanges makeChangedRanges(unsigned Offset, unsigned Length) { ChangedRanges makeChangedRanges(unsigned Offset, unsigned Length) {
ChangedRanges Changes; ChangedRanges Changes;
ReplacementsVec Replaces; Replacements Replaces;
Replaces.push_back(Replacement("", Offset, 0, std::string(Length, '~'))); Replaces.insert(Replacement("", Offset, 0, std::string(Length, '~')));
Changes.adjustChangedRanges(Replaces); Changes.adjustChangedRanges(Replaces);
return Changes; return Changes;
} }
@ -36,20 +35,16 @@ TEST(Reformatter, SingleReformat) {
Reformatter ChangesReformatter(format::getLLVMStyle()); Reformatter ChangesReformatter(format::getLLVMStyle());
ChangedRanges Changes = makeChangedRanges(0, 6); ChangedRanges Changes = makeChangedRanges(0, 6);
tooling::ReplacementsVec Replaces; tooling::Replacements Replaces = ChangesReformatter.reformatSingleFile(
ChangesReformatter.reformatSingleFile( FileName, Changes, VFHelper.getNewSourceManager());
FileName, Changes, VFHelper.getNewSourceManager(), Replaces);
// We expect the code above to reformatted like so: SourceOverrides Overrides(FileName, /*TrackChanges=*/false);
// Overrides.applyReplacements(Replaces, VFHelper.getNewSourceManager());
// int a;
// int b; std::string Expected, Result;
//
// This test is slightly fragile since there's more than one Replacement that Expected = "int a;\n"
// results in the above change. However, testing the result of applying the "int b;\n";
// replacement is more trouble than it's worth in this context. Result = Overrides.getMainFileContent();
ASSERT_EQ(1u, Replaces.size()); EXPECT_EQ(Expected, Result);
EXPECT_EQ(3u, Replaces[0].getOffset());
EXPECT_EQ(2u, Replaces[0].getLength());
EXPECT_EQ(" ", Replaces[0].getReplacementText());
} }

View File

@ -26,7 +26,7 @@ public:
DummyTransform(llvm::StringRef Name, const TransformOptions &Options) DummyTransform(llvm::StringRef Name, const TransformOptions &Options)
: Transform(Name, Options) {} : Transform(Name, Options) {}
virtual int apply(const FileOverrides &, virtual int apply(FileOverrides &,
const tooling::CompilationDatabase &, const tooling::CompilationDatabase &,
const std::vector<std::string> &) { return 0; } const std::vector<std::string> &) { return 0; }
@ -161,7 +161,7 @@ TEST(Transform, Timings) {
// Transform's handle* functions require FileOverrides to be set, even if // Transform's handle* functions require FileOverrides to be set, even if
// there aren't any. // there aren't any.
FileOverrides Overrides; FileOverrides Overrides(/*TrackFileChanges=*/false);
T.setOverrides(Overrides); T.setOverrides(Overrides);
Tool.run(clang::tooling::newFrontendActionFactory(&Factory, &Callbacks)); Tool.run(clang::tooling::newFrontendActionFactory(&Factory, &Callbacks));

View File

@ -28,31 +28,34 @@ TEST(UniqueHeaderName, testUniqueHeaderName) {
append(SourceFile, "project/lib/feature.cpp"); append(SourceFile, "project/lib/feature.cpp");
native(SourceFile.str().str(), SourceFile); native(SourceFile.str().str(), SourceFile);
llvm::SmallString<128> FullActualPath; llvm::SmallString<128> HeaderFile(TmpDir);
append(HeaderFile, "project/include/feature.h");
native(HeaderFile.str().str(), HeaderFile);
llvm::SmallString<128> ExpectedName("^feature.cpp_feature.h_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}.yaml$");
llvm::SmallString<128> ActualName;
llvm::SmallString<128> Error; llvm::SmallString<128> Error;
bool Result = bool Result =
generateReplacementsFileName(SourceFile, FullActualPath, Error); generateReplacementsFileName(SourceFile, HeaderFile, ActualName, Error);
ASSERT_TRUE(Result); ASSERT_TRUE(Result);
EXPECT_TRUE(Error.empty()); EXPECT_TRUE(Error.empty());
// We need to check the directory name and filename separately since on // We need to check the directory name and filename separately since on
// Windows, the path separator is '\' which is a regex escape character. // Windows, the path separator is '\' which is a regex escape character.
llvm::SmallString<128> ExpectedPath = llvm::SmallString<128> ExpectedHeaderPath =
llvm::sys::path::parent_path(SourceFile); llvm::sys::path::parent_path(HeaderFile);
llvm::SmallString<128> ActualPath = llvm::SmallString<128> ActualHeaderPath =
llvm::sys::path::parent_path(FullActualPath); llvm::sys::path::parent_path(ActualName);
llvm::SmallString<128> ActualName = llvm::SmallString<128> ActualHeaderName =
llvm::sys::path::filename(FullActualPath); llvm::sys::path::filename(ActualName);
EXPECT_STREQ(ExpectedPath.c_str(), ActualPath.c_str()); EXPECT_STREQ(ExpectedHeaderPath.c_str(), ActualHeaderPath.c_str());
llvm::StringRef ExpectedName =
"^feature.cpp_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_["
"0-9a-f]{2}_[0-9a-f]{2}.yaml$";
llvm::Regex R(ExpectedName); llvm::Regex R(ExpectedName);
ASSERT_TRUE(R.match(ActualName)) ASSERT_TRUE(R.match(ActualHeaderName))
<< "ExpectedName: " << ExpectedName.data() << "ExpectedName: " << ExpectedName.c_str()
<< "\nActualName: " << ActualName.c_str(); << "\nActualName: " << ActualName.c_str();
ASSERT_TRUE(Error.empty()) << "Error: " << Error.c_str(); ASSERT_TRUE(Error.empty()) << "Error: " << Error.c_str();
} }