12 #include "llvm/Support/YAMLTraits.h" 22 struct NormalizedAtomicChange {
23 NormalizedAtomicChange() =
default;
25 NormalizedAtomicChange(
const llvm::yaml::IO &) {}
29 NormalizedAtomicChange(
const llvm::yaml::IO &,
31 : Key(E.getKey()), FilePath(E.getFilePath()),
Error(E.getError()),
32 InsertedHeaders(E.getInsertedHeaders()),
33 RemovedHeaders(E.getRemovedHeaders()),
34 Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}
38 llvm_unreachable(
"Do not convert YAML to AtomicChange directly with '>>'. " 39 "Use AtomicChange::convertFromYAML instead.");
44 std::vector<std::string> InsertedHeaders;
45 std::vector<std::string> RemovedHeaders;
46 std::vector<clang::tooling::Replacement> Replaces;
55 template <>
struct MappingTraits<NormalizedAtomicChange> {
56 static void mapping(IO &Io, NormalizedAtomicChange &Doc) {
57 Io.mapRequired(
"Key", Doc.Key);
58 Io.mapRequired(
"FilePath", Doc.FilePath);
59 Io.mapRequired(
"Error", Doc.Error);
60 Io.mapRequired(
"InsertedHeaders", Doc.InsertedHeaders);
61 Io.mapRequired(
"RemovedHeaders", Doc.RemovedHeaders);
62 Io.mapRequired(
"Replacements", Doc.Replaces);
68 template <>
struct MappingTraits<
clang::tooling::AtomicChange> {
70 MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
72 Io.mapRequired(
"Key", Keys->Key);
73 Io.mapRequired(
"FilePath", Keys->FilePath);
74 Io.mapRequired(
"Error", Keys->Error);
75 Io.mapRequired(
"InsertedHeaders", Keys->InsertedHeaders);
76 Io.mapRequired(
"RemovedHeaders", Keys->RemovedHeaders);
77 Io.mapRequired(
"Replacements", Keys->Replaces);
90 bool violatesColumnLimit(llvm::StringRef Code,
unsigned ColumnLimit,
91 unsigned Start,
unsigned End) {
92 auto StartPos = Code.rfind(
'\n', Start);
93 StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1;
95 auto EndPos = Code.find(
"\n", End);
96 if (EndPos == llvm::StringRef::npos)
100 Code.substr(StartPos, EndPos - StartPos).split(Lines,
'\n');
101 for (llvm::StringRef
Line : Lines)
102 if (
Line.size() > ColumnLimit)
108 getRangesForFormating(llvm::StringRef Code,
unsigned ColumnLimit,
109 ApplyChangesSpec::FormatOption Format,
112 if (Format == ApplyChangesSpec::kNone)
114 std::vector<clang::tooling::Range> Ranges;
120 int Start = R.getOffset() +
Offset;
121 int End = Start + R.getReplacementText().size();
122 if (!R.getReplacementText().empty() &&
123 R.getReplacementText().back() ==
'\n' && R.getLength() == 0 &&
124 R.getOffset() > 0 && R.getOffset() <= Code.size() &&
125 Code[R.getOffset() - 1] ==
'\n')
129 Offset += R.getReplacementText().size() - R.getLength();
131 if (Format == ApplyChangesSpec::kAll ||
132 violatesColumnLimit(Code, ColumnLimit, Start, End))
133 Ranges.emplace_back(Start, End - Start);
139 return llvm::make_error<llvm::StringError>(Message,
140 llvm::inconvertibleErrorCode());
145 createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code,
147 const format::FormatStyle &
Style) {
150 Replacements HeaderReplacements;
151 for (
const auto &Change : Changes) {
152 for (llvm::StringRef Header : Change.getInsertedHeaders()) {
153 std::string EscapedHeader =
154 Header.startswith(
"<") || Header.startswith(
"\"")
156 : (
"\"" + Header +
"\"").str();
157 std::string ReplacementText =
"#include " + EscapedHeader;
160 llvm::Error Err = HeaderReplacements.add(
163 return std::move(Err);
165 for (
const std::string &Header : Change.getRemovedHeaders()) {
171 return std::move(Err);
184 combineReplacementsInChanges(llvm::StringRef FilePath,
186 Replacements Replaces;
187 for (
const auto &Change : Changes)
188 for (
const auto &R : Change.getReplacements())
190 FilePath, R.getOffset(), R.getLength(), R.getReplacementText())))
191 return std::move(Err);
200 std::pair<FileID, unsigned> FileIDAndOffset =
203 assert(FE &&
"Cannot create AtomicChange with invalid location.");
205 Key = FilePath +
":" + std::to_string(FileIDAndOffset.second);
208 AtomicChange::AtomicChange(std::string Key, std::string FilePath,
210 std::vector<std::string> InsertedHeaders,
211 std::vector<std::string> RemovedHeaders,
213 : Key(std::move(Key)), FilePath(std::move(FilePath)),
214 Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),
215 RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
219 if (Key != Other.Key || FilePath != Other.FilePath || Error != Other.Error)
221 if (!(Replaces == Other.Replaces))
227 std::string AtomicChange::toYAMLString() {
228 std::string YamlContent;
229 llvm::raw_string_ostream YamlContentStream(YamlContent);
231 llvm::yaml::Output YAML(YamlContentStream);
233 YamlContentStream.flush();
237 AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
238 NormalizedAtomicChange NE;
239 llvm::yaml::Input YAML(YAMLContent);
241 AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
243 for (
const auto &R : NE.Replaces) {
244 llvm::Error Err = E.Replaces.
add(R);
247 "Failed to add replacement when Converting YAML to AtomicChange.");
248 llvm::consumeError(std::move(Err));
255 llvm::StringRef ReplacementText) {
260 unsigned Length, llvm::StringRef
Text) {
265 llvm::StringRef
Text,
bool InsertAfter) {
267 return llvm::Error::success();
269 llvm::Error Err = Replaces.
add(R);
271 return llvm::handleErrors(
273 if (RE.
get() != replacement_error::insert_conflict)
274 return llvm::make_error<ReplacementError>(RE);
281 return llvm::Error::success();
284 return llvm::Error::success();
287 void AtomicChange::addHeader(llvm::StringRef Header) {
288 InsertedHeaders.push_back(Header);
291 void AtomicChange::removeHeader(llvm::StringRef Header) {
292 RemovedHeaders.push_back(Header);
300 createReplacementsForHeaders(FilePath, Code, Changes, Spec.
Style);
301 if (!HeaderReplacements)
303 "Failed to create replacements for header changes: " +
307 combineReplacementsInChanges(FilePath, Changes);
313 for (
const auto &R : *HeaderReplacements) {
314 llvm::Error Err = AllReplaces.
add(R);
317 "Failed to combine existing replacements with header replacements: " +
327 AllReplaces = std::move(*CleanReplaces);
345 "Failed to apply replacements for sorting includes: " +
348 AllReplaces = AllReplaces.
merge(HeaderSortingReplacements);
350 std::vector<Range> FormatRanges = getRangesForFormating(
352 if (!FormatRanges.empty()) {
358 "Failed to apply replacements for formatting changed code: " +
bool operator==(CanQual< T > x, CanQual< U > y)
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
AvailabilityChange Changes[NumAvailabilitySlots]
Represents a character-granular source range.
std::pair< FileID, unsigned > getDecomposedLoc() const
Decompose the specified location into a raw FileID + Offset pair.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
const AnnotatedLine * Line
Encodes a location in the source.
StringRef getName() const
Cached information about one file (either on disk or in the virtual file system). ...
Dataflow Directional Tag Classes.
std::string toString(const til::SExpr *E)
FullSourceLoc getSpellingLoc() const
A SourceLocation and its associated SourceManager.
static void mapping(IO &Io, NormalizedAtomicChange &Doc)
This file defines the structure of a YAML document for serializing replacements.
This class handles loading and caching of source files into memory.