blob: 8954a1981952f7576cd44ee6e76bb9691fc651e5 [file] [log] [blame]
Chris Lattner77cd2a02007-10-11 00:43:27 +00001//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000015#include "clang/Rewrite/Rewriter.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000016#include "clang/AST/AST.h"
17#include "clang/AST/ASTConsumer.h"
Chris Lattner8a12c272007-10-11 18:38:32 +000018#include "clang/Basic/SourceManager.h"
Chris Lattner77cd2a02007-10-11 00:43:27 +000019using namespace clang;
20
21
22namespace {
Chris Lattner8a12c272007-10-11 18:38:32 +000023 class RewriteTest : public ASTConsumer {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000024 Rewriter Rewrite;
Chris Lattner01c57482007-10-17 22:35:30 +000025 ASTContext *Context;
Chris Lattner77cd2a02007-10-11 00:43:27 +000026 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000027 unsigned MainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000028 SourceLocation LastIncLoc;
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000029 llvm::SmallVector<ObjcImplementationDecl *, 8> ClassImplementation;
30 llvm::SmallVector<ObjcCategoryImplDecl *, 8> CategoryImplementation;
31 static const int OBJC_ABI_VERSION =7 ;
Chris Lattner77cd2a02007-10-11 00:43:27 +000032 public:
Chris Lattner01c57482007-10-17 22:35:30 +000033 void Initialize(ASTContext &context, unsigned mainFileID) {
34 Context = &context;
35 SM = &Context->SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000036 MainFileID = mainFileID;
Chris Lattner01c57482007-10-17 22:35:30 +000037 Rewrite.setSourceMgr(Context->SourceMgr);
Chris Lattner77cd2a02007-10-11 00:43:27 +000038 }
39
40 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner8a12c272007-10-11 18:38:32 +000041
Chris Lattner2c64b7b2007-10-16 21:07:07 +000042 void HandleDeclInMainFile(Decl *D);
43 void RewriteInclude(SourceLocation Loc);
Chris Lattner311ff022007-10-16 22:36:42 +000044
45 void RewriteFunctionBody(Stmt *S);
46 void RewriteAtEncode(ObjCEncodeExpr *Exp);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000047
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +000048 void WriteObjcMetaData();
49
Chris Lattner8a12c272007-10-11 18:38:32 +000050 ~RewriteTest();
Chris Lattner77cd2a02007-10-11 00:43:27 +000051 };
52}
53
Chris Lattner8a12c272007-10-11 18:38:32 +000054ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +000055
Chris Lattner8a12c272007-10-11 18:38:32 +000056void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000057 // Two cases: either the decl could be in the main file, or it could be in a
58 // #included file. If the former, rewrite it now. If the later, check to see
59 // if we rewrote the #include/#import.
60 SourceLocation Loc = D->getLocation();
61 Loc = SM->getLogicalLoc(Loc);
62
63 // If this is for a builtin, ignore it.
64 if (Loc.isInvalid()) return;
65
66 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
67 return HandleDeclInMainFile(D);
68
69 RewriteInclude(Loc);
70}
71
72void RewriteTest::RewriteInclude(SourceLocation Loc) {
73 // Rip up the #include stack to the main file.
74 SourceLocation IncLoc = Loc, NextLoc = Loc;
75 do {
76 IncLoc = Loc;
77 Loc = SM->getLogicalLoc(NextLoc);
78 NextLoc = SM->getIncludeLoc(Loc);
79 } while (!NextLoc.isInvalid());
80
81 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
82 // IncLoc indicates the header that was included if it is useful.
83 IncLoc = SM->getLogicalLoc(IncLoc);
84 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
85 Loc == LastIncLoc)
86 return;
87 LastIncLoc = Loc;
88
89 unsigned IncCol = SM->getColumnNumber(Loc);
90 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
91
92 // Replace the #import with #include.
93 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
94}
95
96/// HandleDeclInMainFile - This is called for each top-level decl defined in the
97/// main file of the input.
98void RewriteTest::HandleDeclInMainFile(Decl *D) {
Chris Lattner311ff022007-10-16 22:36:42 +000099 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
100 if (Stmt *Body = FD->getBody())
101 RewriteFunctionBody(Body);
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000102
103 if (ObjcImplementationDecl *CI = dyn_cast<ObjcImplementationDecl>(D))
104 ClassImplementation.push_back(CI);
105 else if (ObjcCategoryImplDecl *CI = dyn_cast<ObjcCategoryImplDecl>(D))
106 CategoryImplementation.push_back(CI);
Chris Lattner2c64b7b2007-10-16 21:07:07 +0000107 // Nothing yet.
Chris Lattner8a12c272007-10-11 18:38:32 +0000108}
109
110
Chris Lattner311ff022007-10-16 22:36:42 +0000111void RewriteTest::RewriteFunctionBody(Stmt *S) {
112 // Handle specific things.
113 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
114 return RewriteAtEncode(AtEncode);
115
116 // Otherwise, just rewrite all children.
117 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
118 CI != E; ++CI)
Chris Lattner50754772007-10-17 21:28:00 +0000119 if (*CI)
120 RewriteFunctionBody(*CI);
Chris Lattner311ff022007-10-16 22:36:42 +0000121}
122
123void RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000124 // Create a new string expression.
125 QualType StrType = Context->getPointerType(Context->CharTy);
126 Expr *Replacement = new StringLiteral("foo", 3, false, StrType,
127 SourceLocation(), SourceLocation());
128 Rewrite.ReplaceStmt(Exp, Replacement);
129 delete Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000130}
131
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000132void RewriteTest::WriteObjcMetaData() {
133 int ClsDefCount = ClassImplementation.size();
134 int CatDefCount = CategoryImplementation.size();
135 if (ClsDefCount == 0 && CatDefCount == 0)
136 return;
137 // Write objc_symtab metadata
138 /*
139 struct _objc_symtab
140 {
141 long sel_ref_cnt;
142 SEL *refs;
143 short cls_def_cnt;
144 short cat_def_cnt;
145 void *defs[cls_def_cnt + cat_def_cnt];
146 };
147 */
148
149 printf("\nstruct _objc_symtab {\n");
150 printf("\tlong sel_ref_cnt;\n");
151 printf("\tSEL *refs;\n");
152 printf("\tshort cls_def_cnt;\n");
153 printf("\tshort cat_def_cnt;\n");
154 printf("\tvoid *defs[%d];\n", ClsDefCount + CatDefCount);
155 printf("};\n\n");
156
157 printf("static struct _objc_symtab "
158 "_OBJC_SYMBOLS __attribute__ ((section (\"__OBJC, __symbols\")))= {\n");
159 printf("\t0, 0, %d, %d\n", ClsDefCount, CatDefCount);
160 for (int i = 0; i < ClsDefCount; i++)
161 printf("\t,_OBJC_CLASS_%s\n", ClassImplementation[i]->getName());
162
163 for (int i = 0; i < CatDefCount; i++)
164 printf("\t,_OBJC_CATEGORY_%s_%s\n",
165 CategoryImplementation[i]->getClassInterface()->getName(),
166 CategoryImplementation[i]->getName());
167
168 printf("};\n\n");
169
170 // Write objc_module metadata
171
172 /*
173 struct _objc_module {
174 long version;
175 long size;
176 const char *name;
177 struct _objc_symtab *symtab;
178 }
179 */
180
181 printf("\nstruct _objc_module {\n");
182 printf("\tlong version;\n");
183 printf("\tlong size;\n");
184 printf("\tconst char *name;\n");
185 printf("\tstruct _objc_symtab *symtab;");
186 printf("};\n\n");
187 printf("static struct _objc_module "
188 "_OBJC_MODULES __attribute__ ((section (\"__OBJC, __module_info\")))= {\n");
189 printf("\t%d, %d, \"\", &_OBJC_SYMBOLS\n", OBJC_ABI_VERSION, 16);
190 printf("};\n\n");
191}
Chris Lattner311ff022007-10-16 22:36:42 +0000192
Chris Lattner8a12c272007-10-11 18:38:32 +0000193RewriteTest::~RewriteTest() {
Chris Lattner8a12c272007-10-11 18:38:32 +0000194 // Get the top-level buffer that this corresponds to.
195 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
196 const char *MainBufStart = MainBuf.first;
197 const char *MainBufEnd = MainBuf.second;
198
199 // Loop over the whole file, looking for tabs.
200 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
201 if (*BufPtr != '\t')
202 continue;
203
204 // Okay, we found a tab. This tab will turn into at least one character,
205 // but it depends on which 'virtual column' it is in. Compute that now.
206 unsigned VCol = 0;
207 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
208 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
209 ++VCol;
210
211 // Okay, now that we know the virtual column, we know how many spaces to
212 // insert. We assume 8-character tab-stops.
213 unsigned Spaces = 8-(VCol & 7);
214
215 // Get the location of the tab.
216 SourceLocation TabLoc =
217 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
218
219 // Rewrite the single tab character into a sequence of spaces.
Chris Lattner57c337d2007-10-13 00:46:29 +0000220 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
Chris Lattner8a12c272007-10-11 18:38:32 +0000221 }
222
223 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
224 // we are done.
225 if (const RewriteBuffer *RewriteBuf =
226 Rewrite.getRewriteBufferFor(MainFileID)) {
Chris Lattner7c239602007-10-13 00:11:23 +0000227 printf("Changed:\n");
228 std::string S(RewriteBuf->begin(), RewriteBuf->end());
229 printf("%s\n", S.c_str());
Chris Lattner8a12c272007-10-11 18:38:32 +0000230 } else {
231 printf("No changes\n");
232 }
Fariborz Jahanian545b9ae2007-10-18 19:23:00 +0000233 // Rewrite Objective-c meta data*
234 WriteObjcMetaData();
Chris Lattner77cd2a02007-10-11 00:43:27 +0000235}