1 //===--- AtomicChange.cpp - AtomicChange implementation -----------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/Tooling/Refactoring/AtomicChange.h"
11 #include "clang/Tooling/ReplacementsYaml.h"
12 #include "llvm/Support/YAMLTraits.h"
15 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
16 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
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
23 struct NormalizedAtomicChange {
24 NormalizedAtomicChange() = default;
26 NormalizedAtomicChange(const llvm::yaml::IO &) {}
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()) {}
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.");
45 std::vector<std::string> InsertedHeaders;
46 std::vector<std::string> RemovedHeaders;
47 std::vector<clang::tooling::Replacement> Replaces;
49 } // anonymous namespace
54 /// \brief Specialized MappingTraits to describe how an AtomicChange is
56 template <> 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);
67 /// \brief Specialized MappingTraits to describe how an AtomicChange is
69 template <> struct MappingTraits<clang::tooling::AtomicChange> {
70 static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
71 MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
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);
82 } // end namespace yaml
83 } // end namespace llvm
88 AtomicChange::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);
99 AtomicChange::AtomicChange(std::string Key, std::string FilePath,
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)) {
109 std::string AtomicChange::toYAMLString() {
110 std::string YamlContent;
111 llvm::raw_string_ostream YamlContentStream(YamlContent);
113 llvm::yaml::Output YAML(YamlContentStream);
115 YamlContentStream.flush();
119 AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
120 NormalizedAtomicChange NE;
121 llvm::yaml::Input YAML(YAMLContent);
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);
129 "Failed to add replacement when Converting YAML to AtomicChange.");
130 llvm::consumeError(std::move(Err));
135 llvm::Error AtomicChange::replace(const SourceManager &SM,
136 const CharSourceRange &Range,
137 llvm::StringRef ReplacementText) {
138 return Replaces.add(Replacement(SM, Range, ReplacementText));
141 llvm::Error AtomicChange::replace(const SourceManager &SM, SourceLocation Loc,
142 unsigned Length, llvm::StringRef Text) {
143 return Replaces.add(Replacement(SM, Loc, Length, Text));
146 llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
147 llvm::StringRef Text, bool InsertAfter) {
149 return llvm::Error::success();
150 Replacement R(SM, Loc, 0, Text);
151 llvm::Error Err = Replaces.add(R);
153 return llvm::handleErrors(
154 std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {
155 if (RE.get() != replacement_error::insert_conflict)
156 return llvm::make_error<ReplacementError>(RE);
157 unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
160 RE.getExistingReplacement()->getReplacementText().size();
161 Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
162 Replaces = Replaces.merge(Replacements(NewR));
163 return llvm::Error::success();
166 return llvm::Error::success();
169 void AtomicChange::addHeader(llvm::StringRef Header) {
170 InsertedHeaders.push_back(Header);
173 void AtomicChange::removeHeader(llvm::StringRef Header) {
174 RemovedHeaders.push_back(Header);
177 } // end namespace tooling
178 } // end namespace clang