11#include "llvm/Support/YAMLTraits.h"
21struct NormalizedAtomicChange {
22 NormalizedAtomicChange() =
default;
24 NormalizedAtomicChange(
const llvm::yaml::IO &) {}
28 NormalizedAtomicChange(
const llvm::yaml::IO &,
29 const clang::tooling::AtomicChange &E)
30 : Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()),
31 InsertedHeaders(E.getInsertedHeaders()),
32 RemovedHeaders(E.getRemovedHeaders()),
33 Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}
36 clang::tooling::AtomicChange denormalize(
const llvm::yaml::IO &) {
37 llvm_unreachable(
"Do not convert YAML to AtomicChange directly with '>>'. "
38 "Use AtomicChange::convertFromYAML instead.");
43 std::vector<std::string> InsertedHeaders;
44 std::vector<std::string> RemovedHeaders;
45 std::vector<clang::tooling::Replacement> Replaces;
54template <>
struct MappingTraits<NormalizedAtomicChange> {
55 static void mapping(IO &Io, NormalizedAtomicChange &Doc) {
56 Io.mapRequired(
"Key", Doc.Key);
57 Io.mapRequired(
"FilePath", Doc.FilePath);
58 Io.mapRequired(
"Error", Doc.Error);
59 Io.mapRequired(
"InsertedHeaders", Doc.InsertedHeaders);
60 Io.mapRequired(
"RemovedHeaders", Doc.RemovedHeaders);
61 Io.mapRequired(
"Replacements", Doc.Replaces);
67template <>
struct MappingTraits<
clang::tooling::AtomicChange> {
69 MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
71 Io.mapRequired(
"Key", Keys->Key);
72 Io.mapRequired(
"FilePath", Keys->FilePath);
73 Io.mapRequired(
"Error", Keys->Error);
74 Io.mapRequired(
"InsertedHeaders", Keys->InsertedHeaders);
75 Io.mapRequired(
"RemovedHeaders", Keys->RemovedHeaders);
76 Io.mapRequired(
"Replacements", Keys->Replaces);
89bool violatesColumnLimit(llvm::StringRef Code,
unsigned ColumnLimit,
90 unsigned Start,
unsigned End) {
91 auto StartPos = Code.rfind(
'\n', Start);
92 StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1;
94 auto EndPos = Code.find(
"\n", End);
95 if (EndPos == llvm::StringRef::npos)
99 Code.substr(StartPos, EndPos - StartPos).split(Lines,
'\n');
100 for (llvm::StringRef
Line : Lines)
101 if (
Line.size() > ColumnLimit)
107getRangesForFormatting(llvm::StringRef Code,
unsigned ColumnLimit,
109 const clang::tooling::Replacements &Replaces) {
113 std::vector<clang::tooling::Range> Ranges;
118 for (
const clang::tooling::Replacement &R : Replaces) {
119 int Start =
R.getOffset() + Offset;
120 int End = Start +
R.getReplacementText().size();
121 if (!
R.getReplacementText().empty() &&
122 R.getReplacementText().back() ==
'\n' &&
R.getLength() == 0 &&
123 R.getOffset() > 0 &&
R.getOffset() <= Code.size() &&
124 Code[
R.getOffset() - 1] ==
'\n')
128 Offset +=
R.getReplacementText().size() -
R.getLength();
131 violatesColumnLimit(Code, ColumnLimit, Start, End))
132 Ranges.emplace_back(Start, End - Start);
138 return llvm::make_error<llvm::StringError>(Message,
139 llvm::inconvertibleErrorCode());
144createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code,
146 const format::FormatStyle &Style) {
150 for (
const auto &Change : Changes) {
151 for (llvm::StringRef Header : Change.getInsertedHeaders()) {
152 std::string EscapedHeader =
153 Header.starts_with(
"<") || Header.starts_with(
"\"")
155 : (
"\"" + Header +
"\"").str();
156 std::string ReplacementText =
"#include " + EscapedHeader;
159 llvm::Error Err = HeaderReplacements.add(
160 tooling::Replacement(FilePath,
UINT_MAX, 0, ReplacementText));
162 return std::move(Err);
164 for (
const std::string &Header : Change.getRemovedHeaders()) {
170 return std::move(Err);
183combineReplacementsInChanges(llvm::StringRef FilePath,
186 for (
const auto &Change : Changes)
187 for (
const auto &R : Change.getReplacements())
189 FilePath,
R.getOffset(),
R.getLength(),
R.getReplacementText())))
190 return std::move(Err);
201 assert(FE &&
"Cannot create AtomicChange with invalid location.");
202 FilePath = std::string(FE->
getName());
209 Metadata = std::move(M);
214 std::vector<std::string> InsertedHeaders,
215 std::vector<std::string> RemovedHeaders,
217 : Key(
std::move(Key)), FilePath(
std::move(FilePath)),
219 RemovedHeaders(
std::move(RemovedHeaders)), Replaces(
std::move(Replaces)) {
223 if (Key !=
Other.Key || FilePath !=
Other.FilePath || Error !=
Other.Error)
225 if (!(Replaces ==
Other.Replaces))
232 std::string YamlContent;
233 llvm::raw_string_ostream YamlContentStream(YamlContent);
235 llvm::yaml::Output YAML(YamlContentStream);
241 NormalizedAtomicChange NE;
242 llvm::yaml::Input YAML(YAMLContent);
244 AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
246 for (
const auto &R : NE.Replaces) {
247 llvm::Error Err = E.Replaces.
add(R);
250 "Failed to add replacement when Converting YAML to AtomicChange.");
251 llvm::consumeError(std::move(Err));
258 llvm::StringRef ReplacementText) {
263 unsigned Length, llvm::StringRef
Text) {
268 llvm::StringRef
Text,
bool InsertAfter) {
270 return llvm::Error::success();
272 llvm::Error Err = Replaces.add(R);
274 return llvm::handleErrors(
277 return llvm::make_error<ReplacementError>(RE);
278 unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
284 return llvm::Error::success();
287 return llvm::Error::success();
291 InsertedHeaders.push_back(std::string(Header));
295 RemovedHeaders.push_back(std::string(Header));
303 createReplacementsForHeaders(FilePath, Code, Changes, Spec.
Style);
304 if (!HeaderReplacements)
306 "Failed to create replacements for header changes: " +
307 llvm::toString(HeaderReplacements.takeError()));
310 combineReplacementsInChanges(FilePath, Changes);
313 llvm::toString(Replaces.takeError()));
316 for (
const auto &R : *HeaderReplacements) {
317 llvm::Error Err = AllReplaces.
add(R);
320 "Failed to combine existing replacements with header replacements: " +
321 llvm::toString(std::move(Err)));
329 llvm::toString(CleanReplaces.takeError()));
330 AllReplaces = std::move(*CleanReplaces);
338 llvm::toString(ChangedCode.takeError()));
348 "Failed to apply replacements for sorting includes: " +
349 llvm::toString(ChangedCode.takeError()));
351 AllReplaces = AllReplaces.
merge(HeaderSortingReplacements);
353 std::vector<Range> FormatRanges = getRangesForFormatting(
355 if (!FormatRanges.empty()) {
361 "Failed to apply replacements for formatting changed code: " +
362 llvm::toString(ChangedCode.takeError()));
This file defines the structure of a YAML document for serializing replacements.
Represents a byte-granular source range.
StringRef getName() const
The name of this FileEntry.
A SourceLocation and its associated SourceManager.
FullSourceLoc getSpellingLoc() const
FileIDAndOffset getDecomposedLoc() const
Decompose the specified location into a raw FileID + Offset pair.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
Top level wrappers for InstallAPI frontend operations.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
std::pair< FileID, unsigned > FileIDAndOffset
@ Other
Other implicit parameter.
Diagnostic wrappers for TextAPI types for error reporting.
static void mapping(IO &Io, NormalizedAtomicChange &Doc)