This is a short-term fix for PR33650 aimed to get the modules build bots green again. Remove all the places where we use the LLVM_YAML_IS_(FLOW_)?SEQUENCE_VECTOR macros to try to locally specialize a global template for a global type. That's not how C++ works. Instead, we now centrally define how to format vectors of fundamental types and of string (std::string and StringRef). We use flow formatting for the former cases, since that's the obvious right thing to do; in the latter case, it's less clear what the right choice is, but flow formatting is really bad for some cases (due to very long strings), so we pick block formatting. (Many of the cases that were using flow formatting for strings are improved by this change.) Other than the flow -> block formatting change for some vectors of strings, this should result in no functionality change. Differential Revision: https://reviews.llvm.org/D34907 Corresponding LLVM change is r306878. llvm-svn: 306881
178 lines
6.5 KiB
C++
178 lines
6.5 KiB
C++
//===--- AtomicChange.cpp - AtomicChange implementation -----------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Tooling/Refactoring/AtomicChange.h"
|
|
#include "clang/Tooling/ReplacementsYaml.h"
|
|
#include "llvm/Support/YAMLTraits.h"
|
|
#include <string>
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
|
|
|
|
namespace {
|
|
/// \brief Helper to (de)serialize an AtomicChange since we don't have direct
|
|
/// access to its data members.
|
|
/// Data members of a normalized AtomicChange can be directly mapped from/to
|
|
/// YAML string.
|
|
struct NormalizedAtomicChange {
|
|
NormalizedAtomicChange() = default;
|
|
|
|
NormalizedAtomicChange(const llvm::yaml::IO &) {}
|
|
|
|
// This converts AtomicChange's internal implementation of the replacements
|
|
// set to a vector of replacements.
|
|
NormalizedAtomicChange(const llvm::yaml::IO &,
|
|
const clang::tooling::AtomicChange &E)
|
|
: Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()),
|
|
InsertedHeaders(E.getInsertedHeaders()),
|
|
RemovedHeaders(E.getRemovedHeaders()),
|
|
Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}
|
|
|
|
// This is not expected to be called but needed for template instantiation.
|
|
clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) {
|
|
llvm_unreachable("Do not convert YAML to AtomicChange directly with '>>'. "
|
|
"Use AtomicChange::convertFromYAML instead.");
|
|
}
|
|
std::string Key;
|
|
std::string FilePath;
|
|
std::string Error;
|
|
std::vector<std::string> InsertedHeaders;
|
|
std::vector<std::string> RemovedHeaders;
|
|
std::vector<clang::tooling::Replacement> Replaces;
|
|
};
|
|
} // anonymous namespace
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
|
|
/// \brief Specialized MappingTraits to describe how an AtomicChange is
|
|
/// (de)serialized.
|
|
template <> struct MappingTraits<NormalizedAtomicChange> {
|
|
static void mapping(IO &Io, NormalizedAtomicChange &Doc) {
|
|
Io.mapRequired("Key", Doc.Key);
|
|
Io.mapRequired("FilePath", Doc.FilePath);
|
|
Io.mapRequired("Error", Doc.Error);
|
|
Io.mapRequired("InsertedHeaders", Doc.InsertedHeaders);
|
|
Io.mapRequired("RemovedHeaders", Doc.RemovedHeaders);
|
|
Io.mapRequired("Replacements", Doc.Replaces);
|
|
}
|
|
};
|
|
|
|
/// \brief Specialized MappingTraits to describe how an AtomicChange is
|
|
/// (de)serialized.
|
|
template <> struct MappingTraits<clang::tooling::AtomicChange> {
|
|
static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
|
|
MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
|
|
Keys(Io, Doc);
|
|
Io.mapRequired("Key", Keys->Key);
|
|
Io.mapRequired("FilePath", Keys->FilePath);
|
|
Io.mapRequired("Error", Keys->Error);
|
|
Io.mapRequired("InsertedHeaders", Keys->InsertedHeaders);
|
|
Io.mapRequired("RemovedHeaders", Keys->RemovedHeaders);
|
|
Io.mapRequired("Replacements", Keys->Replaces);
|
|
}
|
|
};
|
|
|
|
} // end namespace yaml
|
|
} // end namespace llvm
|
|
|
|
namespace clang {
|
|
namespace tooling {
|
|
|
|
AtomicChange::AtomicChange(const SourceManager &SM,
|
|
SourceLocation KeyPosition) {
|
|
const FullSourceLoc FullKeyPosition(KeyPosition, SM);
|
|
std::pair<FileID, unsigned> FileIDAndOffset =
|
|
FullKeyPosition.getSpellingLoc().getDecomposedLoc();
|
|
const FileEntry *FE = SM.getFileEntryForID(FileIDAndOffset.first);
|
|
assert(FE && "Cannot create AtomicChange with invalid location.");
|
|
FilePath = FE->getName();
|
|
Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
|
|
}
|
|
|
|
AtomicChange::AtomicChange(std::string Key, std::string FilePath,
|
|
std::string Error,
|
|
std::vector<std::string> InsertedHeaders,
|
|
std::vector<std::string> RemovedHeaders,
|
|
clang::tooling::Replacements Replaces)
|
|
: Key(std::move(Key)), FilePath(std::move(FilePath)),
|
|
Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),
|
|
RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
|
|
}
|
|
|
|
std::string AtomicChange::toYAMLString() {
|
|
std::string YamlContent;
|
|
llvm::raw_string_ostream YamlContentStream(YamlContent);
|
|
|
|
llvm::yaml::Output YAML(YamlContentStream);
|
|
YAML << *this;
|
|
YamlContentStream.flush();
|
|
return YamlContent;
|
|
}
|
|
|
|
AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
|
|
NormalizedAtomicChange NE;
|
|
llvm::yaml::Input YAML(YAMLContent);
|
|
YAML >> NE;
|
|
AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
|
|
NE.RemovedHeaders, tooling::Replacements());
|
|
for (const auto &R : NE.Replaces) {
|
|
llvm::Error Err = E.Replaces.add(R);
|
|
if (Err)
|
|
llvm_unreachable(
|
|
"Failed to add replacement when Converting YAML to AtomicChange.");
|
|
llvm::consumeError(std::move(Err));
|
|
}
|
|
return E;
|
|
}
|
|
|
|
llvm::Error AtomicChange::replace(const SourceManager &SM,
|
|
const CharSourceRange &Range,
|
|
llvm::StringRef ReplacementText) {
|
|
return Replaces.add(Replacement(SM, Range, ReplacementText));
|
|
}
|
|
|
|
llvm::Error AtomicChange::replace(const SourceManager &SM, SourceLocation Loc,
|
|
unsigned Length, llvm::StringRef Text) {
|
|
return Replaces.add(Replacement(SM, Loc, Length, Text));
|
|
}
|
|
|
|
llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
|
|
llvm::StringRef Text, bool InsertAfter) {
|
|
if (Text.empty())
|
|
return llvm::Error::success();
|
|
Replacement R(SM, Loc, 0, Text);
|
|
llvm::Error Err = Replaces.add(R);
|
|
if (Err) {
|
|
return llvm::handleErrors(
|
|
std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {
|
|
if (RE.get() != replacement_error::insert_conflict)
|
|
return llvm::make_error<ReplacementError>(RE);
|
|
unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
|
|
if (!InsertAfter)
|
|
NewOffset -=
|
|
RE.getExistingReplacement()->getReplacementText().size();
|
|
Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
|
|
Replaces = Replaces.merge(Replacements(NewR));
|
|
return llvm::Error::success();
|
|
});
|
|
}
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
void AtomicChange::addHeader(llvm::StringRef Header) {
|
|
InsertedHeaders.push_back(Header);
|
|
}
|
|
|
|
void AtomicChange::removeHeader(llvm::StringRef Header) {
|
|
RemovedHeaders.push_back(Header);
|
|
}
|
|
|
|
} // end namespace tooling
|
|
} // end namespace clang
|