]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp
MFV r323912: 8592 ZFS channel programs - rollback
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Tooling / Refactoring / AtomicChange.cpp
1 //===--- 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
15 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
16
17 namespace {
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
21 /// YAML string.
22 struct NormalizedAtomicChange {
23   NormalizedAtomicChange() = default;
24
25   NormalizedAtomicChange(const llvm::yaml::IO &) {}
26
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()) {}
35
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.");
40   }
41   std::string Key;
42   std::string FilePath;
43   std::string Error;
44   std::vector<std::string> InsertedHeaders;
45   std::vector<std::string> RemovedHeaders;
46   std::vector<clang::tooling::Replacement> Replaces;
47 };
48 } // anonymous namespace
49
50 namespace llvm {
51 namespace yaml {
52
53 /// \brief Specialized MappingTraits to describe how an AtomicChange is
54 /// (de)serialized.
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);
63   }
64 };
65
66 /// \brief Specialized MappingTraits to describe how an AtomicChange is
67 /// (de)serialized.
68 template <> struct MappingTraits<clang::tooling::AtomicChange> {
69   static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
70     MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
71         Keys(Io, Doc);
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);
78   }
79 };
80
81 } // end namespace yaml
82 } // end namespace llvm
83
84 namespace clang {
85 namespace tooling {
86
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);
96 }
97
98 AtomicChange::AtomicChange(std::string Key, std::string FilePath,
99                            std::string Error,
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)) {
106 }
107
108 std::string AtomicChange::toYAMLString() {
109   std::string YamlContent;
110   llvm::raw_string_ostream YamlContentStream(YamlContent);
111
112   llvm::yaml::Output YAML(YamlContentStream);
113   YAML << *this;
114   YamlContentStream.flush();
115   return YamlContent;
116 }
117
118 AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
119   NormalizedAtomicChange NE;
120   llvm::yaml::Input YAML(YAMLContent);
121   YAML >> NE;
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);
126     if (Err)
127       llvm_unreachable(
128           "Failed to add replacement when Converting YAML to AtomicChange.");
129     llvm::consumeError(std::move(Err));
130   }
131   return E;
132 }
133
134 llvm::Error AtomicChange::replace(const SourceManager &SM,
135                                   const CharSourceRange &Range,
136                                   llvm::StringRef ReplacementText) {
137   return Replaces.add(Replacement(SM, Range, ReplacementText));
138 }
139
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));
143 }
144
145 llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
146                                  llvm::StringRef Text, bool InsertAfter) {
147   if (Text.empty())
148     return llvm::Error::success();
149   Replacement R(SM, Loc, 0, Text);
150   llvm::Error Err = Replaces.add(R);
151   if (Err) {
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());
157           if (!InsertAfter)
158             NewOffset -=
159                 RE.getExistingReplacement()->getReplacementText().size();
160           Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
161           Replaces = Replaces.merge(Replacements(NewR));
162           return llvm::Error::success();
163         });
164   }
165   return llvm::Error::success();
166 }
167
168 void AtomicChange::addHeader(llvm::StringRef Header) {
169   InsertedHeaders.push_back(Header);
170 }
171
172 void AtomicChange::removeHeader(llvm::StringRef Header) {
173   RemovedHeaders.push_back(Header);
174 }
175
176 } // end namespace tooling
177 } // end namespace clang