//===-- 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 using namespace llvm; using namespace llvm::sys; using namespace clang::tooling; bool ReplacementHandling::findClangApplyReplacements(const char *Argv0) { ErrorOr CARPathOrErr = findProgramByName("clang-apply-replacements"); if (!CARPathOrErr) return true; CARPath = *CARPathOrErr; 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::error_code EC; raw_fd_ostream ReplacementsFile(ReplacementsFileName, EC, fs::F_None); if (EC) { errs() << "Error opening file: " << EC.message() << "\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(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 &Result, SmallVectorImpl &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; }