11#include "llvm/Support/YAMLTraits.h"
21struct NormalizedAtomicChange {
22 NormalizedAtomicChange() =
default;
24 NormalizedAtomicChange(
const llvm::yaml::IO &) {}
28 NormalizedAtomicChange(
const llvm::yaml::IO &,
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()) {}
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)
107getRangesForFormating(llvm::StringRef Code,
unsigned ColumnLimit,
113 std::vector<clang::tooling::Range> Ranges;
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) {
149 Replacements HeaderReplacements;
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()) {
168 HeaderReplacements.add(Replacement(FilePath,
UINT_MAX, 1, Header));
170 return std::move(Err);
183combineReplacementsInChanges(llvm::StringRef FilePath,
185 Replacements Replaces;
186 for (
const auto &Change : Changes)
187 for (
const auto &R : Change.getReplacements())
188 if (
auto Err = Replaces.add(Replacement(
189 FilePath, R.getOffset(), R.getLength(), R.getReplacementText())))
190 return std::move(Err);
199 std::pair<FileID, unsigned> FileIDAndOffset =
202 assert(FE &&
"Cannot create AtomicChange with invalid location.");
203 FilePath = std::string(FE->
getName());
204 Key = FilePath +
":" + std::to_string(FileIDAndOffset.second);
210 Metadata = std::move(M);
213AtomicChange::AtomicChange(std::string Key, std::string FilePath,
215 std::vector<std::string> InsertedHeaders,
216 std::vector<std::string> RemovedHeaders,
218 : Key(
std::move(Key)), FilePath(
std::move(FilePath)),
219 Error(
std::move(Error)), InsertedHeaders(
std::move(InsertedHeaders)),
220 RemovedHeaders(
std::move(RemovedHeaders)), Replaces(
std::move(Replaces)) {
224 if (Key !=
Other.Key || FilePath !=
Other.FilePath || Error !=
Other.Error)
226 if (!(Replaces ==
Other.Replaces))
233 std::string YamlContent;
234 llvm::raw_string_ostream YamlContentStream(YamlContent);
236 llvm::yaml::Output YAML(YamlContentStream);
238 YamlContentStream.flush();
243 NormalizedAtomicChange NE;
244 llvm::yaml::Input YAML(YAMLContent);
246 AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
248 for (
const auto &R : NE.Replaces) {
249 llvm::Error Err =
E.Replaces.add(R);
252 "Failed to add replacement when Converting YAML to AtomicChange.");
253 llvm::consumeError(std::move(Err));
260 llvm::StringRef ReplacementText) {
265 unsigned Length, llvm::StringRef
Text) {
270 llvm::StringRef
Text,
bool InsertAfter) {
272 return llvm::Error::success();
274 llvm::Error Err = Replaces.add(R);
276 return llvm::handleErrors(
279 return llvm::make_error<ReplacementError>(RE);
280 unsigned NewOffset = Replaces.getShiftedCodePosition(R.
getOffset());
286 return llvm::Error::success();
289 return llvm::Error::success();
293 InsertedHeaders.push_back(std::string(Header));
297 RemovedHeaders.push_back(std::string(Header));
305 createReplacementsForHeaders(FilePath, Code, Changes, Spec.
Style);
306 if (!HeaderReplacements)
308 "Failed to create replacements for header changes: " +
309 llvm::toString(HeaderReplacements.takeError()));
312 combineReplacementsInChanges(FilePath, Changes);
315 llvm::toString(Replaces.takeError()));
318 for (
const auto &R : *HeaderReplacements) {
319 llvm::Error Err = AllReplaces.
add(R);
322 "Failed to combine existing replacements with header replacements: " +
323 llvm::toString(std::move(Err)));
331 llvm::toString(CleanReplaces.takeError()));
332 AllReplaces = std::move(*CleanReplaces);
340 llvm::toString(ChangedCode.takeError()));
350 "Failed to apply replacements for sorting includes: " +
351 llvm::toString(ChangedCode.takeError()));
353 AllReplaces = AllReplaces.
merge(HeaderSortingReplacements);
355 std::vector<Range> FormatRanges = getRangesForFormating(
357 if (!FormatRanges.empty()) {
363 "Failed to apply replacements for formatting changed code: " +
364 llvm::toString(ChangedCode.takeError()));
This file defines the structure of a YAML document for serializing replacements.
Represents a character-granular source range.
StringRef getName() const
The name of this FileEntry.
A SourceLocation and its associated SourceManager.
FullSourceLoc getSpellingLoc() const
std::pair< FileID, unsigned > 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.
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
@ Other
Other implicit parameter.
Diagnostic wrappers for TextAPI types for error reporting.
static void mapping(IO &Io, NormalizedAtomicChange &Doc)