// // 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) { const auto [file_name, line_number, column_number] = resolveLocations(op, source_manager); llvm::outs() << file_name << ":" << line_number << ":" << column_number << ":" << "Binary arithmetic: Type: " << getOpcode(op) << " LHS: "; OperationLog log; log.line = line_number; log.entry_type = OperationLog::BasicOperation::TYPE_NAME; log.entry = _createBasicOperationLogEntry(op, op->getLHS(), op->getRHS()); log.current_for_loops = _for_loop_stack; log.is_fallthrough = _in_fallthrough; _storage->pushOperation(file_name, std::move(log)); llvm::outs() << "\n"; } void OperationFinder::processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager) { const Expr* lhs = op->getExprStmt(); assert(op); assert(lhs); const auto [file_name, line_number, column_number] = resolveLocations(op, source_manager); llvm::outs() << file_name << ":" << line_number << ":" << column_number << ":" << "Unary arithmetic: Type: " << getOpcode(op) << " LHS: "; OperationLog log; log.line = line_number; log.entry_type = OperationLog::BasicOperation::TYPE_NAME; log.entry = _createBasicOperationLogEntry(op, lhs, nullptr); log.current_for_loops = _for_loop_stack; log.is_fallthrough = _in_fallthrough; _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); const auto [file_name, line_number, column_number] = resolveLocations(call, source_manager); const std::string res_type = ResolveTypeName(func->getType()); const std::string func_name = func->getNameAsString(); llvm::outs() << file_name << ":" << line_number << ":" << column_number << ":" << "Function call: name: " << func_name << " Restype: " << res_type << "\n"; auto func_call = std::make_unique(); func_call->function_name = func_name; func_call->call_result_type = res_type; OperationLog log; log.line = line_number; log.entry_type = OperationLog::FunctionCall::TYPE_NAME; log.entry = std::move(func_call); log.current_for_loops = _for_loop_stack; log.is_fallthrough = _in_fallthrough; _storage->pushOperation(file_name, std::move(log)); } void OperationFinder::fallthroughBranchEntered() { _in_fallthrough = true; } void OperationFinder::fallthroughBranchExited() { _in_fallthrough = false; } void OperationFinder::forLoopEntered() { _for_loop_stack.push_back(_next_for_loop_id); _next_for_loop_id++; } void OperationFinder::forLoopExited() { _for_loop_stack.pop_back(); } std::unique_ptr OperationFinder::_createBasicOperationLogEntry(const Expr* source, const Expr* op1, const Expr* op2) { auto log = std::make_unique(); llvm::outs() << "Expression types:\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; }