// // Created by erki on 16.02.21. // #include "OperationFinder.hpp" #include #include "ASTHelpers.hpp" using namespace clang; using namespace clang::ast_matchers; namespace { std::string ResolveTypeName(const QualType& t) { if (t->isTypedefNameType()) { const TypedefType* tdt = cast(t); assert(tdt); llvm::outs() << "Typedef type: " << t.getAsString() << ", underlying: " << tdt->desugar().getAsString() << "."; return tdt->desugar().getAsString(); } else if (t->isBuiltinType()) { llvm::outs() << "Builtin type: " << t.getAsString() << "."; return t.getAsString(); } else { llvm::outs() << "Other type: " << t.getAsString() << "."; return t.getAsString(); } }; } OperationFinder::OperationFinder(IOperationOutput* storage) : _storage(storage) { assert(storage); } void OperationFinder::processArithmetic(const clang::BinaryOperator* op, const clang::SourceManager& source_manager) { auto [file_name, log] = _createBaseOperationLog(op, source_manager); const std::string op_code = getOpcode(op).str(); llvm::outs() << "\n\tBinary arithmetic: Type: " << op_code; log.entry_type = OperationLog::BasicOperation::TYPE_NAME; log.entry = _createBasicOperationLogEntry(op_code, op, op->getLHS(), op->getRHS()); _storage->pushOperation(file_name, std::move(log)); llvm::outs() << "\n"; } void OperationFinder::processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager) { auto [file_name, log] = _createBaseOperationLog(op, source_manager); const std::string op_code = getOpcode(op).str(); llvm::outs() << "\n\tUnary arithmetic: Type: " << op_code; log.entry_type = OperationLog::BasicOperation::TYPE_NAME; log.entry = _createBasicOperationLogEntry(op_code, op, op->getExprStmt(), nullptr); _storage->pushOperation(file_name, std::move(log)); llvm::outs() << "\n"; } void OperationFinder::processFunctionCall(const clang::CallExpr* call, const SourceManager& source_manager) { const FunctionDecl* func = call->getDirectCallee(); assert(func); auto [file_name, log] = _createBaseOperationLog(call, source_manager); const std::string func_name = func->getNameAsString(); llvm::outs() << "\n\tFunction call: func name: " << func_name << "\n\tResult eval type: "; const std::string res_type = ResolveTypeName(func->getType()); auto func_call = std::make_unique(); func_call->function_name = func_name; func_call->call_result_type = res_type; log.entry_type = OperationLog::FunctionCall::TYPE_NAME; log.entry = std::move(func_call); _storage->pushOperation(file_name, std::move(log)); llvm::outs() << "\n"; } void OperationFinder::processArraySubscript(const clang::ArraySubscriptExpr* subscript, const clang::SourceManager& source_manager) { auto [file_name, log] = _createBaseOperationLog(subscript, source_manager); llvm::outs() << "\n\tSubscript:"; log.entry_type = OperationLog::BasicOperation::TYPE_NAME; log.entry = _createBasicOperationLogEntry("subscript", subscript, subscript->getBase(), subscript->getIdx()); _storage->pushOperation(file_name, std::move(log)); llvm::outs() << "\n"; } void OperationFinder::branchEntered() { _current_branch++; llvm::outs() << "Branch entered: " << _current_branch << "\n"; } void OperationFinder::branchExited() { llvm::outs() << "Branch exited: " << _current_branch << "\n"; _current_branch--; assert(_current_branch > -1); } std::unique_ptr OperationFinder::_createBasicOperationLogEntry(const std::string& opcode, const Expr* source, const Expr* op1, const Expr* op2) { auto log = std::make_unique(); log->operation_name = opcode; llvm::outs() << "\n\tExpression eval type: "; log->type_result = ResolveTypeName(source->getType()); if (op1) { llvm::outs() << "\n\tLHS eval type: "; log->type_lhs = ResolveTypeName(op1->getType()); } if (op2) { llvm::outs() << "\n\tRHS eval type: "; log->type_rhs = ResolveTypeName(op2->getType()); } return log; } std::pair OperationFinder::_createBaseOperationLog(const clang::Stmt* stmt, const clang::SourceManager& source_manager) { const auto [file_name, line_number, column_number] = resolveLocations(stmt, source_manager); OperationLog log; log.line = line_number; log.branch_number = _current_branch; llvm::outs() << file_name << ":" << line_number << ":" << column_number << ":"; return { file_name, std::move(log) }; }