llvm-project/clang-tools-extra/clang-modernize/Core/ReplacementHandling.cpp

156 lines
4.9 KiB
C++

//===-- 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;
}