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