blob: 1c1903cc40d4e0b1e0517b533a104d6d4c9bdc5f [file] [log] [blame]
Chris Lattner57629372007-09-15 22:21:22 +00001//===--- Rewriter.cpp - Code rewriting interface --------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner959e5be2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner57629372007-09-15 22:21:22 +00007//
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"
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000016#include "clang/AST/Stmt.h"
Chris Lattner93e2a4e2007-10-17 21:23:07 +000017#include "clang/Lex/Lexer.h"
Chris Lattner569faa62007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Chris Lattnerbf0bfa62007-10-17 22:35:30 +000019#include <sstream>
Chris Lattner57629372007-09-15 22:21:22 +000020using namespace clang;
21
Chris Lattner57629372007-09-15 22:21:22 +000022void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
Chris Lattner3cfe3d32007-10-13 00:11:23 +000023 // Nothing to remove, exit early.
24 if (Size == 0) return;
25
26 unsigned RealOffset = getMappedOffset(OrigOffset, true);
27 assert(RealOffset+Size < Buffer.size() && "Invalid location");
28
29 // Remove the dead characters.
Chris Lattner233875d2007-11-08 20:51:02 +000030 RewriteRope::iterator I = Buffer.getAtOffset(RealOffset);
31 Buffer.erase(I, I+Size);
Chris Lattner3cfe3d32007-10-13 00:11:23 +000032
33 // Add a delta so that future changes are offset correctly.
34 AddDelta(OrigOffset, -Size);
Chris Lattner57629372007-09-15 22:21:22 +000035}
36
37void RewriteBuffer::InsertText(unsigned OrigOffset,
Ted Kremenek8d0368c2008-03-18 21:17:59 +000038 const char *StrData, unsigned StrLen,
39 bool InsertAfter) {
40
Chris Lattnercea0bcc2007-10-13 00:21:23 +000041 // Nothing to insert, exit early.
Chris Lattner3cfe3d32007-10-13 00:11:23 +000042 if (StrLen == 0) return;
Chris Lattnercea0bcc2007-10-13 00:21:23 +000043
Ted Kremenek8d0368c2008-03-18 21:17:59 +000044 unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
Chris Lattnercea0bcc2007-10-13 00:21:23 +000045 assert(RealOffset <= Buffer.size() && "Invalid location");
46
Chris Lattnerd119a842007-11-08 04:41:04 +000047 // Insert the new characters.
Chris Lattner233875d2007-11-08 20:51:02 +000048 Buffer.insert(Buffer.getAtOffset(RealOffset), StrData, StrData+StrLen);
Chris Lattnercea0bcc2007-10-13 00:21:23 +000049
50 // Add a delta so that future changes are offset correctly.
51 AddDelta(OrigOffset, StrLen);
Chris Lattner57629372007-09-15 22:21:22 +000052}
Chris Lattner569faa62007-10-11 18:38:32 +000053
Chris Lattner3cfe3d32007-10-13 00:11:23 +000054/// ReplaceText - This method replaces a range of characters in the input
55/// buffer with a new string. This is effectively a combined "remove/insert"
56/// operation.
57void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
58 const char *NewStr, unsigned NewLength) {
Chris Lattnerb57cd002007-11-08 04:09:59 +000059 unsigned RealOffset = getMappedOffset(OrigOffset, true);
Chris Lattnere471a3b2007-10-13 00:46:29 +000060 assert(RealOffset+OrigLength <= Buffer.size() && "Invalid location");
61
62 // Overwrite the common piece.
Chris Lattnerd119a842007-11-08 04:41:04 +000063 unsigned CommonLength = std::min(OrigLength, NewLength);
Chris Lattner233875d2007-11-08 20:51:02 +000064 std::copy(NewStr, NewStr+CommonLength, Buffer.getAtOffset(RealOffset));
Chris Lattner3cfe3d32007-10-13 00:11:23 +000065
Chris Lattnere471a3b2007-10-13 00:46:29 +000066 // If replacing without shifting around, just overwrite the text.
67 if (OrigLength == NewLength)
Chris Lattner3cfe3d32007-10-13 00:11:23 +000068 return;
Chris Lattnere471a3b2007-10-13 00:46:29 +000069
70 // If inserting more than existed before, this is like an insertion.
71 if (NewLength > OrigLength) {
Chris Lattner233875d2007-11-08 20:51:02 +000072 Buffer.insert(Buffer.getAtOffset(RealOffset+OrigLength),
Chris Lattnere471a3b2007-10-13 00:46:29 +000073 NewStr+OrigLength, NewStr+NewLength);
74 } else {
Chris Lattner233875d2007-11-08 20:51:02 +000075 // If inserting less than existed before, this is like a removal.
76 RewriteRope::iterator I = Buffer.getAtOffset(RealOffset+NewLength);
77 Buffer.erase(I, I+(OrigLength-NewLength));
Chris Lattner3cfe3d32007-10-13 00:11:23 +000078 }
Chris Lattnere471a3b2007-10-13 00:46:29 +000079 AddDelta(OrigOffset, NewLength-OrigLength);
Chris Lattner3cfe3d32007-10-13 00:11:23 +000080}
Chris Lattner569faa62007-10-11 18:38:32 +000081
82
83//===----------------------------------------------------------------------===//
84// Rewriter class
85//===----------------------------------------------------------------------===//
86
Chris Lattner6fe8b272007-10-16 22:36:42 +000087/// getRangeSize - Return the size in bytes of the specified range if they
88/// are in the same file. If not, this returns -1.
89int Rewriter::getRangeSize(SourceRange Range) const {
90 if (!isRewritable(Range.getBegin()) ||
91 !isRewritable(Range.getEnd())) return -1;
92
93 unsigned StartOff, StartFileID;
94 unsigned EndOff , EndFileID;
95
96 StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
97 EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
98
99 if (StartFileID != EndFileID)
100 return -1;
101
Chris Lattnerbc68f692007-10-25 17:18:59 +0000102 // If edits have been made to this buffer, the delta between the range may
103 // have changed.
Chris Lattnera8a73682007-10-25 17:17:34 +0000104 std::map<unsigned, RewriteBuffer>::const_iterator I =
105 RewriteBuffers.find(StartFileID);
Chris Lattnerbc68f692007-10-25 17:18:59 +0000106 if (I != RewriteBuffers.end()) {
Chris Lattnera8a73682007-10-25 17:17:34 +0000107 const RewriteBuffer &RB = I->second;
Chris Lattnerbc68f692007-10-25 17:18:59 +0000108 EndOff = RB.getMappedOffset(EndOff, true);
109 StartOff = RB.getMappedOffset(StartOff);
Chris Lattnera8a73682007-10-25 17:17:34 +0000110 }
111
112
Chris Lattner93e2a4e2007-10-17 21:23:07 +0000113 // Adjust the end offset to the end of the last token, instead of being the
114 // start of the last token.
Chris Lattnerbc68f692007-10-25 17:18:59 +0000115 EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr);
Chris Lattner93e2a4e2007-10-17 21:23:07 +0000116
Chris Lattnerbc68f692007-10-25 17:18:59 +0000117 return EndOff-StartOff;
Chris Lattner6fe8b272007-10-16 22:36:42 +0000118}
119
120
Chris Lattner3cfe3d32007-10-13 00:11:23 +0000121unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
122 unsigned &FileID) const {
Chris Lattner74db1682007-10-16 21:07:07 +0000123 std::pair<unsigned,unsigned> V = SourceMgr->getDecomposedFileLoc(Loc);
Chris Lattner3cfe3d32007-10-13 00:11:23 +0000124 FileID = V.first;
125 return V.second;
126}
127
128
Chris Lattner569faa62007-10-11 18:38:32 +0000129/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
130///
131RewriteBuffer &Rewriter::getEditBuffer(unsigned FileID) {
132 std::map<unsigned, RewriteBuffer>::iterator I =
133 RewriteBuffers.lower_bound(FileID);
134 if (I != RewriteBuffers.end() && I->first == FileID)
135 return I->second;
136 I = RewriteBuffers.insert(I, std::make_pair(FileID, RewriteBuffer()));
137
Chris Lattner74db1682007-10-16 21:07:07 +0000138 std::pair<const char*, const char*> MB = SourceMgr->getBufferData(FileID);
Chris Lattner569faa62007-10-11 18:38:32 +0000139 I->second.Initialize(MB.first, MB.second);
140
141 return I->second;
142}
143
Chris Lattner532e5742007-11-02 17:26:47 +0000144/// InsertText - Insert the specified string at the specified location in the
Chris Lattnerb8a1b042008-01-31 19:51:04 +0000145/// original buffer.
Ted Kremenek8d0368c2008-03-18 21:17:59 +0000146bool Rewriter::InsertText(SourceLocation Loc, const char *StrData,
147 unsigned StrLen, bool InsertAfter) {
Chris Lattnerb1548372008-01-31 19:37:57 +0000148 if (!isRewritable(Loc)) return true;
Chris Lattner532e5742007-11-02 17:26:47 +0000149 unsigned FileID;
150 unsigned StartOffs = getLocationOffsetAndFileID(Loc, FileID);
Ted Kremenek8d0368c2008-03-18 21:17:59 +0000151 getEditBuffer(FileID).InsertText(StartOffs, StrData, StrLen, InsertAfter);
Chris Lattnerb1548372008-01-31 19:37:57 +0000152 return false;
Chris Lattner532e5742007-11-02 17:26:47 +0000153}
154
Chris Lattnerb8a1b042008-01-31 19:51:04 +0000155/// RemoveText - Remove the specified text region.
156bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) {
157 if (!isRewritable(Start)) return true;
Chris Lattnercfd61c82007-10-16 22:51:17 +0000158 unsigned FileID;
159 unsigned StartOffs = getLocationOffsetAndFileID(Start, FileID);
160 getEditBuffer(FileID).RemoveText(StartOffs, Length);
Chris Lattnerb8a1b042008-01-31 19:51:04 +0000161 return false;
Chris Lattnercfd61c82007-10-16 22:51:17 +0000162}
Chris Lattner569faa62007-10-11 18:38:32 +0000163
Chris Lattnercfd61c82007-10-16 22:51:17 +0000164/// ReplaceText - This method replaces a range of characters in the input
165/// buffer with a new string. This is effectively a combined "remove/insert"
166/// operation.
Chris Lattnerb8a1b042008-01-31 19:51:04 +0000167bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
Chris Lattner569faa62007-10-11 18:38:32 +0000168 const char *NewStr, unsigned NewLength) {
Chris Lattnerb8a1b042008-01-31 19:51:04 +0000169 if (!isRewritable(Start)) return true;
Chris Lattner3cfe3d32007-10-13 00:11:23 +0000170 unsigned StartFileID;
171 unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
Chris Lattner569faa62007-10-11 18:38:32 +0000172
Chris Lattner3cfe3d32007-10-13 00:11:23 +0000173 getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength,
174 NewStr, NewLength);
Chris Lattnerb8a1b042008-01-31 19:51:04 +0000175 return false;
Chris Lattner569faa62007-10-11 18:38:32 +0000176}
Chris Lattnerbf0bfa62007-10-17 22:35:30 +0000177
178/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
179/// printer to generate the replacement code. This returns true if the input
180/// could not be rewritten, or false if successful.
181bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
182 // Measaure the old text.
183 int Size = getRangeSize(From->getSourceRange());
184 if (Size == -1)
185 return true;
186
187 // Get the new text.
188 std::ostringstream S;
189 To->printPretty(S);
190 const std::string &Str = S.str();
191
192 ReplaceText(From->getLocStart(), Size, &Str[0], Str.size());
193 return false;
194}
195
196