blob: 508f7996081aa3c72a92de44aac6a5779ba61336 [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;
Chris Lattner77cd2a02007-10-11 00:43:27 +000029 public:
Chris Lattner01c57482007-10-17 22:35:30 +000030 void Initialize(ASTContext &context, unsigned mainFileID) {
31 Context = &context;
32 SM = &Context->SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000033 MainFileID = mainFileID;
Chris Lattner01c57482007-10-17 22:35:30 +000034 Rewrite.setSourceMgr(Context->SourceMgr);
Chris Lattner77cd2a02007-10-11 00:43:27 +000035 }
36
37 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner8a12c272007-10-11 18:38:32 +000038
Chris Lattner2c64b7b2007-10-16 21:07:07 +000039 void HandleDeclInMainFile(Decl *D);
40 void RewriteInclude(SourceLocation Loc);
Chris Lattner311ff022007-10-16 22:36:42 +000041
42 void RewriteFunctionBody(Stmt *S);
43 void RewriteAtEncode(ObjCEncodeExpr *Exp);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000044
Chris Lattner8a12c272007-10-11 18:38:32 +000045 ~RewriteTest();
Chris Lattner77cd2a02007-10-11 00:43:27 +000046 };
47}
48
Chris Lattner8a12c272007-10-11 18:38:32 +000049ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +000050
Chris Lattner8a12c272007-10-11 18:38:32 +000051void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000052 // Two cases: either the decl could be in the main file, or it could be in a
53 // #included file. If the former, rewrite it now. If the later, check to see
54 // if we rewrote the #include/#import.
55 SourceLocation Loc = D->getLocation();
56 Loc = SM->getLogicalLoc(Loc);
57
58 // If this is for a builtin, ignore it.
59 if (Loc.isInvalid()) return;
60
61 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
62 return HandleDeclInMainFile(D);
63
64 RewriteInclude(Loc);
65}
66
67void RewriteTest::RewriteInclude(SourceLocation Loc) {
68 // Rip up the #include stack to the main file.
69 SourceLocation IncLoc = Loc, NextLoc = Loc;
70 do {
71 IncLoc = Loc;
72 Loc = SM->getLogicalLoc(NextLoc);
73 NextLoc = SM->getIncludeLoc(Loc);
74 } while (!NextLoc.isInvalid());
75
76 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
77 // IncLoc indicates the header that was included if it is useful.
78 IncLoc = SM->getLogicalLoc(IncLoc);
79 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
80 Loc == LastIncLoc)
81 return;
82 LastIncLoc = Loc;
83
84 unsigned IncCol = SM->getColumnNumber(Loc);
85 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
86
87 // Replace the #import with #include.
88 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
89}
90
91/// HandleDeclInMainFile - This is called for each top-level decl defined in the
92/// main file of the input.
93void RewriteTest::HandleDeclInMainFile(Decl *D) {
Chris Lattner311ff022007-10-16 22:36:42 +000094 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
95 if (Stmt *Body = FD->getBody())
96 RewriteFunctionBody(Body);
Chris Lattner2c64b7b2007-10-16 21:07:07 +000097 // Nothing yet.
Chris Lattner8a12c272007-10-11 18:38:32 +000098}
99
100
Chris Lattner311ff022007-10-16 22:36:42 +0000101void RewriteTest::RewriteFunctionBody(Stmt *S) {
102 // Handle specific things.
103 if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
104 return RewriteAtEncode(AtEncode);
105
106 // Otherwise, just rewrite all children.
107 for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
108 CI != E; ++CI)
Chris Lattner50754772007-10-17 21:28:00 +0000109 if (*CI)
110 RewriteFunctionBody(*CI);
Chris Lattner311ff022007-10-16 22:36:42 +0000111}
112
113void RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) {
Chris Lattner01c57482007-10-17 22:35:30 +0000114 // Create a new string expression.
115 QualType StrType = Context->getPointerType(Context->CharTy);
116 Expr *Replacement = new StringLiteral("foo", 3, false, StrType,
117 SourceLocation(), SourceLocation());
118 Rewrite.ReplaceStmt(Exp, Replacement);
119 delete Replacement;
Chris Lattner311ff022007-10-16 22:36:42 +0000120}
121
122
Chris Lattner8a12c272007-10-11 18:38:32 +0000123RewriteTest::~RewriteTest() {
Chris Lattner8a12c272007-10-11 18:38:32 +0000124 // Get the top-level buffer that this corresponds to.
125 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
126 const char *MainBufStart = MainBuf.first;
127 const char *MainBufEnd = MainBuf.second;
128
129 // Loop over the whole file, looking for tabs.
130 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
131 if (*BufPtr != '\t')
132 continue;
133
134 // Okay, we found a tab. This tab will turn into at least one character,
135 // but it depends on which 'virtual column' it is in. Compute that now.
136 unsigned VCol = 0;
137 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
138 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
139 ++VCol;
140
141 // Okay, now that we know the virtual column, we know how many spaces to
142 // insert. We assume 8-character tab-stops.
143 unsigned Spaces = 8-(VCol & 7);
144
145 // Get the location of the tab.
146 SourceLocation TabLoc =
147 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
148
149 // Rewrite the single tab character into a sequence of spaces.
Chris Lattner57c337d2007-10-13 00:46:29 +0000150 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
Chris Lattner8a12c272007-10-11 18:38:32 +0000151 }
152
153 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
154 // we are done.
155 if (const RewriteBuffer *RewriteBuf =
156 Rewrite.getRewriteBufferFor(MainFileID)) {
Chris Lattner7c239602007-10-13 00:11:23 +0000157 printf("Changed:\n");
158 std::string S(RewriteBuf->begin(), RewriteBuf->end());
159 printf("%s\n", S.c_str());
Chris Lattner8a12c272007-10-11 18:38:32 +0000160 } else {
161 printf("No changes\n");
162 }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000163}