1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
//===--- Rewriter.h - Code rewriting interface ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the Rewriter class, which is used for code
// transformations.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_REWRITER_H
#define LLVM_CLANG_REWRITER_H
#include "clang/Basic/SourceLocation.h"
#include <map>
#include <vector>
namespace clang {
class SourceManager;
class Rewriter;
/// SourceDelta - As code in the original input buffer is added and deleted,
/// SourceDelta records are used to keep track of how the input SourceLocation
/// object is mapped into the output buffer.
struct SourceDelta {
unsigned FileLoc;
int Delta;
static SourceDelta get(unsigned Loc, int D) {
SourceDelta Delta;
Delta.FileLoc = Loc;
Delta.Delta = D;
return Delta;
}
};
/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
/// input with modifications get a new RewriteBuffer associated with them. The
/// RewriteBuffer captures the modified text itself as well as information used
/// to map between SourceLocation's in the original input and offsets in the
/// RewriteBuffer. For example, if text is inserted into the buffer, any
/// locations after the insertion point have to be mapped.
class RewriteBuffer {
friend class Rewriter;
/// Deltas - Keep track of all the deltas in the source code due to insertions
/// and deletions. These are kept in sorted order based on the FileLoc.
std::vector<SourceDelta> Deltas;
/// Buffer - This is the actual buffer itself. Note that using a vector or
/// string is a horribly inefficient way to do this, we should use a rope
/// instead.
std::vector<char> Buffer;
public:
typedef std::vector<char>::const_iterator iterator;
iterator begin() const { return Buffer.begin(); }
iterator end() const { return Buffer.end(); }
private: // Methods only usable by Rewriter.
/// Initialize - Start this rewrite buffer out with a copy of the unmodified
/// input buffer.
void Initialize(const char *BufStart, const char *BufEnd) {
Buffer.assign(BufStart, BufEnd);
}
/// getMappedOffset - Given an offset into the original SourceBuffer that this
/// RewriteBuffer is based on, map it into the offset space of the
/// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a
/// position where text is inserted, the location returned will be after any
/// inserted text at the position.
unsigned getMappedOffset(unsigned OrigOffset, bool AfterInserts = false)const;
/// AddDelta - When a change is made that shifts around the text buffer, this
/// method is used to record that info.
void AddDelta(unsigned OrigOffset, int Change);
/// RemoveText - Remove the specified text.
void RemoveText(unsigned OrigOffset, unsigned Size);
/// InsertText - Insert some text at the specified point, where the offset in
/// the buffer is specified relative to the original SourceBuffer.
///
/// TODO: Consider a bool to indicate whether the text is inserted 'before' or
/// after the atomic point: i.e. whether the atomic point is moved to after
/// the inserted text or not.
void InsertText(unsigned OrigOffset, const char *StrData, unsigned StrLen);
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
const char *NewStr, unsigned NewLength);
};
/// Rewriter - This is the main interface to the rewrite buffers. Its primary
/// job is to dispatch high-level requests to the low-level RewriteBuffers that
/// are involved.
class Rewriter {
SourceManager *SourceMgr;
std::map<unsigned, RewriteBuffer> RewriteBuffers;
public:
explicit Rewriter(SourceManager &SM) : SourceMgr(&SM) {}
explicit Rewriter() : SourceMgr(0) {}
void setSourceMgr(SourceManager &SM) { SourceMgr = &SM; }
/// isRewritable - Return true if this location is a raw file location, which
/// is rewritable. Locations from macros, etc are not rewritable.
static bool isRewritable(SourceLocation Loc) {
return Loc.isFileID();
}
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method is only valid on rewritable source
/// locations.
void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
/// RemoveText - Remove the specified text region. This method is only valid
/// on rewritable source locations.
void RemoveText(SourceLocation Start, SourceLocation End);
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
void ReplaceText(SourceLocation Start, unsigned OrigLength,
const char *NewStr, unsigned NewLength);
// TODO: Replace Stmt/Expr with another. Return bool to indicate whether the
// locations were rewritable.
/// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
/// If no modification has been made to it, return null.
const RewriteBuffer *getRewriteBufferFor(unsigned FileID) const {
std::map<unsigned, RewriteBuffer>::const_iterator I =
RewriteBuffers.find(FileID);
return I == RewriteBuffers.end() ? 0 : &I->second;
}
private:
RewriteBuffer &getEditBuffer(unsigned FileID);
unsigned getLocationOffsetAndFileID(SourceLocation Loc,
unsigned &FileID) const;
};
} // end namespace clang
#endif
|