Skip to content

Commit 109f399

Browse files
committed
initial commit for LibTooling tutorial files
0 parents  commit 109f399

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

Example.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#include "clang/Driver/Options.h"
2+
#include "clang/AST/AST.h"
3+
#include "clang/AST/ASTContext.h"
4+
#include "clang/AST/ASTConsumer.h"
5+
#include "clang/AST/RecursiveASTVisitor.h"
6+
#include "clang/Frontend/ASTConsumers.h"
7+
#include "clang/Frontend/FrontendActions.h"
8+
#include "clang/Frontend/CompilerInstance.h"
9+
#include "clang/Tooling/CommonOptionsParser.h"
10+
#include "clang/Tooling/Tooling.h"
11+
#include "clang/Rewrite/Core/Rewriter.h"
12+
13+
using namespace std;
14+
using namespace clang;
15+
using namespace clang::driver;
16+
using namespace clang::tooling;
17+
using namespace llvm;
18+
19+
Rewriter rewriter;
20+
int numFunctions = 0;
21+
22+
23+
class ExampleVisitor : public RecursiveASTVisitor<ExampleVisitor> {
24+
private:
25+
ASTContext *astContext; // used for getting additional AST info
26+
27+
public:
28+
explicit ExampleVisitor(CompilerInstance *CI)
29+
: astContext(&(CI->getASTContext())) // initialize private members
30+
{
31+
rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts());
32+
}
33+
34+
virtual bool VisitFunctionDecl(FunctionDecl *func) {
35+
numFunctions++;
36+
string funcName = func->getNameInfo().getName().getAsString();
37+
if (funcName == "do_math") {
38+
rewriter.ReplaceText(func->getLocation(), funcName.length(), "add5");
39+
errs() << "** Rewrote function def: " << funcName << "\n";
40+
}
41+
return true;
42+
}
43+
44+
virtual bool VisitStmt(Stmt *st) {
45+
if (ReturnStmt *ret = dyn_cast<ReturnStmt>(st)) {
46+
rewriter.ReplaceText(ret->getRetValue()->getLocStart(), 6, "val");
47+
errs() << "** Rewrote ReturnStmt\n";
48+
}
49+
if (CallExpr *call = dyn_cast<CallExpr>(st)) {
50+
rewriter.ReplaceText(call->getLocStart(), 7, "add5");
51+
errs() << "** Rewrote function call\n";
52+
}
53+
return true;
54+
}
55+
56+
/*
57+
virtual bool VisitReturnStmt(ReturnStmt *ret) {
58+
rewriter.ReplaceText(ret->getRetValue()->getLocStart(), 6, "val");
59+
errs() << "** Rewrote ReturnStmt\n";
60+
return true;
61+
}
62+
63+
virtual bool VisitCallExpr(CallExpr *call) {
64+
rewriter.ReplaceText(call->getLocStart(), 7, "add5");
65+
errs() << "** Rewrote function call\n";
66+
return true;
67+
}
68+
*/
69+
};
70+
71+
72+
73+
class ExampleASTConsumer : public ASTConsumer {
74+
private:
75+
ExampleVisitor *visitor; // doesn't have to be private
76+
77+
public:
78+
// override the constructor in order to pass CI
79+
explicit ExampleASTConsumer(CompilerInstance *CI)
80+
: visitor(new ExampleVisitor(CI)) // initialize the visitor
81+
{ }
82+
83+
// override this to call our ExampleVisitor on the entire source file
84+
virtual void HandleTranslationUnit(ASTContext &Context) {
85+
/* we can use ASTContext to get the TranslationUnitDecl, which is
86+
a single Decl that collectively represents the entire source file */
87+
visitor->TraverseDecl(Context.getTranslationUnitDecl());
88+
}
89+
90+
/*
91+
// override this to call our ExampleVisitor on each top-level Decl
92+
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
93+
// a DeclGroupRef may have multiple Decls, so we iterate through each one
94+
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; i++) {
95+
Decl *D = *i;
96+
visitor->TraverseDecl(D); // recursively visit each AST node in Decl "D"
97+
}
98+
return true;
99+
}
100+
*/
101+
};
102+
103+
104+
105+
class ExampleFrontendAction : public ASTFrontendAction {
106+
public:
107+
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, StringRef file) {
108+
return new ExampleASTConsumer(&CI); // pass CI pointer to ASTConsumer
109+
}
110+
};
111+
112+
113+
114+
int main(int argc, const char **argv) {
115+
// parse the command-line args passed to your code
116+
CommonOptionsParser op(argc, argv);
117+
// create a new Clang Tool instance (a LibTooling environment)
118+
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
119+
120+
// run the Clang Tool, creating a new FrontendAction (explained below)
121+
int result = Tool.run(newFrontendActionFactory<ExampleFrontendAction>());
122+
123+
errs() << "\nFound " << numFunctions << " functions.\n\n";
124+
// print out the rewritten source code ("rewriter" is a global var.)
125+
rewriter.getEditBuffer(rewriter.getSourceMgr().getMainFileID()).write(errs());
126+
return result;
127+
}

Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CLANG_LEVEL := ../..
2+
3+
TOOLNAME = example #the name of your tool's executable
4+
5+
SOURCES := Example.cpp #the Clang source files you want to compile
6+
7+
include $(CLANG_LEVEL)/../../Makefile.config
8+
9+
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
10+
11+
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
12+
clangTooling.a clangParse.a clangSema.a \
13+
clangAnalysis.a clangRewriteFrontend.a clangRewriteCore.a \
14+
clangEdit.a clangAST.a clangLex.a clangBasic.a
15+
16+
include $(CLANG_LEVEL)/Makefile

run_example.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
LLVM_DIR=~/static_analysis/llvm/ #the location of your llvm dir
3+
$LLVM_DIR/Debug+Asserts/bin/example test.c --

test.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void do_math(int *x) {
2+
*x += 5;
3+
}
4+
5+
int main(void) {
6+
int result = -1, val = 4;
7+
do_math(&val);
8+
return result;
9+
}

0 commit comments

Comments
 (0)