diff options
Diffstat (limited to 'clang-tools-extra/cpp11-migrate/Core')
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp | 227 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/FileOverrides.h | 202 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Makefile | 2 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Refactoring.h | 31 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp | 46 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Reformatting.h | 40 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp | 4 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Transform.cpp | 28 | ||||
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Transform.h | 31 |
9 files changed, 396 insertions, 215 deletions
diff --git a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp index 7ab7e91c30c..d8d4b3f27e1 100644 --- a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp @@ -29,14 +29,157 @@ using namespace clang; using namespace clang::tooling; -bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, - llvm::SmallVectorImpl<char> &Result, - llvm::SmallVectorImpl<char> &Error) { +void HeaderOverride::recordReplacements( + const clang::tooling::Replacements &Replaces) { + 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; + 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(); - if (llvm::error_code EC = fs::createUniqueFile( - MainSourceFile + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { + if (llvm::error_code EC = + fs::createUniqueFile(HeaderPath.c_str(), Result)) { Error.append(EC.message().begin(), EC.message().end()); return false; } @@ -44,6 +187,20 @@ bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, 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 { /// \brief Comparator to be able to order tooling::Range based on their offset. @@ -90,11 +247,10 @@ struct RangeReplacedAdjuster { } // end anonymous namespace -void -ChangedRanges::adjustChangedRanges(const tooling::ReplacementsVec &Replaces) { +void ChangedRanges::adjustChangedRanges(const tooling::Replacements &Replaces) { // first adjust existing ranges in case they overlap with the replacements - for (ReplacementsVec::const_iterator I = Replaces.begin(), E = Replaces.end(); - I != E; ++I) { + for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E; + ++I) { const tooling::Replacement &Replace = *I; 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 - for (ReplacementsVec::const_iterator I = Replaces.begin(), E = Replaces.end(); - I != E; ++I) { + for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E; + ++I) { const tooling::Replacement &R = *I; unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset()); unsigned Length = R.getReplacementText().size(); @@ -147,52 +303,3 @@ void ChangedRanges::coalesceRanges() { std::mem_fun_ref(&Range::contains)), 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; -} diff --git a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h index 8cde7591303..3e81abc6d34 100644 --- a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h +++ b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h @@ -16,8 +16,7 @@ #ifndef CPP11_MIGRATE_FILE_OVERRIDES_H #define CPP11_MIGRATE_FILE_OVERRIDES_H -#include "Core/Refactoring.h" -#include "clang-replace/Tooling/ApplyReplacements.h" +#include "clang/Tooling/Refactoring.h" #include "clang/Tooling/ReplacementsYaml.h" #include "llvm/ADT/StringMap.h" @@ -45,13 +44,13 @@ public: /// to remove replaced parts. /// /// 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. - /// \{ + /// @{ const_iterator begin() const { return Ranges.begin(); } const_iterator end() const { return Ranges.end(); } - /// \} + /// @} private: void coalesceRanges(); @@ -59,71 +58,178 @@ private: RangeVec Ranges; }; -/// \brief Maintains current state of transformed files and tracks source ranges -/// where changes have been made. -class FileOverrides { +/// \brief Container for storing override information for a single headers. +class HeaderOverride { public: - /// \brief Maps file names to file contents. - typedef llvm::StringMap<std::string> FileStateMap; + /// \brief Constructors. + /// @{ + HeaderOverride() {} + HeaderOverride(llvm::StringRef HeaderPath, + llvm::StringRef MainSourceFile) : HeaderPath(HeaderPath) { + Replacements.MainSourceFile = MainSourceFile; + } + /// @} - /// \brief Maps file names to change tracking info for a file. - typedef llvm::StringMap<ChangedRanges> ChangeMap; + /// \brief Getter for HeaderPath. + llvm::StringRef getHeaderPath() const { + return HeaderPath; + } + /// \brief Accessor for ContentOverride. + /// @{ + llvm::StringRef getContentOverride() const { return ContentOverride; } + void setContentOverride(const llvm::StringRef S) { ContentOverride = S; } + /// @} - /// \brief Override file contents seen by \c SM for all files stored by this - /// object. - void applyOverrides(clang::SourceManager &SM) const; + /// \brief Getter for Changes. + const ChangedRanges &getChanges() const { return Changes; } - /// \brief Update change tracking information based on replacements stored in - /// \c Replaces. - void - adjustChangedRanges(const clang::replace::FileToReplacementsMap &Replaces); + /// \brief Swaps the content of ContentOverride with \p S. + void swapContentOverride(std::string &S) { ContentOverride.swap(S); } - /// \brief Accessor for change tracking information. - const ChangeMap &getChangedRanges() const { - return ChangeTracking; + /// \brief Getter for Replacements. + const clang::tooling::TranslationUnitReplacements &getReplacements() const { + return Replacements; } - /// \brief Coalesce changes stored in \c Rewrites and replace file contents - /// overrides stored in this object. + /// \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: + std::string ContentOverride; + 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? /// - /// \param Rewrites Rewriter containing changes to files. - void updateState(const clang::Rewriter &Rewrites); + /// Tracking file changes can be useful to reformat the code for example. + bool isTrackingFileChanges() const { return TrackChanges; } + /// @} - /// \brief Accessor for current file state. - const FileStateMap &getState() const { return FileStates; } + /// \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 Write all file contents overrides to disk. + /// \brief Override the file contents by applying all the replacements. /// - /// \param Diagnostics DiagnosticsEngine for error output. + /// \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. /// - /// \returns \li true if all files with overridden file contents were written - /// to disk successfully. - /// \li false if any failure occurred. - bool writeToDisk(clang::DiagnosticsEngine &Diagnostics) const; + /// \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: - FileStateMap FileStates; - ChangeMap ChangeTracking; + 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. /// -/// Generates a unique filename in the same directory as \c MainSourceFile. The -/// filename is generated following this pattern: +/// Generates a unique filename in the same directory as the header file. The +/// 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. /// -/// \param[in] MainSourceFile Full path to the source file. -/// \param[out] Result The resulting unique filename in the same directory as -/// the \c MainSourceFile. -/// \param[out] Error If an error occurs a description of that error is -/// placed in this string. -/// \returns true on success, false if a unique file name could not be created. -bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, - llvm::SmallVectorImpl<char> &Result, - llvm::SmallVectorImpl<char> &Error); +/// @param SourceFile Full path to the source file. +/// @param HeaderFile Full path to the header file. +/// @param Result The resulting unique filename in the same directory as the +/// header file. +/// @param Error Description of the error if there is any. +/// @returns true if succeeded, false otherwise. +bool generateReplacementsFileName(llvm::StringRef SourceFile, + llvm::StringRef HeaderFile, + llvm::SmallVectorImpl<char> &Result, + llvm::SmallVectorImpl<char> &Error); #endif // CPP11_MIGRATE_FILE_OVERRIDES_H diff --git a/clang-tools-extra/cpp11-migrate/Core/Makefile b/clang-tools-extra/cpp11-migrate/Core/Makefile index 51bc98defee..5da4cec8481 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Makefile +++ b/clang-tools-extra/cpp11-migrate/Core/Makefile @@ -11,4 +11,4 @@ LIBRARYNAME := migrateCore include $(CLANG_LEVEL)/Makefile -CPP.Flags += -I$(PROJ_SRC_DIR)/.. -I$(PROJ_SRC_DIR)/../../clang-replace/include +CPP.Flags += -I$(PROJ_SRC_DIR)/.. diff --git a/clang-tools-extra/cpp11-migrate/Core/Refactoring.h b/clang-tools-extra/cpp11-migrate/Core/Refactoring.h deleted file mode 100644 index a15634a3704..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Refactoring.h +++ /dev/null @@ -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 diff --git a/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp b/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp index 50ba1f19f7a..4e14ea5784e 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp @@ -22,23 +22,39 @@ using namespace clang; -void Reformatter::reformatChanges(const FileOverrides &FileStates, - clang::SourceManager &SM, - clang::tooling::ReplacementsVec &Replaces) { - FileStates.applyOverrides(SM); - - for (FileOverrides::ChangeMap::const_iterator - I = FileStates.getChangedRanges().begin(), - E = FileStates.getChangedRanges().end(); +void Reformatter::reformatChanges(SourceOverrides &Overrides) { + llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts( + new DiagnosticOptions()); + DiagnosticsEngine Diagnostics( + llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), + DiagOpts.getPtr()); + FileManager Files((FileSystemOptions())); + SourceManager SM(Diagnostics, Files); + + reformatChanges(Overrides, SM); +} + +void Reformatter::reformatChanges(SourceOverrides &Overrides, + clang::SourceManager &SM) { + 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) { - reformatSingleFile(I->getKey(), I->getValue(), SM, Replaces); + 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); } -void Reformatter::reformatSingleFile( - const llvm::StringRef FileName, const ChangedRanges &Changes, - SourceManager &SM, clang::tooling::ReplacementsVec &FormatReplacements) { - +tooling::Replacements Reformatter::reformatSingleFile( + llvm::StringRef FileName, const ChangedRanges &Changes, SourceManager &SM) { const clang::FileEntry *Entry = SM.getFileManager().getFile(FileName); assert(Entry && "expected an existing file"); @@ -56,7 +72,5 @@ void Reformatter::reformatSingleFile( } Lexer Lex(ID, SM.getBuffer(ID), SM, getFormattingLangOpts(Style.Standard)); - const tooling::Replacements &R = - format::reformat(Style, Lex, SM, ReformatRanges); - std::copy(R.begin(), R.end(), std::back_inserter(FormatReplacements)); + return format::reformat(Style, Lex, SM, ReformatRanges); } diff --git a/clang-tools-extra/cpp11-migrate/Core/Reformatting.h b/clang-tools-extra/cpp11-migrate/Core/Reformatting.h index 9a10171a742..e63e51d2160 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Reformatting.h +++ b/clang-tools-extra/cpp11-migrate/Core/Reformatting.h @@ -16,10 +16,9 @@ #ifndef CPP11_MIGRATE_REFORMATTING_H #define CPP11_MIGRATE_REFORMATTING_H -#include "Core/Refactoring.h" #include "clang/Format/Format.h" -class FileOverrides; +class SourceOverrides; class ChangedRanges; class Reformatter { @@ -28,30 +27,31 @@ public: /// \brief Reformat the changes made to the file overrides. /// - /// This function will apply the state of files stored in \c FileState to \c - /// SM. + /// \param Overrides Overriden source files to reformat. Note that since only + /// 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. - /// \param[in] SM SourceManager for access to source files. - /// \param[out] Replaces Container to store all reformatting replacements. - void reformatChanges(const FileOverrides &FileState, clang::SourceManager &SM, - clang::tooling::ReplacementsVec &Replaces); + /// \sa \c SourceOverrides::isTrackingFileChanges() + void reformatChanges(SourceOverrides &Overrides, clang::SourceManager &SM); + + /// \brief Overload of \c reformatChanges() providing it's own + /// \c SourceManager. + void reformatChanges(SourceOverrides &Overrides); /// \brief Produce a list of replacements to apply on \p FileName, only the /// ranges in \p Changes are replaced. /// - /// Since this routine use \c clang::format::reformat() the rules that - /// function applies to ranges also apply here. + /// Since this routine use \c clang::format::reformat() the rules that applies + /// on the ranges are identical: /// - /// \param[in] FileName Name of file to reformat. - /// \param[in] Changes Description of where changes were made to the file. - /// \param[in] SM SourceManager required to create replacements. - /// \param[out] FormatReplacements New reformatting replacements are appended - /// to this container. - void reformatSingleFile(const llvm::StringRef FileName, - const ChangedRanges &Changes, - clang::SourceManager &SM, - clang::tooling::ReplacementsVec &FormatReplacements); + /// \par + /// Each range is extended on either end to its next bigger logic + /// unit, i.e. everything that might influence its formatting or might be + /// influenced by its formatting. + /// -- \c clang::format::reformat() + clang::tooling::Replacements reformatSingleFile(llvm::StringRef FileName, + const ChangedRanges &Changes, + clang::SourceManager &SM); private: clang::format::FormatStyle Style; diff --git a/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp b/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp index bd2eb63044f..7315768f360 100644 --- a/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp @@ -30,7 +30,9 @@ public: if (!SyntaxOnlyAction::BeginSourceFileAction(CI, Filename)) return false; - Overrides.applyOverrides(CI.getSourceManager()); + FileOverrides::const_iterator I = Overrides.find(Filename); + if (I != Overrides.end()) + I->second->applyOverrides(CI.getSourceManager()); return true; } diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp index cd76723d316..4354df2987e 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp @@ -100,8 +100,13 @@ bool Transform::isFileModifiable(const SourceManager &SM, bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { assert(Overrides != 0 && "Subclass transform didn't provide InputState"); - Overrides->applyOverrides(CI.getSourceManager()); - CurrentSource = Filename; + CurrentSource = Filename.str(); + + FileOverrides::const_iterator I = Overrides->find(CurrentSource); + if (I != Overrides->end()) + I->second->applyOverrides(CI.getSourceManager()); + + Replace.clear(); if (Options().EnableTiming) { Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord())); @@ -111,7 +116,11 @@ bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { } void Transform::handleEndSource() { - CurrentSource.clear(); + if (!getReplacements().empty()) { + SourceOverrides &SO = Overrides->getOrCreate(CurrentSource); + SO.applyReplacements(getReplacements()); + } + if (Options().EnableTiming) 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)); } -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) { return new ActionFactory(Finder, /*Owner=*/ *this); } diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.h b/clang-tools-extra/cpp11-migrate/Core/Transform.h index 45e470d64e4..43082111d54 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.h +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.h @@ -17,7 +17,7 @@ #define CPP11_MIGRATE_TRANSFORM_H #include "Core/IncludeExcludeInfo.h" -#include "Core/Refactoring.h" +#include "clang/Tooling/Refactoring.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Registry.h" @@ -52,12 +52,6 @@ class MatchFinder; 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. extern llvm::cl::OptionCategory TransformsOptionsCategory; @@ -105,7 +99,7 @@ public: /// SourcePaths and should take precedence over content of files on disk. /// Upon return, \p ResultStates shall contain the result of performing this /// 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 std::vector<std::string> &SourcePaths) = 0; @@ -178,17 +172,6 @@ public: /// \brief Return an iterator to the start of collected timing data. 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: void setAcceptedChanges(unsigned Changes) { @@ -212,12 +195,16 @@ protected: /// created with. 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 /// applying frontend actions. /// /// It is an error not to call this function before calling ClangTool::run() /// with the factory provided by createActionFactory(). - void setOverrides(const FileOverrides &Overrides) { + void setOverrides(FileOverrides &Overrides) { this->Overrides = &Overrides; } @@ -232,8 +219,8 @@ protected: private: const std::string Name; const TransformOptions &GlobalOptions; - const FileOverrides *Overrides; - TUReplacementsMap Replacements; + FileOverrides *Overrides; + clang::tooling::Replacements Replace; std::string CurrentSource; TimingVec Timings; unsigned AcceptedChanges; |