citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

commit 14979e33bd59b1954f7e3a1d6346d7164ca31c7a
parent d5f4672cae53e239fea472038bfde568842e677f
Author: kyle <kyle@getaddrinfo.net>
Date:   Thu, 29 Oct 2015 19:06:02 -0600

instrument: refactor astvisitor

- rename MyASTVisitor -> instrumenter
- move member function definitions out of class declaration
- regress declaration coverage
- add funtion call coverage
- generally switch from "linus[xx] = 1, xxx" to "(lines[xx] = 1, xxx)"

Diffstat:
Minstrument/instrument.cpp | 182++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mtests/fibonacci/instrumented.c | 30+++++++++++++++---------------
Mtests/hello_world/instrumented.c | 4++--
Mtests/if_statement/instrumented.c | 16++++++++--------
Mtests/while_loops/instrumented.c | 6+++---
5 files changed, 125 insertions(+), 113 deletions(-)

diff --git a/instrument/instrument.cpp b/instrument/instrument.cpp @@ -18,6 +18,7 @@ #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "clang/Rewrite/Core/Rewriter.h" @@ -29,105 +30,116 @@ using namespace clang::tooling; static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample"); + // By implementing RecursiveASTVisitor, we can specify which AST nodes // we're interested in by overriding relevant methods. -class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> { +class instrumenter : public RecursiveASTVisitor<instrumenter> { public: - MyASTVisitor(Rewriter &R) : TheRewriter(R) {} + instrumenter(Rewriter &R) : TheRewriter(R), SM(R.getSourceMgr()) {} - bool VisitVarDecl(VarDecl *d) { - // std::cout << "HERE" << std::endl; - return true; - } - bool VisitStmt(Stmt *s) { - std::stringstream ss; - SourceManager &SM = TheRewriter.getSourceMgr(); - unsigned line = SM.getPresumedLineNumber(s->getLocStart()); + bool VisitVarDecl(VarDecl *d); + bool VisitStmt(Stmt *s); + bool VisitFunctionDecl(FunctionDecl *f); - ss << "lines[" << line << "] = 1"; +private: + Rewriter &TheRewriter; + SourceManager &SM; + LangOptions lopt; - if (isa<IfStmt>(s)) { - IfStmt *IfStatement = cast<IfStmt>(s); - Stmt *Cond = IfStatement->getCond(); - ss << ", "; - TheRewriter.InsertTextBefore(Cond->getLocStart(), - ss.str()); - } - else if (isa<ForStmt>(s)) { - ForStmt *ForStatement = cast<ForStmt>(s); - Stmt *Cond = ForStatement->getCond(); - ss << ", "; - TheRewriter.InsertTextAfter(Cond->getLocStart(), - ss.str()); - } - else if (isa<ReturnStmt>(s)) { - ReturnStmt *ReturnStatement = cast<ReturnStmt>(s); - Expr *RetValue = ReturnStatement->getRetValue(); - ss << ", "; - TheRewriter.InsertTextBefore(RetValue->getLocStart(), - ss.str()); - } - else if (isa<WhileStmt>(s)) { - WhileStmt *WhileStatement = cast<WhileStmt>(s); - Stmt *Cond = WhileStatement->getCond(); - ss << ", "; - TheRewriter.InsertTextBefore(Cond->getLocStart(), - ss.str()); - } - else if (isa<BreakStmt>(s) || isa<ContinueStmt>(s) || - isa<DeclStmt>(s) || isa<SwitchStmt>(s) || - isa<SwitchCase>(s)) { - ss << "; "; - TheRewriter.InsertTextBefore(s->getLocStart(), - ss.str()); - } - else if (isa<CallExpr>(s)) { - /* still has problems with f(x) + g(y) style code - ss << ", "; - TheRewriter.InsertTextBefore(s->getLocStart(), - ss.str()); - */ - } + SourceLocation real_loc_end(Stmt *s); +}; - return true; +bool +instrumenter::VisitVarDecl(VarDecl *d) +{ + // std::cout << "HERE" << std::endl; + return true; +} + +bool +instrumenter::VisitStmt(Stmt *s) +{ + std::stringstream ss; + unsigned line = SM.getPresumedLineNumber(s->getLocStart()); + Stmt *stmt_to_inst; + + if (isa<IfStmt>(s)) { + IfStmt *IfStatement = cast<IfStmt>(s); + stmt_to_inst = IfStatement->getCond(); + } + else if (isa<ForStmt>(s)) { + ForStmt *ForStatement = cast<ForStmt>(s); + stmt_to_inst = ForStatement->getCond(); } + else if (isa<WhileStmt>(s)) { + WhileStmt *WhileStatement = cast<WhileStmt>(s); + stmt_to_inst = WhileStatement->getCond(); + } + else if (isa<ReturnStmt>(s)) { + ReturnStmt *ReturnStatement = cast<ReturnStmt>(s); + stmt_to_inst = ReturnStatement->getRetValue(); + } + /* + else if (isa<BreakStmt>(s) || isa<ContinueStmt>(s) || + || isa<SwitchStmt>(s) || isa<SwitchCase>(s)) { + } + */ + else if (isa<DeclStmt>(s)) { + } + else if (isa<CallExpr>(s)) { + stmt_to_inst = s; + } + else + return true; + + ss << "(lines[" << line << "] = 1, "; + TheRewriter.InsertTextBefore(stmt_to_inst->getLocStart(), ss.str()); + TheRewriter.InsertTextAfter(real_loc_end(stmt_to_inst), ")"); - bool VisitFunctionDecl(FunctionDecl *f) { - // Only function definitions (with bodies), not declarations. - if (f->hasBody()) { - Stmt *FuncBody = f->getBody(); + return true; +} +bool +instrumenter::VisitFunctionDecl(FunctionDecl *f) +{ + // Only function definitions (with bodies), not declarations. + if (f->hasBody()) { + Stmt *FuncBody = f->getBody(); #if 0 - // Type name as string - QualType QT = f->getReturnType(); - std::string TypeStr = QT.getAsString(); - - // Function name - DeclarationName DeclName = f->getNameInfo().getName(); - std::string FuncName = DeclName.getAsString(); - - // Add comment before - std::stringstream SSBefore; - SSBefore << "// Begin function " << FuncName << " returning " << TypeStr - << "\n"; - SourceLocation ST = f->getSourceRange().getBegin(); - TheRewriter.InsertText(ST, SSBefore.str(), true, true); - - // And after - std::stringstream SSAfter; - SSAfter << "\n// End function " << FuncName; - ST = FuncBody->getLocEnd().getLocWithOffset(1); - TheRewriter.InsertText(ST, SSAfter.str(), true, true); + // Type name as string + QualType QT = f->getReturnType(); + std::string TypeStr = QT.getAsString(); + + // Function name + DeclarationName DeclName = f->getNameInfo().getName(); + std::string FuncName = DeclName.getAsString(); + + // Add comment before + std::stringstream SSBefore; + SSBefore << "// Begin function " << FuncName << " returning " << TypeStr + << "\n"; + SourceLocation ST = f->getSourceRange().getBegin(); + TheRewriter.InsertText(ST, SSBefore.str(), true, true); + + // And after + std::stringstream SSAfter; + SSAfter << "\n// End function " << FuncName; + ST = FuncBody->getLocEnd().getLocWithOffset(1); + TheRewriter.InsertText(ST, SSAfter.str(), true, true); #endif - } - - return true; } -private: - Rewriter &TheRewriter; -}; + return true; +} + +SourceLocation +instrumenter::real_loc_end(Stmt *d) +{ + SourceLocation _e(d->getLocEnd()); + return SourceLocation(Lexer::getLocForEndOfToken(_e, 0, SM, lopt)); +} + // Implementation of the ASTConsumer interface for reading an AST produced // by the Clang parser. @@ -147,7 +159,7 @@ public: } private: - MyASTVisitor Visitor; + instrumenter Visitor; }; // For each source file provided to the tool, a new FrontendAction is created. diff --git a/tests/fibonacci/instrumented.c b/tests/fibonacci/instrumented.c @@ -8,30 +8,30 @@ int size = 512; long long fibonacci(long long n) { - if (lines[9] = 1, n == 0) - return lines[10] = 1, 0; - else if (lines[11] = 1, n == 1) - return lines[12] = 1, 1; + if ((lines[9] = 1, n == 0)) + return (lines[10] = 1, 0); + else if ((lines[11] = 1, n == 1)) + return (lines[12] = 1, 1); - return lines[14] = 1, fibonacci(n - 1) + fibonacci(n - 2); + return (lines[14] = 1, (lines[14] = 1, fibonacci(n - 1)) + (lines[14] = 1, fibonacci(n - 2))); } int main(int argc, char *argv[]) { - lines[20] = 1; long long n; - lines[21] = 1; const char *errstr = NULL; + long long n; + const char *errstr = NULL; - if (lines[23] = 1, argc != 2) { - printf("usage: %s <N>\n", argv[0]); - return lines[25] = 1, 1; + if ((lines[23] = 1, argc != 2)) { + (lines[24] = 1, printf("usage: %s <N>\n", argv[0])); + return (lines[25] = 1, 1); } - n = strtonum(argv[1], LONG_MIN, LONG_MAX, &errstr); - if (lines[29] = 1, errstr) - err(1, "%s", errstr); + n = (lines[28] = 1, strtonum(argv[1], LONG_MIN, LONG_MAX, &errstr)); + if ((lines[29] = 1, errstr)) + (lines[30] = 1, err(1, "%s", errstr)); - printf("result: %lli\n", fibonacci(n)); + (lines[32] = 1, printf("result: %lli\n", (lines[32] = 1, fibonacci(n)))); - return lines[34] = 1, 0; + return (lines[34] = 1, 0); } diff --git a/tests/hello_world/instrumented.c b/tests/hello_world/instrumented.c @@ -5,6 +5,6 @@ int size = 77; int main(void) { - printf("hello, world\n"); - return lines[7] = 1, 0; + (lines[6] = 1, printf("hello, world\n")); + return (lines[7] = 1, 0); } diff --git a/tests/if_statement/instrumented.c b/tests/if_statement/instrumented.c @@ -5,18 +5,18 @@ int size = 199; int main(int argc, char *argv[]) { - if (lines[6] = 1, argc == 1) - return lines[7] = 1, 1; + if ((lines[6] = 1, argc == 1)) + return (lines[7] = 1, 1); else - exit(14); + (lines[9] = 1, exit(14)); - if (lines[11] = 1, argc == 2) { - return lines[12] = 1, 5; + if ((lines[11] = 1, argc == 2)) { + return (lines[12] = 1, 5); } - else if (lines[14] = 1, argc == 3) { - return lines[15] = 1, 0; + else if ((lines[14] = 1, argc == 3)) { + return (lines[15] = 1, 0); } else { - exit(0); + (lines[18] = 1, exit(0)); } } diff --git a/tests/while_loops/instrumented.c b/tests/while_loops/instrumented.c @@ -3,12 +3,12 @@ int size = 76; int main(void) { - lines[4] = 1; int i; + int i; i = 0; - while (lines[7] = 1, i < 10) { + while ((lines[7] = 1, i < 10)) { i++; } - return lines[11] = 1, i; + return (lines[11] = 1, i); }