| //===-- 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 <system_error> |
| |
| 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; |
| std::string ClangModernizePath = fs::getMainExecutable(Argv0, &StaticSymbol); |
| SmallString<128> TestPath = path::parent_path(ClangModernizePath); |
| 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_None); |
| if (!ErrorInfo.empty()) { |
| errs() << "Error opening file: " << ErrorInfo << "\n"; |
| Errors = true; |
| continue; |
| } |
| yaml::Output YAML(ReplacementsFile); |
| YAML << const_cast<TranslationUnitReplacements &>(I->getValue()); |
| } |
| return !Errors; |
| } |
| |
| bool ReplacementHandling::applyReplacements() { |
| SmallVector<const char *, 8> 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(nullptr); |
| |
| std::string ErrorMsg; |
| bool ExecutionFailed = false; |
| int ReturnCode = ExecuteAndWait(CARPath.c_str(), Argv.data(), |
| /* env */ nullptr, /* redirects */ nullptr, |
| /* 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<char> &Result, SmallVectorImpl<char> &Error) { |
| |
| Error.clear(); |
| SmallString<128> Prefix = DestinationDir; |
| path::append(Prefix, path::filename(MainSourceFile)); |
| if (std::error_code EC = |
| fs::createUniqueFile(Prefix + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { |
| const std::string &Msg = EC.message(); |
| Error.append(Msg.begin(), Msg.end()); |
| return false; |
| } |
| |
| return true; |
| } |