diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp index bcd6d302e334..c192718ce602 100644 --- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp +++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp @@ -228,7 +228,7 @@ int main(int argc, char **argv) { if (ErrorCode) { errs() << "Trouble iterating over directory '" << Directory << "': " << ErrorCode.message() << "\n"; - return false; + return 1; } // Remove the TUReplacementFiles (triggered by "remove-change-desc-files" diff --git a/clang-tools-extra/clang-modernize/AddOverride/AddOverride.cpp b/clang-tools-extra/clang-modernize/AddOverride/AddOverride.cpp index 9a13c044e5d2..80165d45481e 100644 --- a/clang-tools-extra/clang-modernize/AddOverride/AddOverride.cpp +++ b/clang-tools-extra/clang-modernize/AddOverride/AddOverride.cpp @@ -29,8 +29,7 @@ static cl::opt DetectMacros( cl::desc("Detect and use macros that expand to the 'override' keyword."), cl::cat(TransformsOptionsCategory)); -int AddOverrideTransform::apply(const FileOverrides &InputStates, - const CompilationDatabase &Database, +int AddOverrideTransform::apply(const CompilationDatabase &Database, const std::vector &SourcePaths) { ClangTool AddOverrideTool(Database, SourcePaths); unsigned AcceptedChanges = 0; @@ -42,8 +41,6 @@ int AddOverrideTransform::apply(const FileOverrides &InputStates, // Make Fixer available to handleBeginSource(). this->Fixer = &Fixer; - setOverrides(InputStates); - if (int result = AddOverrideTool.run(createActionFactory(Finder))) { llvm::errs() << "Error encountered during translation.\n"; return result; diff --git a/clang-tools-extra/clang-modernize/AddOverride/AddOverride.h b/clang-tools-extra/clang-modernize/AddOverride/AddOverride.h index d5d602efb004..51222907fadd 100644 --- a/clang-tools-extra/clang-modernize/AddOverride/AddOverride.h +++ b/clang-tools-extra/clang-modernize/AddOverride/AddOverride.h @@ -31,8 +31,7 @@ public: : Transform("AddOverride", Options) {} /// \see Transform::run(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) LLVM_OVERRIDE; virtual bool handleBeginSource(clang::CompilerInstance &CI, diff --git a/clang-tools-extra/clang-modernize/CMakeLists.txt b/clang-tools-extra/clang-modernize/CMakeLists.txt index 5413edc2abc0..9751b3c0d5f4 100644 --- a/clang-tools-extra/clang-modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-modernize/CMakeLists.txt @@ -1,6 +1,3 @@ -get_filename_component(ClangReplaceLocation - "${CMAKE_CURRENT_SOURCE_DIR}/../clang-apply-replacements/include" ABSOLUTE) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${ClangReplaceLocation} diff --git a/clang-tools-extra/clang-modernize/Core/CMakeLists.txt b/clang-tools-extra/clang-modernize/Core/CMakeLists.txt index 787388b69e27..784b56026c29 100644 --- a/clang-tools-extra/clang-modernize/Core/CMakeLists.txt +++ b/clang-tools-extra/clang-modernize/Core/CMakeLists.txt @@ -1,13 +1,11 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(modernizeCore - FileOverrides.cpp - SyntaxCheck.cpp + ReplacementHandling.cpp Transforms.cpp Transform.cpp IncludeExcludeInfo.cpp PerfSupport.cpp - Reformatting.cpp IncludeDirectives.cpp ) target_link_libraries(modernizeCore diff --git a/clang-tools-extra/clang-modernize/Core/FileOverrides.cpp b/clang-tools-extra/clang-modernize/Core/FileOverrides.cpp deleted file mode 100644 index 7ab7e91c30c0..000000000000 --- a/clang-tools-extra/clang-modernize/Core/FileOverrides.cpp +++ /dev/null @@ -1,198 +0,0 @@ -//===-- Core/FileOverrides.cpp --------------------------------------------===// -// -// 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 provides types and functionality for dealing with source -/// and header file content overrides. -/// -//===----------------------------------------------------------------------===// - -#include "Core/FileOverrides.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Tooling/Tooling.h" -#include "clang/Tooling/ReplacementsYaml.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include - -using namespace clang; -using namespace clang::tooling; - -bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, - llvm::SmallVectorImpl &Result, - llvm::SmallVectorImpl &Error) { - using namespace llvm::sys; - - Error.clear(); - if (llvm::error_code EC = fs::createUniqueFile( - MainSourceFile + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { - Error.append(EC.message().begin(), EC.message().end()); - return false; - } - - return true; -} - -namespace { - -/// \brief Comparator to be able to order tooling::Range based on their offset. -bool rangeLess(clang::tooling::Range A, clang::tooling::Range B) { - if (A.getOffset() == B.getOffset()) - return A.getLength() < B.getLength(); - return A.getOffset() < B.getOffset(); -} - -/// \brief Functor that returns the given range without its overlaps with the -/// replacement given in the constructor. -struct RangeReplacedAdjuster { - RangeReplacedAdjuster(const tooling::Replacement &Replace) - : Replace(Replace.getOffset(), Replace.getLength()), - ReplaceNewSize(Replace.getReplacementText().size()) {} - - tooling::Range operator()(clang::tooling::Range Range) const { - if (!Range.overlapsWith(Replace)) - return Range; - // range inside replacement -> make the range length null - if (Replace.contains(Range)) - return tooling::Range(Range.getOffset(), 0); - // replacement inside range -> resize the range - if (Range.contains(Replace)) { - int Difference = ReplaceNewSize - Replace.getLength(); - return tooling::Range(Range.getOffset(), Range.getLength() + Difference); - } - // beginning of the range replaced -> truncate range beginning - if (Range.getOffset() > Replace.getOffset()) { - unsigned ReplaceEnd = Replace.getOffset() + Replace.getLength(); - unsigned RangeEnd = Range.getOffset() + Range.getLength(); - return tooling::Range(ReplaceEnd, RangeEnd - ReplaceEnd); - } - // end of the range replaced -> truncate range end - if (Range.getOffset() < Replace.getOffset()) - return tooling::Range(Range.getOffset(), - Replace.getOffset() - Range.getOffset()); - llvm_unreachable("conditions not handled properly"); - } - - const tooling::Range Replace; - const unsigned ReplaceNewSize; -}; - -} // end anonymous namespace - -void -ChangedRanges::adjustChangedRanges(const tooling::ReplacementsVec &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) { - const tooling::Replacement &Replace = *I; - - std::transform(Ranges.begin(), Ranges.end(), Ranges.begin(), - RangeReplacedAdjuster(Replace)); - } - - // then shift existing ranges to reflect the new positions - for (RangeVec::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - unsigned ShiftedOffset = - tooling::shiftedCodePosition(Replaces, I->getOffset()); - *I = tooling::Range(ShiftedOffset, I->getLength()); - } - - // then generate the new ranges from the replacements - for (ReplacementsVec::const_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(); - - Ranges.push_back(tooling::Range(Offset, Length)); - } - - // cleanups unecessary ranges to finish - coalesceRanges(); -} - -void ChangedRanges::coalesceRanges() { - // sort the ranges by offset and then for each group of adjacent/overlapping - // ranges the first one in the group is extended to cover the whole group. - std::sort(Ranges.begin(), Ranges.end(), &rangeLess); - RangeVec::iterator FirstInGroup = Ranges.begin(); - assert(!Ranges.empty() && "unexpected empty vector"); - for (RangeVec::iterator I = Ranges.begin() + 1, E = Ranges.end(); I != E; - ++I) { - unsigned GroupEnd = FirstInGroup->getOffset() + FirstInGroup->getLength(); - - // no contact - if (I->getOffset() > GroupEnd) - FirstInGroup = I; - else { - unsigned GrpBegin = FirstInGroup->getOffset(); - unsigned GrpEnd = std::max(GroupEnd, I->getOffset() + I->getLength()); - *FirstInGroup = tooling::Range(GrpBegin, GrpEnd - GrpBegin); - } - } - - // remove the ranges that are covered by the first member of the group - Ranges.erase(std::unique(Ranges.begin(), Ranges.end(), - 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/clang-modernize/Core/FileOverrides.h b/clang-tools-extra/clang-modernize/Core/FileOverrides.h deleted file mode 100644 index f1c43e34215b..000000000000 --- a/clang-tools-extra/clang-modernize/Core/FileOverrides.h +++ /dev/null @@ -1,129 +0,0 @@ -//===-- Core/FileOverrides.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 provides types and functionality for dealing with source -/// and header file content overrides. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_FILE_OVERRIDES_H -#define CLANG_MODERNIZE_FILE_OVERRIDES_H - -#include "Core/Refactoring.h" -#include "clang-apply-replacements/Tooling/ApplyReplacements.h" -#include "clang/Tooling/ReplacementsYaml.h" -#include "llvm/ADT/StringMap.h" - -// Forward Declarations -namespace llvm { -template -class SmallVectorImpl; -} // namespace llvm -namespace clang { -class SourceManager; -class Rewriter; -} // namespace clang - -/// \brief Class encapsulating a list of \c tooling::Range with some -/// convenience methods. -/// -/// The ranges stored are used to keep track of the overriden parts of a file. -class ChangedRanges { - typedef std::vector RangeVec; - -public: - typedef RangeVec::const_iterator const_iterator; - - /// \brief Create new ranges from the replacements and adjust existing one - /// to remove replaced parts. - /// - /// Note that all replacements should come from the same file. - void adjustChangedRanges(const clang::tooling::ReplacementsVec &Replaces); - - /// \brief Iterators. - /// \{ - const_iterator begin() const { return Ranges.begin(); } - const_iterator end() const { return Ranges.end(); } - /// \} - -private: - void coalesceRanges(); - - RangeVec Ranges; -}; - -/// \brief Maintains current state of transformed files and tracks source ranges -/// where changes have been made. -class FileOverrides { -public: - /// \brief Maps file names to file contents. - typedef llvm::StringMap FileStateMap; - - /// \brief Maps file names to change tracking info for a file. - typedef llvm::StringMap ChangeMap; - - - /// \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 - /// overrides stored in this object. - /// - /// \param Rewrites Rewriter containing changes to files. - void updateState(const clang::Rewriter &Rewrites); - - /// \brief Accessor for current file state. - const FileStateMap &getState() const { return FileStates; } - - /// \brief Write all file contents overrides to disk. - /// - /// \param Diagnostics DiagnosticsEngine for error output. - /// - /// \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; - -private: - FileStateMap FileStates; - ChangeMap ChangeTracking; -}; - -/// \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: -/// -/// MainSourceFile_%%_%%_%%_%%_%%_%%.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 &Result, - llvm::SmallVectorImpl &Error); - -#endif // CLANG_MODERNIZE_FILE_OVERRIDES_H diff --git a/clang-tools-extra/clang-modernize/Core/Reformatting.cpp b/clang-tools-extra/clang-modernize/Core/Reformatting.cpp deleted file mode 100644 index 50ba1f19f7a1..000000000000 --- a/clang-tools-extra/clang-modernize/Core/Reformatting.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- Core/Reformatting.cpp - LibFormat integration ---------------------===// -// -// 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 provides the LibFormat integration used to reformat -/// migrated code. -/// -//===----------------------------------------------------------------------===// - -#include "Core/Reformatting.h" -#include "Core/FileOverrides.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" - -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(); - I != E; ++I) { - reformatSingleFile(I->getKey(), I->getValue(), SM, Replaces); - } -} - -void Reformatter::reformatSingleFile( - const llvm::StringRef FileName, const ChangedRanges &Changes, - SourceManager &SM, clang::tooling::ReplacementsVec &FormatReplacements) { - - const clang::FileEntry *Entry = SM.getFileManager().getFile(FileName); - assert(Entry && "expected an existing file"); - - FileID ID = SM.translateFile(Entry); - if (ID.isInvalid()) - ID = SM.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User); - - std::vector ReformatRanges; - SourceLocation StartOfFile = SM.getLocForStartOfFile(ID); - for (ChangedRanges::const_iterator I = Changes.begin(), E = Changes.end(); - I != E; ++I) { - SourceLocation Start = StartOfFile.getLocWithOffset(I->getOffset()); - SourceLocation End = Start.getLocWithOffset(I->getLength()); - ReformatRanges.push_back(CharSourceRange::getCharRange(Start, End)); - } - - 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)); -} diff --git a/clang-tools-extra/clang-modernize/Core/Reformatting.h b/clang-tools-extra/clang-modernize/Core/Reformatting.h deleted file mode 100644 index a9c76df438fb..000000000000 --- a/clang-tools-extra/clang-modernize/Core/Reformatting.h +++ /dev/null @@ -1,60 +0,0 @@ -//===-- Core/Reformatting.h - LibFormat integration -------------*- 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 provides the LibFormat integration used to reformat -/// migrated code. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_REFORMATTING_H -#define CLANG_MODERNIZE_REFORMATTING_H - -#include "Core/Refactoring.h" -#include "clang/Format/Format.h" - -class FileOverrides; -class ChangedRanges; - -class Reformatter { -public: - Reformatter(const clang::format::FormatStyle &Style) : Style(Style) {} - - /// \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[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); - - /// \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. - /// - /// \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); - -private: - clang::format::FormatStyle Style; -}; - -#endif // CLANG_MODERNIZE_REFORMATTING_H diff --git a/clang-tools-extra/clang-modernize/Core/ReplacementHandling.cpp b/clang-tools-extra/clang-modernize/Core/ReplacementHandling.cpp new file mode 100644 index 000000000000..ec0ab3ed938b --- /dev/null +++ b/clang-tools-extra/clang-modernize/Core/ReplacementHandling.cpp @@ -0,0 +1,155 @@ +//===-- Core/ReplacementHandling.cpp --------------------------------------===// +// +// 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 provides implementations for the ReplacementHandling class. +/// +//===----------------------------------------------------------------------===// + +#include "Core/ReplacementHandling.h" +#include "clang/Tooling/ReplacementsYaml.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/system_error.h" + +using namespace llvm; +using namespace llvm::sys; +using namespace clang::tooling; + +bool ReplacementHandling::findClangApplyReplacements(const char *Argv0) { + CARPath = FindProgramByName("clang-apply-replacements"); + + if (!CARPath.empty()) + return true; + + static int StaticSymbol; + CARPath = fs::getMainExecutable(Argv0, &StaticSymbol); + SmallString<128> TestPath = path::parent_path(CARPath); + path::append(TestPath, "clang-apply-replacements"); + if (fs::can_execute(Twine(TestPath))) + CARPath = TestPath.str(); + + return !CARPath.empty(); +} + +StringRef ReplacementHandling::useTempDestinationDir() { + DestinationDir = generateTempDir(); + return DestinationDir; +} + +void ReplacementHandling::enableFormatting(StringRef Style, + StringRef StyleConfigDir) { + DoFormat = true; + FormatStyle = Style; + this->StyleConfigDir = StyleConfigDir; +} + +bool ReplacementHandling::serializeReplacements( + const TUReplacementsMap &Replacements) { + assert(!DestinationDir.empty() && "Destination directory not set"); + + bool Errors = false; + + for (TUReplacementsMap::const_iterator I = Replacements.begin(), + E = Replacements.end(); + I != E; ++I) { + SmallString<128> ReplacementsFileName; + SmallString<64> Error; + bool Result = generateReplacementsFileName(DestinationDir, + I->getValue().MainSourceFile, + ReplacementsFileName, Error); + if (!Result) { + errs() << "Failed to generate replacements filename:" << Error << "\n"; + Errors = true; + continue; + } + + std::string ErrorInfo; + raw_fd_ostream ReplacementsFile(ReplacementsFileName.c_str(), ErrorInfo, + fs::F_Binary); + if (!ErrorInfo.empty()) { + errs() << "Error opening file: " << ErrorInfo << "\n"; + Errors = true; + continue; + } + yaml::Output YAML(ReplacementsFile); + YAML << const_cast(I->getValue()); + } + return !Errors; +} + +bool ReplacementHandling::applyReplacements() { + SmallVector Argv; + Argv.push_back(CARPath.c_str()); + std::string Style = "--style=" + FormatStyle; + std::string StyleConfig = "--style-config=" + StyleConfigDir; + if (DoFormat) { + Argv.push_back("--format"); + Argv.push_back(Style.c_str()); + if (!StyleConfigDir.empty()) + Argv.push_back(StyleConfig.c_str()); + } + Argv.push_back("--remove-change-desc-files"); + Argv.push_back(DestinationDir.c_str()); + + // Argv array needs to be null terminated. + Argv.push_back(0); + + std::string ErrorMsg; + bool ExecutionFailed = false; + int ReturnCode = ExecuteAndWait(CARPath.c_str(), Argv.data(), /* env */ 0, + /* redirects */ 0, + /* secondsToWait */ 0, /* memoryLimit */ 0, + &ErrorMsg, &ExecutionFailed); + if (ExecutionFailed || !ErrorMsg.empty()) { + errs() << "Failed to launch clang-apply-replacements: " << ErrorMsg << "\n"; + errs() << "Command Line:\n"; + for (const char **I = Argv.begin(), **E = Argv.end(); I != E; ++I) { + if (*I) + errs() << *I << "\n"; + } + return false; + } + + if (ReturnCode != 0) { + errs() << "clang-apply-replacements failed with return code " << ReturnCode + << "\n"; + return false; + } + + return true; +} + +std::string ReplacementHandling::generateTempDir() { + SmallString<128> Prefix; + path::system_temp_directory(true, Prefix); + path::append(Prefix, "clang-modernize"); + SmallString<128> Result; + fs::createUniqueDirectory(Twine(Prefix), Result); + return Result.str(); +} + +bool ReplacementHandling::generateReplacementsFileName( + StringRef DestinationDir, StringRef MainSourceFile, + SmallVectorImpl &Result, SmallVectorImpl &Error) { + + Error.clear(); + SmallString<128> Prefix = DestinationDir; + path::append(Prefix, path::filename(MainSourceFile)); + if (error_code EC = + fs::createUniqueFile(Prefix + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { + const std::string &Msg = EC.message(); + Error.append(Msg.begin(), Msg.end()); + return false; + } + + return true; +} diff --git a/clang-tools-extra/clang-modernize/Core/ReplacementHandling.h b/clang-tools-extra/clang-modernize/Core/ReplacementHandling.h new file mode 100644 index 000000000000..be3d15077193 --- /dev/null +++ b/clang-tools-extra/clang-modernize/Core/ReplacementHandling.h @@ -0,0 +1,119 @@ +//===-- Core/ReplacementHandling.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 defines the ReplacementHandling class which abstracts +/// serialization and application of serialized replacements. +/// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_MODERNIZE_REPLACEMENTHANDLING_H +#define CLANG_MODERNIZE_REPLACEMENTHANDLING_H + +#include "llvm/ADT/StringRef.h" +#include "Core/Transform.h" + +class ReplacementHandling { +public: + + /// \brief Finds the path to the executable 'clang-apply-replacements'. + /// + /// The executable is searched for on the PATH. If not found, looks in the + /// same directory as the image used to start the current executable. + /// + /// \param[in] Argv0 argv[0] as passed to main(). + /// + /// \returns \li true if clang-apply-replacements was found. + /// \li false otherwise. + bool findClangApplyReplacements(const char *Argv0); + + /// \brief Set the name of the directory in which replacements will be + /// serialized. + /// + /// \param[in] Dir Destination directory name + void setDestinationDir(llvm::StringRef Dir) { DestinationDir = Dir; } + + /// \brief Create a new temporary directory to serialize replacements into. + /// + /// \returns The name of the directory createdy. + llvm::StringRef useTempDestinationDir(); + + /// \brief Enable clang-apply-replacements do code reformatting when applying + /// serialized replacements. + /// + /// \param[in] Style Value to pass to clang-apply-replacement's --style + /// option. + /// \param[in] StyleConfigDir If non-empty, value to pass to + /// clang-apply-replacement's --style-config option. + void enableFormatting(llvm::StringRef Style, + llvm::StringRef StyleConfigDir = ""); + + /// \brief Write all TranslationUnitReplacements stored in \c Replacements + /// to disk. + /// + /// \pre Destination directory must have been previously set by calling + /// setDestiantionDir() or useTempDestinationDir(). + /// \pre Destination dir must exist. + /// + /// \param[in] Replacements Container of replacements to serialize. + /// + /// \returns \li true if all replacements were serialized successfully to + /// disk. + /// \li false otherwise. + bool serializeReplacements(const TUReplacementsMap &Replacements); + + /// \brief Invoke clang-apply-replacements to apply all serialized + /// replacements stored in the destination directory. + /// + /// \pre Destination directory must have been previously set by calling + /// setDestiantionDir() or useTempDestinationDir(). + /// + /// \returns \li true if clang-apply-replacements was successfully launched + /// and successfully completed. + /// \li false otherwise. + bool applyReplacements(); + + /// \brief Generate a unique filename to store the replacements. + /// + /// Generates a unique filename in \c DestinationDir. The filename is generated + /// following this pattern: + /// + /// DestinationDir/Prefix_%%_%%_%%_%%_%%_%%.yaml + /// + /// where Prefix := llvm::sys::path::filename(MainSourceFile) and all '%' will + /// be replaced by a randomly chosen hex digit. + /// + /// \param[in] DestinationDir Directory the unique file should be placed in. + /// \param[in] MainSourceFile Full path to the source file. + /// \param[out] Result The resulting unique filename. + /// \param[out] Error If an error occurs a description of that error is + /// placed in this string. + /// + /// \returns \li true on success + /// \li false if a unique file name could not be created. + static bool generateReplacementsFileName(llvm::StringRef DestinationDir, + llvm::StringRef MainSourceFile, + llvm::SmallVectorImpl &Result, + llvm::SmallVectorImpl &Error); + + /// \brief Helper to create a temporary directory name. + /// + /// \param[out] Resulting name is placed here. + static std::string generateTempDir(); + +private: + + std::string CARPath; + std::string DestinationDir; + bool DoFormat; + std::string FormatStyle; + std::string StyleConfigDir; +}; + +#endif // CLANG_MODERNIZE_REPLACEMENTHANDLING_H diff --git a/clang-tools-extra/clang-modernize/Core/SyntaxCheck.cpp b/clang-tools-extra/clang-modernize/Core/SyntaxCheck.cpp deleted file mode 100644 index 42900e7d5405..000000000000 --- a/clang-tools-extra/clang-modernize/Core/SyntaxCheck.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===-- Core/SyntaxCheck.cpp ----------------------------------------------===// -// -// 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 exposes functionaliy for doing a syntax-only check on -/// files with overridden contents. -/// -//===----------------------------------------------------------------------===// - -#include "Core/SyntaxCheck.h" -#include "Core/FileOverrides.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/Tooling.h" - -using namespace clang; -using namespace tooling; - -class SyntaxCheck : public SyntaxOnlyAction { -public: - SyntaxCheck(const FileOverrides &Overrides) : Overrides(Overrides) {} - - virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) { - if (!SyntaxOnlyAction::BeginSourceFileAction(CI, Filename)) - return false; - - Overrides.applyOverrides(CI.getSourceManager()); - - return true; - } - -private: - const FileOverrides &Overrides; -}; - -class SyntaxCheckFactory : public FrontendActionFactory { -public: - SyntaxCheckFactory(const FileOverrides &Overrides) - : Overrides(Overrides) {} - - virtual FrontendAction *create() { return new SyntaxCheck(Overrides); } - -private: - const FileOverrides &Overrides; -}; - -class SyntaxArgumentsAdjuster : public ArgumentsAdjuster { - CommandLineArguments Adjust(const CommandLineArguments &Args) { - CommandLineArguments AdjustedArgs = Args; - AdjustedArgs.push_back("-fsyntax-only"); - AdjustedArgs.push_back("-std=c++11"); - return AdjustedArgs; - } -}; - -bool doSyntaxCheck(const CompilationDatabase &Database, - const std::vector &SourcePaths, - const FileOverrides &Overrides) { - ClangTool SyntaxTool(Database, SourcePaths); - - // Ensure C++11 support is enabled. - // FIXME: This isn't necessary anymore since the Modernizer requires C++11 - // to be enabled in the CompilationDatabase. Remove later. - SyntaxTool.setArgumentsAdjuster(new SyntaxArgumentsAdjuster); - - return SyntaxTool.run(new SyntaxCheckFactory(Overrides)) == 0; -} diff --git a/clang-tools-extra/clang-modernize/Core/SyntaxCheck.h b/clang-tools-extra/clang-modernize/Core/SyntaxCheck.h deleted file mode 100644 index 508727616b4b..000000000000 --- a/clang-tools-extra/clang-modernize/Core/SyntaxCheck.h +++ /dev/null @@ -1,38 +0,0 @@ -//===-- Core/SyntaxCheck.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 exposes functionaliy for doing a syntax-only check on -/// files with overridden contents. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_SYNTAX_CHECK_H -#define CLANG_MODERNIZE_SYNTAX_CHECK_H - -#include -#include - -// Forward Declarations -namespace clang { -namespace tooling { -class CompilationDatabase; -} // namespace tooling -} // namespace clang - -class FileOverrides; - -/// \brief Perform a syntax-only check over all files in \c SourcePaths using -/// options provided by \c Database using file contents from \c Overrides if -/// available. -extern bool doSyntaxCheck(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths, - const FileOverrides &Overrides); - -#endif // CLANG_MODERNIZE_SYNTAX_CHECK_H diff --git a/clang-tools-extra/clang-modernize/Core/Transform.cpp b/clang-tools-extra/clang-modernize/Core/Transform.cpp index a61f101ddc20..1d4eb766b45e 100644 --- a/clang-tools-extra/clang-modernize/Core/Transform.cpp +++ b/clang-tools-extra/clang-modernize/Core/Transform.cpp @@ -14,7 +14,6 @@ //===----------------------------------------------------------------------===// #include "Core/Transform.h" -#include "Core/FileOverrides.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" @@ -76,7 +75,7 @@ private: } // namespace Transform::Transform(llvm::StringRef Name, const TransformOptions &Options) - : Name(Name), GlobalOptions(Options), Overrides(0) { + : Name(Name), GlobalOptions(Options) { Reset(); } @@ -95,9 +94,6 @@ 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; if (Options().EnableTiming) { diff --git a/clang-tools-extra/clang-modernize/Core/Transform.h b/clang-tools-extra/clang-modernize/Core/Transform.h index e74c77f73e60..6265df413251 100644 --- a/clang-tools-extra/clang-modernize/Core/Transform.h +++ b/clang-tools-extra/clang-modernize/Core/Transform.h @@ -50,9 +50,6 @@ class MatchFinder; } // namespace ast_matchers } // namespace clang -class FileOverrides; - - // \brief Maps main source file names to a TranslationUnitReplacements // structure storing replacements for that translation unit. typedef llvm::StringMap @@ -95,13 +92,13 @@ public: /// \brief Apply a transform to all files listed in \p SourcePaths. /// - /// \p Database must contain information for how to compile all files in \p - /// SourcePaths. \p InputStates contains the file contents of files in \p - /// 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, - const clang::tooling::CompilationDatabase &Database, + /// \param[in] Database Contains information for how to compile all files in + /// \p SourcePaths. + /// \param[in] SourcePaths list of sources to transform. + /// + /// \returns \li 0 if successful + /// \li 1 otherwise + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) = 0; /// \brief Query if changes were made during the last call to apply(). @@ -207,15 +204,6 @@ protected: /// created with. const TransformOptions &Options() { return GlobalOptions; } - /// \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) { - this->Overrides = &Overrides; - } - /// \brief Subclasses must call this function to create a /// FrontendActionFactory to pass to ClangTool. /// @@ -227,7 +215,6 @@ protected: private: const std::string Name; const TransformOptions &GlobalOptions; - const FileOverrides *Overrides; TUReplacementsMap Replacements; std::string CurrentSource; TimingVec Timings; diff --git a/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.cpp b/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.cpp index e41d758c50ba..bfd8007f9381 100644 --- a/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.cpp +++ b/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.cpp @@ -24,8 +24,7 @@ using clang::ast_matchers::MatchFinder; using namespace clang::tooling; using namespace clang; -int LoopConvertTransform::apply(const FileOverrides &InputStates, - const CompilationDatabase &Database, +int LoopConvertTransform::apply(const CompilationDatabase &Database, const std::vector &SourcePaths) { ClangTool LoopTool(Database, SourcePaths); @@ -49,8 +48,6 @@ int LoopConvertTransform::apply(const FileOverrides &InputStates, LFK_PseudoArray, /*Owner=*/ *this); Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer); - setOverrides(InputStates); - if (int result = LoopTool.run(createActionFactory(Finder))) { llvm::errs() << "Error encountered during translation.\n"; return result; diff --git a/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.h b/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.h index 744527954487..7aa3110544cf 100644 --- a/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.h +++ b/clang-tools-extra/clang-modernize/LoopConvert/LoopConvert.h @@ -31,8 +31,7 @@ public: : Transform("LoopConvert", Options) {} /// \see Transform::run(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) LLVM_OVERRIDE; virtual bool handleBeginSource(clang::CompilerInstance &CI, diff --git a/clang-tools-extra/clang-modernize/PassByValue/PassByValue.cpp b/clang-tools-extra/clang-modernize/PassByValue/PassByValue.cpp index fbd641233aff..eb4a92470e4a 100644 --- a/clang-tools-extra/clang-modernize/PassByValue/PassByValue.cpp +++ b/clang-tools-extra/clang-modernize/PassByValue/PassByValue.cpp @@ -21,8 +21,7 @@ using namespace clang; using namespace clang::tooling; using namespace clang::ast_matchers; -int PassByValueTransform::apply(const FileOverrides &InputStates, - const tooling::CompilationDatabase &Database, +int PassByValueTransform::apply(const tooling::CompilationDatabase &Database, const std::vector &SourcePaths) { ClangTool Tool(Database, SourcePaths); unsigned AcceptedChanges = 0; @@ -36,8 +35,6 @@ int PassByValueTransform::apply(const FileOverrides &InputStates, // make the replacer available to handleBeginSource() this->Replacer = &Replacer; - setOverrides(InputStates); - if (Tool.run(createActionFactory(Finder))) { llvm::errs() << "Error encountered during translation.\n"; return 1; diff --git a/clang-tools-extra/clang-modernize/PassByValue/PassByValue.h b/clang-tools-extra/clang-modernize/PassByValue/PassByValue.h index 62a5c425bd1b..e604459f0376 100644 --- a/clang-tools-extra/clang-modernize/PassByValue/PassByValue.h +++ b/clang-tools-extra/clang-modernize/PassByValue/PassByValue.h @@ -58,8 +58,7 @@ public: : Transform("PassByValue", Options), Replacer(0) {} /// \see Transform::apply(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) LLVM_OVERRIDE; private: diff --git a/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.cpp b/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.cpp index fae7970b4162..63b033bc913c 100644 --- a/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.cpp +++ b/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.cpp @@ -22,8 +22,7 @@ using namespace clang::tooling; using namespace clang::ast_matchers; int -ReplaceAutoPtrTransform::apply(const FileOverrides &InputStates, - const CompilationDatabase &Database, +ReplaceAutoPtrTransform::apply(const CompilationDatabase &Database, const std::vector &SourcePaths) { ClangTool Tool(Database, SourcePaths); unsigned AcceptedChanges = 0; @@ -35,8 +34,6 @@ ReplaceAutoPtrTransform::apply(const FileOverrides &InputStates, Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer); Finder.addMatcher(makeTransferOwnershipExprMatcher(), &Fixer); - setOverrides(InputStates); - if (Tool.run(createActionFactory(Finder))) { llvm::errs() << "Error encountered during translation.\n"; return 1; diff --git a/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.h b/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.h index ced677069322..a65e4fa28ecd 100644 --- a/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.h +++ b/clang-tools-extra/clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.h @@ -47,8 +47,7 @@ public: : Transform("ReplaceAutoPtr", Options) {} /// \see Transform::run(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) LLVM_OVERRIDE; }; diff --git a/clang-tools-extra/clang-modernize/UseAuto/UseAuto.cpp b/clang-tools-extra/clang-modernize/UseAuto/UseAuto.cpp index 72f5ae077f25..ff622b25a864 100644 --- a/clang-tools-extra/clang-modernize/UseAuto/UseAuto.cpp +++ b/clang-tools-extra/clang-modernize/UseAuto/UseAuto.cpp @@ -20,8 +20,7 @@ using clang::ast_matchers::MatchFinder; using namespace clang; using namespace clang::tooling; -int UseAutoTransform::apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, +int UseAutoTransform::apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) { ClangTool UseAutoTool(Database, SourcePaths); @@ -37,8 +36,6 @@ int UseAutoTransform::apply(const FileOverrides &InputStates, Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators); Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew); - setOverrides(InputStates); - if (int Result = UseAutoTool.run(createActionFactory(Finder))) { llvm::errs() << "Error encountered during translation.\n"; return Result; diff --git a/clang-tools-extra/clang-modernize/UseAuto/UseAuto.h b/clang-tools-extra/clang-modernize/UseAuto/UseAuto.h index 2293fd71f192..3c892a026cb9 100644 --- a/clang-tools-extra/clang-modernize/UseAuto/UseAuto.h +++ b/clang-tools-extra/clang-modernize/UseAuto/UseAuto.h @@ -34,8 +34,7 @@ public: : Transform("UseAuto", Options) {} /// \see Transform::run(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) LLVM_OVERRIDE; }; diff --git a/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.cpp b/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.cpp index e07ee6682eef..cca739292522 100644 --- a/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.cpp +++ b/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.cpp @@ -24,8 +24,7 @@ using clang::ast_matchers::MatchFinder; using namespace clang::tooling; using namespace clang; -int UseNullptrTransform::apply(const FileOverrides &InputStates, - const CompilationDatabase &Database, +int UseNullptrTransform::apply(const CompilationDatabase &Database, const std::vector &SourcePaths) { ClangTool UseNullptrTool(Database, SourcePaths); @@ -36,8 +35,6 @@ int UseNullptrTransform::apply(const FileOverrides &InputStates, Finder.addMatcher(makeCastSequenceMatcher(), &Fixer); - setOverrides(InputStates); - if (int result = UseNullptrTool.run(createActionFactory(Finder))) { llvm::errs() << "Error encountered during translation.\n"; return result; diff --git a/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.h b/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.h index dd93a1d7ed69..c3d86697c7d0 100644 --- a/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.h +++ b/clang-tools-extra/clang-modernize/UseNullptr/UseNullptr.h @@ -28,8 +28,7 @@ public: : Transform("UseNullptr", Options) {} /// \see Transform::run(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, + virtual int apply(const clang::tooling::CompilationDatabase &Database, const std::vector &SourcePaths) LLVM_OVERRIDE; }; diff --git a/clang-tools-extra/clang-modernize/tool/CMakeLists.txt b/clang-tools-extra/clang-modernize/tool/CMakeLists.txt index b28de70966a5..e5b8ecef5584 100644 --- a/clang-tools-extra/clang-modernize/tool/CMakeLists.txt +++ b/clang-tools-extra/clang-modernize/tool/CMakeLists.txt @@ -34,7 +34,6 @@ add_dependencies(clang-modernize ) target_link_libraries(clang-modernize - clangApplyReplacements modernizeCore ) diff --git a/clang-tools-extra/clang-modernize/tool/ClangModernize.cpp b/clang-tools-extra/clang-modernize/tool/ClangModernize.cpp index a824b0902595..8f643b9c7cb9 100644 --- a/clang-tools-extra/clang-modernize/tool/ClangModernize.cpp +++ b/clang-tools-extra/clang-modernize/tool/ClangModernize.cpp @@ -15,23 +15,20 @@ /// //===----------------------------------------------------------------------===// -#include "Core/FileOverrides.h" #include "Core/PerfSupport.h" -#include "Core/SyntaxCheck.h" +#include "Core/ReplacementHandling.h" #include "Core/Transform.h" #include "Core/Transforms.h" -#include "Core/Reformatting.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/SourceManager.h" +#include "clang/Format/Format.h" #include "clang/Frontend/FrontendActions.h" -#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" -#include "clang-apply-replacements/Tooling/ApplyReplacements.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" namespace cl = llvm::cl; @@ -81,13 +78,29 @@ static cl::opt FinalSyntaxCheck( cl::desc("Check for correct syntax after applying transformations"), cl::init(false)); -static cl::opt FormatStyleOpt( - "format-style", - cl::desc("Coding style to use on the replacements, either a builtin style\n" - "or a YAML config file (see: clang-format -dump-config).\n" - "Currently supports 4 builtins style:\n" - " LLVM, Google, Chromium, Mozilla.\n"), - cl::value_desc("string")); +static cl::OptionCategory FormattingCategory("Formatting Options"); + +static cl::opt DoFormat( + "format", + cl::desc("Enable formatting of code changed by applying replacements.\n" + "Use -style to choose formatting style.\n"), + cl::cat(FormattingCategory)); + +static cl::opt +FormatStyleOpt("style", cl::desc(format::StyleOptionHelpDescription), + cl::init("LLVM"), cl::cat(FormattingCategory)); + +// FIXME: Consider making the default behaviour for finding a style +// configuration file to start the search anew for every file being changed to +// handle situations where the style is different for different parts of a +// project. + +static cl::opt FormatStyleConfig( + "style-config", + cl::desc("Path to a directory containing a .clang-format file\n" + "describing a formatting style to use for formatting\n" + "code when -style=file.\n"), + cl::init(""), cl::cat(FormattingCategory)); static cl::opt SummaryMode("summary", cl::desc("Print transform summary"), @@ -98,29 +111,46 @@ static cl::opt TimingDirectoryName( "directory. Default: ./migrate_perf"), cl::ValueOptional, cl::value_desc("directory name")); +static cl::OptionCategory IncludeExcludeCategory("Inclusion/Exclusion Options"); + static cl::opt IncludePaths("include", cl::desc("Comma seperated list of paths to consider to be " - "transformed")); + "transformed"), + cl::cat(IncludeExcludeCategory)); + static cl::opt -ExcludePaths("exclude", - cl::desc("Comma seperated list of paths that can not " - "be transformed")); +ExcludePaths("exclude", cl::desc("Comma seperated list of paths that can not " + "be transformed"), + cl::cat(IncludeExcludeCategory)); + static cl::opt IncludeFromFile("include-from", cl::value_desc("filename"), cl::desc("File containing a list of paths to consider to " - "be transformed")); + "be transformed"), + cl::cat(IncludeExcludeCategory)); + static cl::opt ExcludeFromFile("exclude-from", cl::value_desc("filename"), cl::desc("File containing a list of paths that can not be " - "transforms")); + "transforms"), + cl::cat(IncludeExcludeCategory)); + +static cl::OptionCategory SerializeCategory("Serialization Options"); static cl::opt -SerializeReplacements("serialize-replacements", - cl::Hidden, - cl::desc("Serialize translation unit replacements to " - "disk instead of changing files."), - cl::init(false)); +SerializeOnly("serialize-replacements", + cl::desc("Serialize translation unit replacements to " + "disk instead of changing files."), + cl::init(false), + cl::cat(SerializeCategory)); + +static cl::opt +SerializeLocation("serialize-dir", + cl::desc("Path to an existing directory in which to write\n" + "serialized replacements. Default behaviour is to\n" + "write to a temporary directory.\n"), + cl::cat(SerializeCategory)); cl::opt SupportedCompilers( "for-compilers", cl::value_desc("string"), @@ -184,102 +214,6 @@ static CompilerVersions handleSupportedCompilers(const char *ProgName, return RequiredVersions; } -/// \brief Creates the Reformatter if the format style option is provided, -/// return a null pointer otherwise. -/// -/// \param ProgName The name of the program, \c argv[0], used to print errors. -/// \param Error If the \c -format-style is provided but with wrong parameters -/// this is parameter is set to \c true, left untouched otherwise. An error -/// message is printed with an explanation. -static Reformatter *handleFormatStyle(const char *ProgName, bool &Error) { - if (FormatStyleOpt.getNumOccurrences() > 0) { - format::FormatStyle Style; - if (!format::getPredefinedStyle(FormatStyleOpt, &Style)) { - llvm::StringRef ConfigFilePath = FormatStyleOpt; - llvm::OwningPtr Text; - llvm::error_code ec; - - ec = llvm::MemoryBuffer::getFile(ConfigFilePath, Text); - if (!ec) - ec = parseConfiguration(Text->getBuffer(), &Style); - - if (ec) { - llvm::errs() << ProgName << ": invalid format style " << FormatStyleOpt - << ": " << ec.message() << "\n"; - Error = true; - return 0; - } - } - - // force mode to C++11 - Style.Standard = clang::format::FormatStyle::LS_Cpp11; - return new Reformatter(Style); - } - 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. -void reformat(Reformatter &ChangesReformatter, 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; - } - - Rewriter DestRewriter(SM, LangOptions()); - if (!replace::applyReplacements(GroupedReplacements, DestRewriter)) { - llvm::errs() << "Warning: Failed to apply reformatting conflicts!\n"; - return; - } - - Overrides.updateState(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(*I); - } - return !Errors; -} - CompilationDatabase *autoDetectCompilations(std::string &ErrorMessage) { // Auto-detect a compilation database from BuildPath. if (BuildPath.getNumOccurrences() > 0) @@ -332,6 +266,7 @@ static bool isFileExplicitlyExcludedPredicate(llvm::StringRef FilePath) { int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); Transforms TransformManager; + ReplacementHandling ReplacementHandler; TransformManager.registerTransforms(); @@ -386,11 +321,7 @@ int main(int argc, const char **argv) { // Enable timming. GlobalOptions.EnableTiming = TimingDirectoryName.getNumOccurrences() > 0; - // Check the reformatting style option bool CmdSwitchError = false; - llvm::OwningPtr ChangesReformatter( - handleFormatStyle(argv[0], CmdSwitchError)); - CompilerVersions RequiredVersions = handleSupportedCompilers(argv[0], CmdSwitchError); if (CmdSwitchError) @@ -398,15 +329,6 @@ int main(int argc, const char **argv) { TransformManager.createSelectedTransforms(GlobalOptions, RequiredVersions); - llvm::IntrusiveRefCntPtr DiagOpts( - new DiagnosticOptions()); - DiagnosticsEngine Diagnostics( - llvm::IntrusiveRefCntPtr(new DiagnosticIDs()), - DiagOpts.getPtr()); - - // FIXME: Make this DiagnosticsEngine available to all Transforms probably via - // GlobalOptions. - if (TransformManager.begin() == TransformManager.end()) { if (SupportedCompilers.empty()) llvm::errs() << llvm::sys::path::filename(argv[0]) @@ -417,28 +339,52 @@ int main(int argc, const char **argv) { return 1; } - // If SerializeReplacements is requested, then change reformatting must be - // turned off and only one transform should be requested. Reformatting is - // basically another transform so even if there's only one other transform, - // the reformatting pass would make two. - if (SerializeReplacements && + llvm::IntrusiveRefCntPtr DiagOpts( + new DiagnosticOptions()); + DiagnosticsEngine Diagnostics( + llvm::IntrusiveRefCntPtr(new DiagnosticIDs()), + DiagOpts.getPtr()); + + // FIXME: Make this DiagnosticsEngine available to all Transforms probably via + // GlobalOptions. + + // If SerializeReplacements is requested, then code reformatting must be + // turned off and only one transform should be requested. + if (SerializeOnly && (std::distance(TransformManager.begin(), TransformManager.end()) > 1 || - ChangesReformatter)) { + DoFormat)) { llvm::errs() << "Serialization of replacements requested for multiple " "transforms.\nChanges from only one transform can be " "serialized.\n"; return 1; } + // If we're asked to apply changes to files on disk, need to locate + // clang-apply-replacements. + if (!SerializeOnly) { + if (!ReplacementHandler.findClangApplyReplacements(argv[0])) { + llvm::errs() << "Could not find clang-apply-replacements\n"; + return 1; + } + + if (DoFormat) + ReplacementHandler.enableFormatting(FormatStyleOpt, FormatStyleConfig); + } + + StringRef TempDestinationDir; + if (SerializeLocation.getNumOccurrences() > 0) + ReplacementHandler.setDestinationDir(SerializeLocation); + else + TempDestinationDir = ReplacementHandler.useTempDestinationDir(); + SourcePerfData PerfData; - FileOverrides FileStates; for (Transforms::const_iterator I = TransformManager.begin(), E = TransformManager.end(); I != E; ++I) { Transform *T = *I; - if (T->apply(FileStates, *Compilations, Sources) != 0) { + if (T->apply(*Compilations, Sources) != 0) { // FIXME: Improve ClangTool to not abort if just one file fails. return 1; } @@ -456,65 +402,25 @@ int main(int argc, const char **argv) { 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 - // replacements. Otherwise reformat changes if reformatting is enabled. - if (!SerializeReplacements) { - if (ChangesReformatter) - reformat(*ChangesReformatter, FileStates, Diagnostics); - FileStates.writeToDisk(Diagnostics); - } - - if (FinalSyntaxCheck) - if (!doSyntaxCheck(*Compilations, Sources, FileStates)) + if (!ReplacementHandler.serializeReplacements(T->getAllReplacements())) return 1; + if (!SerializeOnly) + if (!ReplacementHandler.applyReplacements()) + return 1; + } + + // Let the user know which temporary directory the replacements got written + // to. + if (SerializeOnly && !TempDestinationDir.empty()) + llvm::errs() << "Replacements serialized to: " << TempDestinationDir << "\n"; + + if (FinalSyntaxCheck) { + ClangTool SyntaxTool(*Compilations, SourcePaths); + if (SyntaxTool.run(newFrontendActionFactory()) != 0) + return 1; + } + // Report execution times. if (GlobalOptions.EnableTiming && !PerfData.empty()) { std::string DirectoryName = TimingDirectoryName; diff --git a/clang-tools-extra/clang-modernize/tool/Makefile b/clang-tools-extra/clang-modernize/tool/Makefile index 77f7e6380a32..5f50d2634eff 100644 --- a/clang-tools-extra/clang-modernize/tool/Makefile +++ b/clang-tools-extra/clang-modernize/tool/Makefile @@ -36,14 +36,14 @@ SOURCES += $(addprefix ../ReplaceAutoPtr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/.. BUILT_SOURCES += $(ObjDir)/../ReplaceAutoPtr/.objdir LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc mcparser option -USEDLIBS = modernizeCore.a clangFormat.a clangApplyReplacements.a clangTooling.a clangFrontend.a \ +USEDLIBS = modernizeCore.a clangFormat.a clangTooling.a clangFrontend.a \ clangSerialization.a clangDriver.a clangRewriteFrontend.a \ clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \ clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile -CPP.Flags += -I$(PROJ_SRC_DIR)/.. -I$(PROJ_SRC_DIR)/../../clang-apply-replacements/include +CPP.Flags += -I$(PROJ_SRC_DIR)/.. # 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 diff --git a/clang-tools-extra/test/clang-modernize/Core/Inputs/.clang-format b/clang-tools-extra/test/clang-modernize/Core/Inputs/.clang-format new file mode 100644 index 000000000000..d210decfa4f1 --- /dev/null +++ b/clang-tools-extra/test/clang-modernize/Core/Inputs/.clang-format @@ -0,0 +1,43 @@ +--- +# BasedOnStyle: Google +AccessModifierOffset: -1 +ConstructorInitializerIndentWidth: 4 +AlignEscapedNewlinesLeft: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakTemplateDeclarations: true +AlwaysBreakBeforeMultilineStrings: true +BreakBeforeBinaryOperators: false +BreakConstructorInitializersBeforeComma: false +BinPackParameters: true +ColumnLimit: 80 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +DerivePointerBinding: true +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: true +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceBeforeProtocolList: false +PenaltyBreakComment: 60 +PenaltyBreakString: 1000 +PenaltyBreakFirstLessLess: 120 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerBindsToType: true +SpacesBeforeTrailingComments: 2 +Cpp11BracedListStyle: true +Standard: Auto +IndentWidth: 2 +TabWidth: 8 +UseTab: Never +BreakBeforeBraces: Attach +IndentFunctionDeclarationAfterType: true +SpacesInParentheses: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpaceAfterControlStatementKeyword: true +SpaceBeforeAssignmentOperators: true +... + diff --git a/clang-tools-extra/test/clang-modernize/Core/NoReformattingNeeded.cpp b/clang-tools-extra/test/clang-modernize/Core/NoReformattingNeeded.cpp deleted file mode 100644 index e58fdb24068b..000000000000 --- a/clang-tools-extra/test/clang-modernize/Core/NoReformattingNeeded.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -format-style=LLVM -use-auto %t.cpp -- -std=c++11 -// RUN: FileCheck --strict-whitespace -input-file=%t.cpp %s - -class C {}; - -void f() { // - C *a = new C(); - // CHECK: {{^\ \ auto\ a\ \=\ new\ C\(\);}} -} diff --git a/clang-tools-extra/test/clang-modernize/Core/Reformatting.cpp b/clang-tools-extra/test/clang-modernize/Core/Reformatting.cpp index 129871809d80..338a17889d1a 100644 --- a/clang-tools-extra/test/clang-modernize/Core/Reformatting.cpp +++ b/clang-tools-extra/test/clang-modernize/Core/Reformatting.cpp @@ -1,11 +1,37 @@ // RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: not clang-modernize -format-style=non_existent_file.yaml -use-auto %t.cpp -- -std=c++11 -// RUN: touch %T/non_format_config.yaml -// RUN: not clang-modernize -format-style=%T/non_format_config.yaml -use-auto %t.cpp -- -std=c++11 -// RUN: clang-modernize -format-style=LLVM -use-auto %t.cpp -- -std=c++11 +// RUN: clang-modernize -format -use-auto %t.cpp // RUN: FileCheck --strict-whitespace -input-file=%t.cpp %s -class MyType012345678901234567890123456789 {}; +// Ensure that -style is forwarded to clang-apply-replacements by using a style +// other than LLVM and ensuring the result is styled as requested. +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-modernize -format -style=Google -use-nullptr %t.cpp +// RUN: FileCheck --check-prefix=Google --strict-whitespace -input-file=%t.cpp %s + +// Ensure -style-config is forwarded to clang-apply-replacements. The .clang-format +// in %S/Inputs is a dump of the Google style so the same test can be used. +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-modernize -format -style=file -style-config=%S/Inputs -use-nullptr %t.cpp +// RUN: FileCheck --check-prefix=Google --strict-whitespace -input-file=%t.cpp %s + +class MyType012345678901234567890123456789 { +public: + MyType012345678901234567890123456789() + : iiiiiiiiiiii(0), jjjjjjjjjjjj(0), kkkkkkkkkkkk(0), mmmmmmmmmmmm(0), + nnnnnnnnnnnn(0) {} + // Google: iiiiiiiiiiii(nullptr), + // Google-NEXT: jjjjjjjjjjjj(nullptr), + // Google-NEXT: kkkkkkkkkkkk(nullptr), + // Google-NEXT: mmmmmmmmmmmm(nullptr), + // Google-NEXT: nnnnnnnnnnnn(nullptr) {} + +private: + int *iiiiiiiiiiii; + int *jjjjjjjjjjjj; + int *kkkkkkkkkkkk; + int *mmmmmmmmmmmm; + int *nnnnnnnnnnnn; +}; int f() { MyType012345678901234567890123456789 *a = @@ -13,4 +39,6 @@ int f() { // CHECK: {{^\ \ auto\ a\ \=\ new\ MyType012345678901234567890123456789\(\);}} delete a; + + return 0; } diff --git a/clang-tools-extra/test/clang-modernize/HeaderReplacements/main.cpp b/clang-tools-extra/test/clang-modernize/HeaderReplacements/main.cpp index ce06794dfb02..c25dba7268a2 100644 --- a/clang-tools-extra/test/clang-modernize/HeaderReplacements/main.cpp +++ b/clang-tools-extra/test/clang-modernize/HeaderReplacements/main.cpp @@ -7,7 +7,7 @@ // RUN: rm -rf %T/SerializeTest // RUN: mkdir -p %T/SerializeTest // RUN: cp %S/main.cpp %S/common.cpp %S/common.h %T/SerializeTest -// RUN: clang-modernize -loop-convert -serialize-replacements -include=%T/SerializeTest %T/SerializeTest/main.cpp %T/SerializeTest/common.cpp -- +// RUN: clang-modernize -loop-convert -serialize-replacements -serialize-dir=%T/SerializeTest -include=%T/SerializeTest %T/SerializeTest/main.cpp %T/SerializeTest/common.cpp -- // Check that only 1 file is generated per translation unit // RUN: ls -1 %T/SerializeTest | FileCheck %s --check-prefix=MAIN_CPP // RUN: ls -1 %T/SerializeTest | FileCheck %s --check-prefix=COMMON_CPP diff --git a/clang-tools-extra/unittests/clang-modernize/CMakeLists.txt b/clang-tools-extra/unittests/clang-modernize/CMakeLists.txt index 3022a6105497..80fd4a74bd07 100644 --- a/clang-tools-extra/unittests/clang-modernize/CMakeLists.txt +++ b/clang-tools-extra/unittests/clang-modernize/CMakeLists.txt @@ -15,8 +15,6 @@ include_directories( ) add_extra_unittest(ClangModernizeTests - FileOverridesTest.cpp - ReformattingTest.cpp IncludeExcludeTest.cpp PerfSupportTest.cpp TransformTest.cpp diff --git a/clang-tools-extra/unittests/clang-modernize/FileOverridesTest.cpp b/clang-tools-extra/unittests/clang-modernize/FileOverridesTest.cpp deleted file mode 100644 index 94776bc2c107..000000000000 --- a/clang-tools-extra/unittests/clang-modernize/FileOverridesTest.cpp +++ /dev/null @@ -1,187 +0,0 @@ -//===- clang-modernize/FileOverridesTest.cpp - File overrides unit tests --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Core/FileOverrides.h" -#include "Core/Refactoring.h" -#include "gtest/gtest.h" -#include "common/VirtualFileHelper.h" -#include "clang/Rewrite/Core/Rewriter.h" - -using namespace clang; -using namespace clang::tooling; - -static Replacement makeReplacement(unsigned Offset, unsigned Length, - unsigned ReplacementLength, - llvm::StringRef FilePath) { - return Replacement(FilePath, Offset, Length, - std::string(ReplacementLength, '~')); -} - -// generate a set of replacements containing one element -static ReplacementsVec makeReplacements(unsigned Offset, unsigned Length, - unsigned ReplacementLength, - llvm::StringRef FilePath = "~") { - ReplacementsVec Replaces; - Replaces.push_back( - makeReplacement(Offset, Length, ReplacementLength, FilePath)); - return Replaces; -} - -static bool equalRanges(Range A, Range B) { - return A.getOffset() == B.getOffset() && A.getLength() == B.getLength(); -} - -TEST(ChangedRangesTest, adjustChangedRangesShrink) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(0, 0, 4)); - EXPECT_NE(Changes.begin(), Changes.end()); - EXPECT_TRUE(equalRanges(Range(0, 4), *Changes.begin())); - // create a replacement that cuts the end of the last insertion - Changes.adjustChangedRanges(makeReplacements(2, 4, 0)); - Range ExpectedChanges[] = { Range(0, 2) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesExtend) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(1, 0, 4)); - // cut the old one by a bigger one - Changes.adjustChangedRanges(makeReplacements(3, 4, 6)); - Range ExpectedChanges[] = { Range(1, 8) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesNoOverlap) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(0, 0, 4)); - Changes.adjustChangedRanges(makeReplacements(6, 0, 4)); - Range ExpectedChanges[] = { Range(0, 4), Range(6, 4) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesNullRange) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(0, 4, 0)); - Range ExpectedChanges[] = { Range(0, 0) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesExtendExisting) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(0, 0, 3)); - Changes.adjustChangedRanges(makeReplacements(2, 5, 8)); - Range ExpectedChanges[] = { Range(0, 10) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesSplit) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(0, 0, 3)); - Changes.adjustChangedRanges(makeReplacements(1, 1, 0)); - Range ExpectedChanges[] = { Range(0, 2) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesRangeContained) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(3, 0, 2)); - Changes.adjustChangedRanges(makeReplacements(1, 4, 5)); - Range ExpectedChanges[] = { Range(1, 5) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); -} - -TEST(ChangedRangesTest, adjustChangedRangesRangeResized) { - ChangedRanges Changes; - Changes.adjustChangedRanges(makeReplacements(2, 0, 5)); - // first make the range bigger - Changes.adjustChangedRanges(makeReplacements(4, 1, 3)); - Range ExpectedChanges[] = { Range(2, 7) }; - EXPECT_TRUE( - std::equal(Changes.begin(), Changes.end(), ExpectedChanges, equalRanges)); - // then smaller - Changes.adjustChangedRanges(makeReplacements(3, 3, 1)); - ExpectedChanges[0] = Range(2, 5); - EXPECT_TRUE( - 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()); -} diff --git a/clang-tools-extra/unittests/clang-modernize/PerfSupportTest.cpp b/clang-tools-extra/unittests/clang-modernize/PerfSupportTest.cpp index 9789a9571f16..71209a6e441c 100644 --- a/clang-tools-extra/unittests/clang-modernize/PerfSupportTest.cpp +++ b/clang-tools-extra/unittests/clang-modernize/PerfSupportTest.cpp @@ -18,8 +18,7 @@ public: TransformA(const TransformOptions &Options) : Transform("TransformA", Options) {} - virtual int apply(const FileOverrides &, - const tooling::CompilationDatabase &, + virtual int apply(const tooling::CompilationDatabase &, const std::vector &) { return 0; } @@ -34,8 +33,7 @@ public: TransformB(const TransformOptions &Options) : Transform("TransformB", Options) {} - virtual int apply(const FileOverrides &, - const tooling::CompilationDatabase &, + virtual int apply(const tooling::CompilationDatabase &, const std::vector &) { return 0; } diff --git a/clang-tools-extra/unittests/clang-modernize/ReformattingTest.cpp b/clang-tools-extra/unittests/clang-modernize/ReformattingTest.cpp deleted file mode 100644 index 1359129714c4..000000000000 --- a/clang-tools-extra/unittests/clang-modernize/ReformattingTest.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===- clang-modernize/ReformattingTest.cpp - Reformatting unit tests -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Core/Reformatting.h" -#include "Core/FileOverrides.h" -#include "Core/Refactoring.h" -#include "gtest/gtest.h" -#include "common/VirtualFileHelper.h" - -using namespace clang; -using namespace clang::tooling; - -namespace { -// convenience function to create a ChangedRanges containing one Range -ChangedRanges makeChangedRanges(unsigned Offset, unsigned Length) { - ChangedRanges Changes; - ReplacementsVec Replaces; - - Replaces.push_back(Replacement("", Offset, 0, std::string(Length, '~'))); - Changes.adjustChangedRanges(Replaces); - return Changes; -} -} // end anonymous namespace - -TEST(Reformatter, SingleReformat) { - VirtualFileHelper VFHelper; - llvm::StringRef FileName = ""; - VFHelper.mapFile(FileName, "int a;\n" - "int b;\n"); - - Reformatter ChangesReformatter(format::getLLVMStyle()); - ChangedRanges Changes = makeChangedRanges(0, 6); - tooling::ReplacementsVec Replaces; - ChangesReformatter.reformatSingleFile( - FileName, Changes, VFHelper.getNewSourceManager(), Replaces); - - // We expect the code above to reformatted like so: - // - // int a; - // int b; - // - // This test is slightly fragile since there's more than one Replacement that - // results in the above change. However, testing the result of applying the - // replacement is more trouble than it's worth in this context. - ASSERT_EQ(1u, Replaces.size()); - EXPECT_EQ(3u, Replaces[0].getOffset()); - EXPECT_EQ(2u, Replaces[0].getLength()); - EXPECT_EQ(" ", Replaces[0].getReplacementText()); -} diff --git a/clang-tools-extra/unittests/clang-modernize/TransformTest.cpp b/clang-tools-extra/unittests/clang-modernize/TransformTest.cpp index b69d27c70120..5e5093a27acf 100644 --- a/clang-tools-extra/unittests/clang-modernize/TransformTest.cpp +++ b/clang-tools-extra/unittests/clang-modernize/TransformTest.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "gtest/gtest.h" -#include "Core/FileOverrides.h" #include "Core/Transform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclGroup.h" @@ -26,8 +25,7 @@ public: DummyTransform(llvm::StringRef Name, const TransformOptions &Options) : Transform(Name, Options) {} - virtual int apply(const FileOverrides &, - const tooling::CompilationDatabase &, + virtual int apply(const tooling::CompilationDatabase &, const std::vector &) { return 0; } void setAcceptedChanges(unsigned Changes) { @@ -40,10 +38,6 @@ public: Transform::setDeferredChanges(Changes); } - void setOverrides(FileOverrides &Overrides) { - Transform::setOverrides(Overrides); - } - }; TEST(Transform, Interface) { @@ -159,11 +153,6 @@ TEST(Transform, Timings) { // handleEndSource() calls to it. CallbackForwarder Callbacks(T); - // Transform's handle* functions require FileOverrides to be set, even if - // there aren't any. - FileOverrides Overrides; - T.setOverrides(Overrides); - Tool.run(clang::tooling::newFrontendActionFactory(&Factory, &Callbacks)); EXPECT_TRUE(Factory.Called); diff --git a/clang-tools-extra/unittests/clang-modernize/UniqueHeaderNameTest.cpp b/clang-tools-extra/unittests/clang-modernize/UniqueHeaderNameTest.cpp index 9383ded4d98a..45e8cce6e4e7 100644 --- a/clang-tools-extra/unittests/clang-modernize/UniqueHeaderNameTest.cpp +++ b/clang-tools-extra/unittests/clang-modernize/UniqueHeaderNameTest.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "gtest/gtest.h" -#include "Core/FileOverrides.h" +#include "Core/ReplacementHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" @@ -28,10 +28,13 @@ TEST(UniqueHeaderName, testUniqueHeaderName) { append(SourceFile, "project/lib/feature.cpp"); native(SourceFile.str().str(), SourceFile); + llvm::SmallString<128> DestDir(TmpDir); + append(DestDir, "replacements"); + llvm::SmallString<128> FullActualPath; llvm::SmallString<128> Error; - bool Result = - generateReplacementsFileName(SourceFile, FullActualPath, Error); + bool Result = ReplacementHandling::generateReplacementsFileName( + DestDir, SourceFile, FullActualPath, Error); ASSERT_TRUE(Result); EXPECT_TRUE(Error.empty()); @@ -45,7 +48,7 @@ TEST(UniqueHeaderName, testUniqueHeaderName) { llvm::SmallString<128> ActualName = llvm::sys::path::filename(FullActualPath); - EXPECT_STREQ(ExpectedPath.c_str(), ActualPath.c_str()); + EXPECT_STREQ(DestDir.c_str(), ActualPath.c_str()); llvm::StringRef ExpectedName = "^feature.cpp_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_["