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 }