]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp
Update llvm/clang to trunk r126547.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Rewrite / Rewriter.cpp
1 //===--- Rewriter.cpp - Code rewriting interface --------------------------===//
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 //  This file defines the Rewriter class, which is used for code
11 //  transformations.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "clang/Rewrite/Rewriter.h"
16 #include "clang/AST/Stmt.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/Lex/Lexer.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "llvm/Support/raw_ostream.h"
21 using namespace clang;
22
23 llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const {
24   // FIXME: eliminate the copy by writing out each chunk at a time
25   os << std::string(begin(), end());
26   return os;
27 }
28
29 void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
30   // Nothing to remove, exit early.
31   if (Size == 0) return;
32
33   unsigned RealOffset = getMappedOffset(OrigOffset, true);
34   assert(RealOffset+Size < Buffer.size() && "Invalid location");
35
36   // Remove the dead characters.
37   Buffer.erase(RealOffset, Size);
38
39   // Add a delta so that future changes are offset correctly.
40   AddReplaceDelta(OrigOffset, -Size);
41 }
42
43 void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str,
44                                bool InsertAfter) {
45
46   // Nothing to insert, exit early.
47   if (Str.empty()) return;
48
49   unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
50   Buffer.insert(RealOffset, Str.begin(), Str.end());
51
52   // Add a delta so that future changes are offset correctly.
53   AddInsertDelta(OrigOffset, Str.size());
54 }
55
56 /// ReplaceText - This method replaces a range of characters in the input
57 /// buffer with a new string.  This is effectively a combined "remove+insert"
58 /// operation.
59 void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
60                                 llvm::StringRef NewStr) {
61   unsigned RealOffset = getMappedOffset(OrigOffset, true);
62   Buffer.erase(RealOffset, OrigLength);
63   Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
64   if (OrigLength != NewStr.size())
65     AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
66 }
67
68
69 //===----------------------------------------------------------------------===//
70 // Rewriter class
71 //===----------------------------------------------------------------------===//
72
73 /// getRangeSize - Return the size in bytes of the specified range if they
74 /// are in the same file.  If not, this returns -1.
75 int Rewriter::getRangeSize(const CharSourceRange &Range) const {
76   if (!isRewritable(Range.getBegin()) ||
77       !isRewritable(Range.getEnd())) return -1;
78
79   FileID StartFileID, EndFileID;
80   unsigned StartOff, EndOff;
81
82   StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
83   EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
84
85   if (StartFileID != EndFileID)
86     return -1;
87
88   // If edits have been made to this buffer, the delta between the range may
89   // have changed.
90   std::map<FileID, RewriteBuffer>::const_iterator I =
91     RewriteBuffers.find(StartFileID);
92   if (I != RewriteBuffers.end()) {
93     const RewriteBuffer &RB = I->second;
94     EndOff = RB.getMappedOffset(EndOff, true);
95     StartOff = RB.getMappedOffset(StartOff);
96   }
97
98
99   // Adjust the end offset to the end of the last token, instead of being the
100   // start of the last token if this is a token range.
101   if (Range.isTokenRange())
102     EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
103
104   return EndOff-StartOff;
105 }
106
107 int Rewriter::getRangeSize(SourceRange Range) const {
108   return getRangeSize(CharSourceRange::getTokenRange(Range));
109 }
110
111
112 /// getRewrittenText - Return the rewritten form of the text in the specified
113 /// range.  If the start or end of the range was unrewritable or if they are
114 /// in different buffers, this returns an empty string.
115 ///
116 /// Note that this method is not particularly efficient.
117 ///
118 std::string Rewriter::getRewrittenText(SourceRange Range) const {
119   if (!isRewritable(Range.getBegin()) ||
120       !isRewritable(Range.getEnd()))
121     return "";
122
123   FileID StartFileID, EndFileID;
124   unsigned StartOff, EndOff;
125   StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
126   EndOff   = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
127
128   if (StartFileID != EndFileID)
129     return ""; // Start and end in different buffers.
130
131   // If edits have been made to this buffer, the delta between the range may
132   // have changed.
133   std::map<FileID, RewriteBuffer>::const_iterator I =
134     RewriteBuffers.find(StartFileID);
135   if (I == RewriteBuffers.end()) {
136     // If the buffer hasn't been rewritten, just return the text from the input.
137     const char *Ptr = SourceMgr->getCharacterData(Range.getBegin());
138
139     // Adjust the end offset to the end of the last token, instead of being the
140     // start of the last token.
141     EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
142     return std::string(Ptr, Ptr+EndOff-StartOff);
143   }
144
145   const RewriteBuffer &RB = I->second;
146   EndOff = RB.getMappedOffset(EndOff, true);
147   StartOff = RB.getMappedOffset(StartOff);
148
149   // Adjust the end offset to the end of the last token, instead of being the
150   // start of the last token.
151   EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
152
153   // Advance the iterators to the right spot, yay for linear time algorithms.
154   RewriteBuffer::iterator Start = RB.begin();
155   std::advance(Start, StartOff);
156   RewriteBuffer::iterator End = Start;
157   std::advance(End, EndOff-StartOff);
158
159   return std::string(Start, End);
160 }
161
162 unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
163                                               FileID &FID) const {
164   assert(Loc.isValid() && "Invalid location");
165   std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc);
166   FID = V.first;
167   return V.second;
168 }
169
170
171 /// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
172 ///
173 RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
174   std::map<FileID, RewriteBuffer>::iterator I =
175     RewriteBuffers.lower_bound(FID);
176   if (I != RewriteBuffers.end() && I->first == FID)
177     return I->second;
178   I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
179
180   llvm::StringRef MB = SourceMgr->getBufferData(FID);
181   I->second.Initialize(MB.begin(), MB.end());
182
183   return I->second;
184 }
185
186 /// InsertText - Insert the specified string at the specified location in the
187 /// original buffer.
188 bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
189                           bool InsertAfter) {
190   if (!isRewritable(Loc)) return true;
191   FileID FID;
192   unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
193   getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
194   return false;
195 }
196
197 /// RemoveText - Remove the specified text region.
198 bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) {
199   if (!isRewritable(Start)) return true;
200   FileID FID;
201   unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
202   getEditBuffer(FID).RemoveText(StartOffs, Length);
203   return false;
204 }
205
206 /// ReplaceText - This method replaces a range of characters in the input
207 /// buffer with a new string.  This is effectively a combined "remove/insert"
208 /// operation.
209 bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
210                            llvm::StringRef NewStr) {
211   if (!isRewritable(Start)) return true;
212   FileID StartFileID;
213   unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
214
215   getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr);
216   return false;
217 }
218
219 /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
220 /// printer to generate the replacement code.  This returns true if the input
221 /// could not be rewritten, or false if successful.
222 bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
223   // Measaure the old text.
224   int Size = getRangeSize(From->getSourceRange());
225   if (Size == -1)
226     return true;
227
228   // Get the new text.
229   std::string SStr;
230   llvm::raw_string_ostream S(SStr);
231   To->printPretty(S, 0, PrintingPolicy(*LangOpts));
232   const std::string &Str = S.str();
233
234   ReplaceText(From->getLocStart(), Size, Str);
235   return false;
236 }