blob: 3572d2a1bea59c042e17faf3d4cc7e3c345c4453 [file] [log] [blame]
Eric Liu9e745b72017-03-01 13:14:01 +00001//===--- AtomicChange.cpp - AtomicChange implementation -----------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/Tooling/Refactoring/AtomicChange.h"
11#include "clang/Tooling/ReplacementsYaml.h"
12#include "llvm/Support/YAMLTraits.h"
13#include <string>
14
15LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
16LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
17
18namespace {
19/// \brief Helper to (de)serialize an AtomicChange since we don't have direct
20/// access to its data members.
21/// Data members of a normalized AtomicChange can be directly mapped from/to
22/// YAML string.
23struct NormalizedAtomicChange {
24 NormalizedAtomicChange() = default;
25
26 NormalizedAtomicChange(const llvm::yaml::IO &) {}
27
28 // This converts AtomicChange's internal implementation of the replacements
29 // set to a vector of replacements.
30 NormalizedAtomicChange(const llvm::yaml::IO &,
31 const clang::tooling::AtomicChange &E)
32 : Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()),
33 InsertedHeaders(E.getInsertedHeaders()),
34 RemovedHeaders(E.getRemovedHeaders()),
35 Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}
36
37 // This is not expected to be called but needed for template instantiation.
38 clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) {
39 llvm_unreachable("Do not convert YAML to AtomicChange directly with '>>'. "
40 "Use AtomicChange::convertFromYAML instead.");
41 }
42 std::string Key;
43 std::string FilePath;
44 std::string Error;
45 std::vector<std::string> InsertedHeaders;
46 std::vector<std::string> RemovedHeaders;
47 std::vector<clang::tooling::Replacement> Replaces;
48};
49} // anonymous namespace
50
51namespace llvm {
52namespace yaml {
53
54/// \brief Specialized MappingTraits to describe how an AtomicChange is
55/// (de)serialized.
56template <> struct MappingTraits<NormalizedAtomicChange> {
57 static void mapping(IO &Io, NormalizedAtomicChange &Doc) {
58 Io.mapRequired("Key", Doc.Key);
59 Io.mapRequired("FilePath", Doc.FilePath);
60 Io.mapRequired("Error", Doc.Error);
61 Io.mapRequired("InsertedHeaders", Doc.InsertedHeaders);
62 Io.mapRequired("RemovedHeaders", Doc.RemovedHeaders);
63 Io.mapRequired("Replacements", Doc.Replaces);
64 }
65};
66
67/// \brief Specialized MappingTraits to describe how an AtomicChange is
68/// (de)serialized.
69template <> struct MappingTraits<clang::tooling::AtomicChange> {
70 static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
71 MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
72 Keys(Io, Doc);
73 Io.mapRequired("Key", Keys->Key);
74 Io.mapRequired("FilePath", Keys->FilePath);
75 Io.mapRequired("Error", Keys->Error);
76 Io.mapRequired("InsertedHeaders", Keys->InsertedHeaders);
77 Io.mapRequired("RemovedHeaders", Keys->RemovedHeaders);
78 Io.mapRequired("Replacements", Keys->Replaces);
79 }
80};
81
82} // end namespace yaml
83} // end namespace llvm
84
85namespace clang {
86namespace tooling {
87
88AtomicChange::AtomicChange(const SourceManager &SM,
89 SourceLocation KeyPosition) {
90 const FullSourceLoc FullKeyPosition(KeyPosition, SM);
91 std::pair<FileID, unsigned> FileIDAndOffset =
92 FullKeyPosition.getSpellingLoc().getDecomposedLoc();
93 const FileEntry *FE = SM.getFileEntryForID(FileIDAndOffset.first);
94 assert(FE && "Cannot create AtomicChange with invalid location.");
95 FilePath = FE->getName();
96 Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
97}
98
99AtomicChange::AtomicChange(std::string Key, std::string FilePath,
100 std::string Error,
101 std::vector<std::string> InsertedHeaders,
102 std::vector<std::string> RemovedHeaders,
103 clang::tooling::Replacements Replaces)
104 : Key(std::move(Key)), FilePath(std::move(FilePath)),
105 Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),
106 RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
107}
108
109std::string AtomicChange::toYAMLString() {
110 std::string YamlContent;
111 llvm::raw_string_ostream YamlContentStream(YamlContent);
112
113 llvm::yaml::Output YAML(YamlContentStream);
114 YAML << *this;
115 YamlContentStream.flush();
116 return YamlContent;
117}
118
119AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
120 NormalizedAtomicChange NE;
121 llvm::yaml::Input YAML(YAMLContent);
122 YAML >> NE;
123 AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
124 NE.RemovedHeaders, tooling::Replacements());
125 for (const auto &R : NE.Replaces) {
126 llvm::Error Err = E.Replaces.add(R);
127 if (Err)
128 llvm_unreachable(
129 "Failed to add replacement when Converting YAML to AtomicChange.");
130 llvm::consumeError(std::move(Err));
131 }
132 return E;
133}
134
135llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
136 llvm::StringRef Text, bool InsertAfter) {
137 if (Text.empty())
138 return llvm::Error::success();
139 Replacement R(SM, Loc, 0, Text);
140 llvm::Error Err = Replaces.add(R);
141 if (Err) {
142 return llvm::handleErrors(
143 std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {
144 if (RE.get() != replacement_error::insert_conflict)
145 return llvm::make_error<ReplacementError>(RE);
146 unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
147 if (!InsertAfter)
148 NewOffset -=
149 RE.getExistingReplacement()->getReplacementText().size();
150 Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
151 Replaces = Replaces.merge(Replacements(NewR));
152 return llvm::Error::success();
153 });
154 }
155 return llvm::Error::success();
156}
157
158void AtomicChange::addHeader(llvm::StringRef Header) {
159 InsertedHeaders.push_back(Header);
160}
161
162void AtomicChange::removeHeader(llvm::StringRef Header) {
163 RemovedHeaders.push_back(Header);
164}
165
166} // end namespace tooling
167} // end namespace clang