citrun

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

visitor.cc (4997B)


      1 //
      2 // Copyright (c) 2016 Kyle Milz <kyle@0x30.net>
      3 //
      4 // Permission to use, copy, modify, and distribute this software for any
      5 // purpose with or without fee is hereby granted, provided that the above
      6 // copyright notice and this permission notice appear in all copies.
      7 //
      8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 //
     16 #include "visitor.h"
     17 
     18 #include <clang/AST/AST.h>
     19 #include <clang/Basic/SourceManager.h>
     20 #include <clang/Lex/Lexer.h>
     21 #include <sstream>
     22 #include <string>
     23 
     24 
     25 RewriteASTVisitor::RewriteASTVisitor(clang::Rewriter &R) :
     26 	m_TheRewriter(R),
     27 	m_SM(R.getSourceMgr()),
     28 	m_lopt(R.getLangOpts()),
     29 	m_counters(),
     30 	m_counter_descr( {{
     31 		"Function definitions",
     32 		"If statements",
     33 		"For loops",
     34 		"While loops",
     35 		"Do while loops",
     36 		"Switch statements",
     37 		"Return statement values",
     38 		"Call expressions",
     39 		"Total statements",
     40 		"Binary operators",
     41 		"Errors rewriting source code"
     42 	}} )
     43 {
     44 }
     45 
     46 bool
     47 RewriteASTVisitor::TraverseStmt(clang::Stmt *s)
     48 {
     49 	if (s == NULL)
     50 		return true;
     51 
     52 	clang::SourceLocation start_loc = s->getBeginLoc();
     53 	if (m_SM.isInMainFile(start_loc) == false)
     54 		return false;
     55 
     56 	// Instrumenting statement conditions in macros works perfectly.
     57 	// Instrumenting binary operators in macros does not work well.
     58 	if (clang::Lexer::isAtStartOfMacroExpansion(start_loc, m_SM, m_lopt))
     59 		return false;
     60 
     61 	RecursiveASTVisitor<RewriteASTVisitor>::TraverseStmt(s);
     62 	return true;
     63 }
     64 
     65 bool
     66 RewriteASTVisitor::TraverseDecl(clang::Decl *d)
     67 {
     68 	if (m_SM.isInMainFile(d->getBeginLoc()) == false)
     69 		return false;
     70 
     71 	if (clang::isa<clang::VarDecl>(d)) {
     72 		clang::VarDecl *vd = clang::cast<clang::VarDecl>(d);
     73 		if (vd->hasGlobalStorage())
     74 			return false;
     75 	}
     76 	if (clang::isa<clang::RecordDecl>(d))
     77 		return false;
     78 	if (clang::isa<clang::EnumDecl>(d))
     79 		return false;
     80 
     81 	RecursiveASTVisitor<RewriteASTVisitor>::TraverseDecl(d);
     82 	return true;
     83 }
     84 
     85 bool
     86 RewriteASTVisitor::VisitVarDecl(clang::VarDecl *d)
     87 {
     88 	return true;
     89 }
     90 
     91 bool
     92 RewriteASTVisitor::VisitStmt(clang::Stmt *s)
     93 {
     94 	++m_counters[TOTAL_STMT];
     95 	return true;
     96 }
     97 
     98 bool
     99 RewriteASTVisitor::VisitIfStmt(clang::IfStmt *i)
    100 {
    101 	modify_stmt(i->getCond(), m_counters[IF_STMT]);
    102 	return true;
    103 }
    104 
    105 bool
    106 RewriteASTVisitor::VisitForStmt(clang::ForStmt *f)
    107 {
    108 	modify_stmt(f->getCond(), m_counters[FOR_STMT]);
    109 	return true;
    110 }
    111 
    112 bool
    113 RewriteASTVisitor::VisitWhileStmt(clang::WhileStmt *w)
    114 {
    115 	modify_stmt(w->getCond(), m_counters[WHILE_STMT]);
    116 	return true;
    117 }
    118 
    119 bool
    120 RewriteASTVisitor::VisitDoStmt(clang::DoStmt *d)
    121 {
    122 	modify_stmt(d->getCond(), m_counters[DOWHILE_STMT]);
    123 	return true;
    124 }
    125 
    126 bool
    127 RewriteASTVisitor::VisitSwitchStmt(clang::SwitchStmt *s)
    128 {
    129 	modify_stmt(s->getCond(), m_counters[SWITCH_STMT]);
    130 	return true;
    131 }
    132 
    133 bool
    134 RewriteASTVisitor::VisitReturnStmt(clang::ReturnStmt *r)
    135 {
    136 	modify_stmt(r->getRetValue(), m_counters[RET_STMT_VAL]);
    137 	return true;
    138 }
    139 
    140 bool
    141 RewriteASTVisitor::VisitCallExpr(clang::CallExpr *c)
    142 {
    143 	modify_stmt(c, m_counters[CALL_EXPR]);
    144 	return true;
    145 }
    146 
    147 bool
    148 RewriteASTVisitor::VisitBinaryOperator(clang::BinaryOperator *b)
    149 {
    150 	// If we can't rewrite the last token, don't even start.
    151 	if (b->getEndLoc().isMacroID())
    152 		return true;
    153 	modify_stmt(b, m_counters[BIN_OPER]);
    154 	return true;
    155 }
    156 
    157 bool
    158 RewriteASTVisitor::modify_stmt(clang::Stmt *s, int &counter)
    159 {
    160 	if (s == NULL)
    161 		return false;
    162 
    163 	std::stringstream ss;
    164 	ss << "(++_citrun.data["
    165 		<< m_SM.getPresumedLineNumber(s->getBeginLoc()) - 1
    166 		<< "], ";
    167 
    168 	if (m_TheRewriter.InsertTextBefore(s->getBeginLoc(), ss.str())) {
    169 		++m_counters[REWRITE_ERROR];
    170 		return false;
    171 	}
    172 
    173 	m_TheRewriter.InsertTextAfter(real_loc_end(s), ")");
    174 	++counter;
    175 
    176 	return true;
    177 }
    178 
    179 bool
    180 RewriteASTVisitor::VisitFunctionDecl(clang::FunctionDecl *f)
    181 {
    182 	// Only function definitions (with bodies), not declarations.
    183 	if (f->hasBody() == 0)
    184 		return true;
    185 
    186 	std::stringstream rewrite_text;
    187 
    188 	clang::Stmt *FuncBody = f->getBody();
    189 	clang::SourceLocation curly_brace(FuncBody->getBeginLoc().getLocWithOffset(1));
    190 
    191 	// Animate function calls by firing the entire declaration.
    192 	int decl_start = m_SM.getPresumedLineNumber(f->getBeginLoc());
    193 	int decl_end = m_SM.getPresumedLineNumber(curly_brace);
    194 	for (int i = decl_start; i <= decl_end; ++i)
    195 		rewrite_text << "++_citrun.data[" << i - 1 << "];";
    196 
    197 	// Rewrite the function source right after the beginning curly brace.
    198 	m_TheRewriter.InsertTextBefore(curly_brace, rewrite_text.str());
    199 
    200 	++m_counters[FUNC_DEF];
    201 	return true;
    202 }
    203 
    204 clang::SourceLocation
    205 RewriteASTVisitor::real_loc_end(clang::Stmt *d)
    206 {
    207 	clang::SourceLocation _e(d->getEndLoc());
    208 	return clang::Lexer::getLocForEndOfToken(_e, 0, m_SM, m_lopt);
    209 }