blob: 5b27f55190f6076075128c38ed08b002b6eaea05 [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 Lattner77cd2a02007-10-11 00:43:27 +000025 SourceManager *SM;
Chris Lattner8a12c272007-10-11 18:38:32 +000026 unsigned MainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000027 SourceLocation LastIncLoc;
Chris Lattner77cd2a02007-10-11 00:43:27 +000028 public:
Chris Lattner8a12c272007-10-11 18:38:32 +000029 void Initialize(ASTContext &Context, unsigned mainFileID) {
Chris Lattner77cd2a02007-10-11 00:43:27 +000030 SM = &Context.SourceMgr;
Chris Lattner8a12c272007-10-11 18:38:32 +000031 MainFileID = mainFileID;
Chris Lattner2c64b7b2007-10-16 21:07:07 +000032 Rewrite.setSourceMgr(Context.SourceMgr);
Chris Lattner77cd2a02007-10-11 00:43:27 +000033 }
34
35 virtual void HandleTopLevelDecl(Decl *D);
Chris Lattner8a12c272007-10-11 18:38:32 +000036
Chris Lattner2c64b7b2007-10-16 21:07:07 +000037 void HandleDeclInMainFile(Decl *D);
38 void RewriteInclude(SourceLocation Loc);
39
Chris Lattner8a12c272007-10-11 18:38:32 +000040 ~RewriteTest();
Chris Lattner77cd2a02007-10-11 00:43:27 +000041 };
42}
43
Chris Lattner8a12c272007-10-11 18:38:32 +000044ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
Chris Lattner77cd2a02007-10-11 00:43:27 +000045
Chris Lattner8a12c272007-10-11 18:38:32 +000046void RewriteTest::HandleTopLevelDecl(Decl *D) {
Chris Lattner2c64b7b2007-10-16 21:07:07 +000047 // Two cases: either the decl could be in the main file, or it could be in a
48 // #included file. If the former, rewrite it now. If the later, check to see
49 // if we rewrote the #include/#import.
50 SourceLocation Loc = D->getLocation();
51 Loc = SM->getLogicalLoc(Loc);
52
53 // If this is for a builtin, ignore it.
54 if (Loc.isInvalid()) return;
55
56 if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
57 return HandleDeclInMainFile(D);
58
59 RewriteInclude(Loc);
60}
61
62void RewriteTest::RewriteInclude(SourceLocation Loc) {
63 // Rip up the #include stack to the main file.
64 SourceLocation IncLoc = Loc, NextLoc = Loc;
65 do {
66 IncLoc = Loc;
67 Loc = SM->getLogicalLoc(NextLoc);
68 NextLoc = SM->getIncludeLoc(Loc);
69 } while (!NextLoc.isInvalid());
70
71 // Loc is now the location of the #include filename "foo" or <foo/bar.h>.
72 // IncLoc indicates the header that was included if it is useful.
73 IncLoc = SM->getLogicalLoc(IncLoc);
74 if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
75 Loc == LastIncLoc)
76 return;
77 LastIncLoc = Loc;
78
79 unsigned IncCol = SM->getColumnNumber(Loc);
80 SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
81
82 // Replace the #import with #include.
83 Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
84}
85
86/// HandleDeclInMainFile - This is called for each top-level decl defined in the
87/// main file of the input.
88void RewriteTest::HandleDeclInMainFile(Decl *D) {
89 // Nothing yet.
Chris Lattner8a12c272007-10-11 18:38:32 +000090}
91
92
Chris Lattner8a12c272007-10-11 18:38:32 +000093RewriteTest::~RewriteTest() {
Chris Lattner8a12c272007-10-11 18:38:32 +000094 // Get the top-level buffer that this corresponds to.
95 std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
96 const char *MainBufStart = MainBuf.first;
97 const char *MainBufEnd = MainBuf.second;
98
99 // Loop over the whole file, looking for tabs.
100 for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
101 if (*BufPtr != '\t')
102 continue;
103
104 // Okay, we found a tab. This tab will turn into at least one character,
105 // but it depends on which 'virtual column' it is in. Compute that now.
106 unsigned VCol = 0;
107 while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
108 BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
109 ++VCol;
110
111 // Okay, now that we know the virtual column, we know how many spaces to
112 // insert. We assume 8-character tab-stops.
113 unsigned Spaces = 8-(VCol & 7);
114
115 // Get the location of the tab.
116 SourceLocation TabLoc =
117 SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
118
119 // Rewrite the single tab character into a sequence of spaces.
Chris Lattner57c337d2007-10-13 00:46:29 +0000120 Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
Chris Lattner8a12c272007-10-11 18:38:32 +0000121 }
122
123 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
124 // we are done.
125 if (const RewriteBuffer *RewriteBuf =
126 Rewrite.getRewriteBufferFor(MainFileID)) {
Chris Lattner7c239602007-10-13 00:11:23 +0000127 printf("Changed:\n");
128 std::string S(RewriteBuf->begin(), RewriteBuf->end());
129 printf("%s\n", S.c_str());
Chris Lattner8a12c272007-10-11 18:38:32 +0000130 } else {
131 printf("No changes\n");
132 }
Chris Lattner77cd2a02007-10-11 00:43:27 +0000133}