2007-10-11 08:43:27 +08:00
|
|
|
//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Hacks and fun related to the code rewriter.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ASTConsumers.h"
|
2007-10-12 02:38:32 +08:00
|
|
|
#include "clang/Rewrite/Rewriter.h"
|
2007-10-11 08:43:27 +08:00
|
|
|
#include "clang/AST/AST.h"
|
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2007-10-12 02:38:32 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2007-10-11 08:43:27 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
2007-10-12 02:38:32 +08:00
|
|
|
class RewriteTest : public ASTConsumer {
|
2007-10-17 05:07:07 +08:00
|
|
|
Rewriter Rewrite;
|
2007-10-11 08:43:27 +08:00
|
|
|
SourceManager *SM;
|
2007-10-12 02:38:32 +08:00
|
|
|
unsigned MainFileID;
|
2007-10-17 05:07:07 +08:00
|
|
|
SourceLocation LastIncLoc;
|
2007-10-11 08:43:27 +08:00
|
|
|
public:
|
2007-10-12 02:38:32 +08:00
|
|
|
void Initialize(ASTContext &Context, unsigned mainFileID) {
|
2007-10-11 08:43:27 +08:00
|
|
|
SM = &Context.SourceMgr;
|
2007-10-12 02:38:32 +08:00
|
|
|
MainFileID = mainFileID;
|
2007-10-17 05:07:07 +08:00
|
|
|
Rewrite.setSourceMgr(Context.SourceMgr);
|
2007-10-11 08:43:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void HandleTopLevelDecl(Decl *D);
|
2007-10-12 02:38:32 +08:00
|
|
|
|
2007-10-17 05:07:07 +08:00
|
|
|
void HandleDeclInMainFile(Decl *D);
|
|
|
|
void RewriteInclude(SourceLocation Loc);
|
|
|
|
|
2007-10-12 02:38:32 +08:00
|
|
|
~RewriteTest();
|
2007-10-11 08:43:27 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2007-10-12 02:38:32 +08:00
|
|
|
ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); }
|
2007-10-11 08:43:27 +08:00
|
|
|
|
2007-10-12 02:38:32 +08:00
|
|
|
void RewriteTest::HandleTopLevelDecl(Decl *D) {
|
2007-10-17 05:07:07 +08:00
|
|
|
// Two cases: either the decl could be in the main file, or it could be in a
|
|
|
|
// #included file. If the former, rewrite it now. If the later, check to see
|
|
|
|
// if we rewrote the #include/#import.
|
|
|
|
SourceLocation Loc = D->getLocation();
|
|
|
|
Loc = SM->getLogicalLoc(Loc);
|
|
|
|
|
|
|
|
// If this is for a builtin, ignore it.
|
|
|
|
if (Loc.isInvalid()) return;
|
|
|
|
|
|
|
|
if (SM->getDecomposedFileLoc(Loc).first == MainFileID)
|
|
|
|
return HandleDeclInMainFile(D);
|
|
|
|
|
|
|
|
RewriteInclude(Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RewriteTest::RewriteInclude(SourceLocation Loc) {
|
|
|
|
// Rip up the #include stack to the main file.
|
|
|
|
SourceLocation IncLoc = Loc, NextLoc = Loc;
|
|
|
|
do {
|
|
|
|
IncLoc = Loc;
|
|
|
|
Loc = SM->getLogicalLoc(NextLoc);
|
|
|
|
NextLoc = SM->getIncludeLoc(Loc);
|
|
|
|
} while (!NextLoc.isInvalid());
|
|
|
|
|
|
|
|
// Loc is now the location of the #include filename "foo" or <foo/bar.h>.
|
|
|
|
// IncLoc indicates the header that was included if it is useful.
|
|
|
|
IncLoc = SM->getLogicalLoc(IncLoc);
|
|
|
|
if (SM->getDecomposedFileLoc(Loc).first != MainFileID ||
|
|
|
|
Loc == LastIncLoc)
|
|
|
|
return;
|
|
|
|
LastIncLoc = Loc;
|
|
|
|
|
|
|
|
unsigned IncCol = SM->getColumnNumber(Loc);
|
|
|
|
SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1);
|
|
|
|
|
|
|
|
// Replace the #import with #include.
|
|
|
|
Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include "));
|
2007-10-12 02:38:32 +08:00
|
|
|
}
|
|
|
|
|
2007-10-17 05:07:07 +08:00
|
|
|
/// HandleDeclInMainFile - This is called for each top-level decl defined in the
|
|
|
|
/// main file of the input.
|
|
|
|
void RewriteTest::HandleDeclInMainFile(Decl *D) {
|
|
|
|
// Nothing yet.
|
|
|
|
}
|
2007-10-12 02:38:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
RewriteTest::~RewriteTest() {
|
|
|
|
// Get the top-level buffer that this corresponds to.
|
|
|
|
std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
|
|
|
|
const char *MainBufStart = MainBuf.first;
|
|
|
|
const char *MainBufEnd = MainBuf.second;
|
|
|
|
|
|
|
|
// Loop over the whole file, looking for tabs.
|
|
|
|
for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
|
|
|
|
if (*BufPtr != '\t')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Okay, we found a tab. This tab will turn into at least one character,
|
|
|
|
// but it depends on which 'virtual column' it is in. Compute that now.
|
|
|
|
unsigned VCol = 0;
|
|
|
|
while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
|
|
|
|
BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
|
|
|
|
++VCol;
|
|
|
|
|
|
|
|
// Okay, now that we know the virtual column, we know how many spaces to
|
|
|
|
// insert. We assume 8-character tab-stops.
|
|
|
|
unsigned Spaces = 8-(VCol & 7);
|
|
|
|
|
|
|
|
// Get the location of the tab.
|
|
|
|
SourceLocation TabLoc =
|
|
|
|
SourceLocation::getFileLoc(MainFileID, BufPtr-MainBufStart);
|
|
|
|
|
|
|
|
// Rewrite the single tab character into a sequence of spaces.
|
2007-10-13 08:46:29 +08:00
|
|
|
Rewrite.ReplaceText(TabLoc, 1, " ", Spaces);
|
2007-10-12 02:38:32 +08:00
|
|
|
}
|
2007-10-11 08:43:27 +08:00
|
|
|
|
2007-10-12 02:38:32 +08:00
|
|
|
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
|
|
|
|
// we are done.
|
|
|
|
if (const RewriteBuffer *RewriteBuf =
|
|
|
|
Rewrite.getRewriteBufferFor(MainFileID)) {
|
2007-10-13 08:11:23 +08:00
|
|
|
printf("Changed:\n");
|
|
|
|
std::string S(RewriteBuf->begin(), RewriteBuf->end());
|
|
|
|
printf("%s\n", S.c_str());
|
2007-10-12 02:38:32 +08:00
|
|
|
} else {
|
|
|
|
printf("No changes\n");
|
|
|
|
}
|
2007-10-11 08:43:27 +08:00
|
|
|
}
|