Reparse rewritten source

Hello gentlemen,

I’m trying to write a clang tool which will instrument source code.

I’m using a FrontEndAction, an ASTConsumer and finally a RecursiveASTVisitor, which will use a Rewriter to update the source code.

Now, I’d like to add another pass with an updated AST (which should match the rewritten source code), and I can’t get how to do this (I searched for a long time before posting here).

I could, of course, dump new source code on the file system, and then parse the new file. But this method is rather inelegant, probably time consuming and inappropriate for my needs.

I’d be grateful to anyone helping me.

Nicolas

P.S.

Here’s a minimalist source code I’m based on:

static llvm::cl::OptionCategory ToolingSampleCategory(“Test”);

class myASTVisitor: public clang::RecursiveASTVisitor
{
clang::CompilerInstance& ci__;
clang::Rewriter& rewriter__;

public:
myASTVisitor(clang::CompilerInstance& ci, clang::Rewriter& r): ci__(ci), rewriter__(r) {}

bool VisitDeclStmt(clang::DeclStmt* ds)
{
// Code which involves the rewriter__
return true;
}
};

class ASTConsumer : public clang::ASTConsumer
{
clang::CompilerInstance& ci__;
clang::StringRef file__;
clang::Rewriter& rewriter__;

public:
ASTConsumer(clang::CompilerInstance& ci, clang::StringRef file, clang::Rewriter& rw): ci__(ci), file__(file), rewriter__(rw) {}

bool HandleTopLevelDecl(clang::DeclGroupRef DR) override {
for (clang::DeclGroupRef::iterator it = DR.begin(); it != DR.end(); ++it) {
clang::FunctionDecl* fd = clang::castclang::FunctionDecl(*it);
if (fd != NULL) {
myASTVisitor visitor(ci__, rewriter__);
visitor.TraverseDecl(fd);
}
}
return true;
}
};

class FrontendAction : public clang::ASTFrontendAction
{
clang::Rewriter rewriter__;
clang::CompilerInstance* ci__;

public:
FrontendAction() {}

void EndSourceFileAction() override {
rewriter__.getEditBuffer(ci__->getSourceManager().getMainFileID()).write(llvm::outs());

// write to stdout for now, but there (only if appropriate), I would like

// to run a second pass, using another ASTVisitor/ASTConsumer

// on the new AST from the rewritten sources

}

std::unique_ptrclang::ASTConsumer CreateASTConsumer(clang::CompilerInstance& CI, clang::StringRef file) override {
ci__ = &CI;
rewriter__.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
return std::unique_ptrclang::ASTConsumer(new ASTConsumer(CI, file, rewriter__));
}
};

int main(int argc, const char** argv)
{
clang::tooling::CommonOptionsParser op(argc, argv, ToolingSampleCategory);
clang::tooling::ClangTool Tool(op.getCompilations(), op.getSourcePathList());

return Tool.run(clang::tooling::newFrontendActionFactory().get());
}

Hi Nicolas,

We had the similar problem in clang-include-fixer where we need to replace the content of a file without actually writing new content to file system, and we use [ClangTool::mapVirtualFile](http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1ClangTool.html#a2fef9bcf06819ffb9418560996ff71c7) as an workaround. I hope this would help.

Cheers,
Eric

Hi Eric,

I have to instantiate and initialize a second clang::tooling::ClangTool object (I can live with it), but it works like a charm.

Thank you very much,

Nicolas