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