]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp
Merge clang trunk r300422 and resolve conflicts.
[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_FLOW_SEQUENCE_VECTOR(std::string)
16 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
17
18 namespace {
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.
23 struct 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
51 namespace llvm {
52 namespace yaml {
53
54 /// \brief Specialized MappingTraits to describe how an AtomicChange is
55 /// (de)serialized.
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);
64   }
65 };
66
67 /// \brief Specialized MappingTraits to describe how an AtomicChange is
68 /// (de)serialized.
69 template <> 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
85 namespace clang {
86 namespace tooling {
87
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);
97 }
98
99 AtomicChange::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
109 std::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
119 AtomicChange 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
135 llvm::Error AtomicChange::replace(const SourceManager &SM,
136                                   const CharSourceRange &Range,
137                                   llvm::StringRef ReplacementText) {
138   return Replaces.add(Replacement(SM, Range, ReplacementText));
139 }
140
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));
144 }
145
146 llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
147                                  llvm::StringRef Text, bool InsertAfter) {
148   if (Text.empty())
149     return llvm::Error::success();
150   Replacement R(SM, Loc, 0, Text);
151   llvm::Error Err = Replaces.add(R);
152   if (Err) {
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());
158           if (!InsertAfter)
159             NewOffset -=
160                 RE.getExistingReplacement()->getReplacementText().size();
161           Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
162           Replaces = Replaces.merge(Replacements(NewR));
163           return llvm::Error::success();
164         });
165   }
166   return llvm::Error::success();
167 }
168
169 void AtomicChange::addHeader(llvm::StringRef Header) {
170   InsertedHeaders.push_back(Header);
171 }
172
173 void AtomicChange::removeHeader(llvm::StringRef Header) {
174   RemovedHeaders.push_back(Header);
175 }
176
177 } // end namespace tooling
178 } // end namespace clang