masters-thesis/op-finder-lib/src/OperationFinder.cpp

171 lines
4.6 KiB
C++

//
// Created by erki on 16.02.21.
//
#include "OperationFinder.hpp"
#include <iostream>
#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<TypedefType>(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<OperationLog::FunctionCall>();
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<OperationLog::BasicOperation>
OperationFinder::_createBasicOperationLogEntry(const std::string& opcode, const Expr* source, const Expr* op1, const Expr* op2)
{
auto log = std::make_unique<OperationLog::BasicOperation>();
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<std::string, OperationLog> 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) };
}