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_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
18 /// \brief Helper to (de)serialize an AtomicChange since we don't have direct
19 /// access to its data members.
20 /// Data members of a normalized AtomicChange can be directly mapped from/to
22 struct NormalizedAtomicChange {
23 NormalizedAtomicChange() = default;
25 NormalizedAtomicChange(const llvm::yaml::IO &) {}
27 // This converts AtomicChange's internal implementation of the replacements
28 // set to a vector of replacements.
29 NormalizedAtomicChange(const llvm::yaml::IO &,
30 const clang::tooling::AtomicChange &E)
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()) {}
36 // This is not expected to be called but needed for template instantiation.
37 clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) {
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;
48 } // anonymous namespace
53 /// \brief Specialized MappingTraits to describe how an AtomicChange is
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);
66 /// \brief Specialized MappingTraits to describe how an AtomicChange is
68 template <> struct MappingTraits<clang::tooling::AtomicChange> {
69 static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
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);
81 } // end namespace yaml
82 } // end namespace llvm
87 AtomicChange::AtomicChange(const SourceManager &SM,
88 SourceLocation KeyPosition) {
89 const FullSourceLoc FullKeyPosition(KeyPosition, SM);
90 std::pair<FileID, unsigned> FileIDAndOffset =
91 FullKeyPosition.getSpellingLoc().getDecomposedLoc();
92 const FileEntry *FE = SM.getFileEntryForID(FileIDAndOffset.first);
93 assert(FE && "Cannot create AtomicChange with invalid location.");
94 FilePath = FE->getName();
95 Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
98 AtomicChange::AtomicChange(std::string Key, std::string FilePath,
100 std::vector<std::string> InsertedHeaders,
101 std::vector<std::string> RemovedHeaders,
102 clang::tooling::Replacements Replaces)
103 : Key(std::move(Key)), FilePath(std::move(FilePath)),
104 Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),
105 RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
108 std::string AtomicChange::toYAMLString() {
109 std::string YamlContent;
110 llvm::raw_string_ostream YamlContentStream(YamlContent);
112 llvm::yaml::Output YAML(YamlContentStream);
114 YamlContentStream.flush();
118 AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
119 NormalizedAtomicChange NE;
120 llvm::yaml::Input YAML(YAMLContent);
122 AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
123 NE.RemovedHeaders, tooling::Replacements());
124 for (const auto &R : NE.Replaces) {
125 llvm::Error Err = E.Replaces.add(R);
128 "Failed to add replacement when Converting YAML to AtomicChange.");
129 llvm::consumeError(std::move(Err));
134 llvm::Error AtomicChange::replace(const SourceManager &SM,
135 const CharSourceRange &Range,
136 llvm::StringRef ReplacementText) {
137 return Replaces.add(Replacement(SM, Range, ReplacementText));
140 llvm::Error AtomicChange::replace(const SourceManager &SM, SourceLocation Loc,
141 unsigned Length, llvm::StringRef Text) {
142 return Replaces.add(Replacement(SM, Loc, Length, Text));
145 llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
146 llvm::StringRef Text, bool InsertAfter) {
148 return llvm::Error::success();
149 Replacement R(SM, Loc, 0, Text);
150 llvm::Error Err = Replaces.add(R);
152 return llvm::handleErrors(
153 std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {
154 if (RE.get() != replacement_error::insert_conflict)
155 return llvm::make_error<ReplacementError>(RE);
156 unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
159 RE.getExistingReplacement()->getReplacementText().size();
160 Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
161 Replaces = Replaces.merge(Replacements(NewR));
162 return llvm::Error::success();
165 return llvm::Error::success();
168 void AtomicChange::addHeader(llvm::StringRef Header) {
169 InsertedHeaders.push_back(Header);
172 void AtomicChange::removeHeader(llvm::StringRef Header) {
173 RemovedHeaders.push_back(Header);
176 } // end namespace tooling
177 } // end namespace clang