210 lines
5.8 KiB
C++
210 lines
5.8 KiB
C++
//
|
|
// Created by erki on 16.02.21.
|
|
//
|
|
|
|
#include "OperationFinder.hpp"
|
|
|
|
#include <iostream>
|
|
|
|
using namespace clang;
|
|
using namespace clang::ast_matchers;
|
|
|
|
namespace
|
|
{
|
|
|
|
StatementMatcher AssignmentMatcher =
|
|
binaryOperation(isAssignmentOperator(),
|
|
hasLHS(expr().bind("lhs")),
|
|
hasRHS(expr().bind("rhs"))).bind("assignment");
|
|
|
|
StatementMatcher ArithmeticMatcher =
|
|
binaryOperation(hasAnyOperatorName("+", "-", "/", "*", "<", ">",
|
|
"<=", ">=", "==", "<<", ">>", "%"),
|
|
hasLHS(expr().bind("lhs")),
|
|
hasRHS(expr().bind("lhs"))).bind("arithmetic");
|
|
|
|
StatementMatcher UnaryArithmeticMatcher =
|
|
unaryOperator(hasAnyOperatorName("!", "++", "--"),
|
|
hasUnaryOperand(expr().bind("lhs"))).bind("unary_arithmetic");
|
|
|
|
StatementMatcher CompoundMatcher =
|
|
compoundStmt().bind("compound_stmt");
|
|
|
|
//StatementMatcher ForStatementMatcher =
|
|
// forStmt(hasInitStatement(expr().bind("init"))).bind("for_stmt");
|
|
|
|
template<typename TOp>
|
|
StringRef getOpcode(const TOp *op)
|
|
{
|
|
return op->getOpcodeStr(op->getOpcode());
|
|
}
|
|
|
|
SourceLocation ResolveOperationSourceLocation(const SourceManager& source_manager, const SourceLocation& original)
|
|
{
|
|
if (source_manager.isMacroBodyExpansion(original))
|
|
{
|
|
return source_manager.getExpansionLoc(original);
|
|
}
|
|
|
|
return original;
|
|
}
|
|
|
|
template<typename TOp>
|
|
std::tuple<std::string, unsigned int, unsigned int> resolveLocations(const TOp* op, const SourceManager& source_manager)
|
|
{
|
|
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
|
|
|
|
return {
|
|
source_manager.getFilename(loc).str(),
|
|
source_manager.getSpellingLineNumber(loc),
|
|
source_manager.getSpellingColumnNumber(loc)
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
OperationFinder::OperationFinder(IOperationOutput* storage)
|
|
: _storage(storage)
|
|
{
|
|
assert(storage);
|
|
}
|
|
|
|
void OperationFinder::addMatcher(MatchFinder &finder)
|
|
{
|
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this);
|
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this);
|
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, UnaryArithmeticMatcher), this);
|
|
}
|
|
|
|
void OperationFinder::run(const MatchFinder::MatchResult& result)
|
|
{
|
|
if (result.Nodes.getNodeAs<clang::BinaryOperator>("assignment"))
|
|
{
|
|
_processAssignment(result);
|
|
}
|
|
else if (result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic"))
|
|
{
|
|
_processArithmetic(result);
|
|
}
|
|
else if (result.Nodes.getNodeAs<clang::UnaryOperator>("unary_arithmetic"))
|
|
{
|
|
_processUnaryArithmetic(result);
|
|
}
|
|
}
|
|
|
|
void OperationFinder::_processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result)
|
|
{
|
|
const BinaryOperator* op = result.Nodes.getNodeAs<BinaryOperator>("assignment");
|
|
|
|
assert(op);
|
|
|
|
const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
|
|
|
|
llvm::outs() << file_name << ":"
|
|
<< line_number << ":"
|
|
<< column_number << ":"
|
|
<< "Assignment: Assigned to: ";
|
|
|
|
OperationLog log;
|
|
log.line = line_number;
|
|
log.operation = "=";
|
|
|
|
_processExpressionTypes(log, op, op->getLHS(), op->getRHS());
|
|
|
|
_storage->pushOperation(file_name, log);
|
|
|
|
llvm::outs() << "\n";
|
|
}
|
|
|
|
void OperationFinder::_processArithmetic(const MatchFinder::MatchResult& result)
|
|
{
|
|
const BinaryOperator* op = result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic");
|
|
|
|
assert(op);
|
|
|
|
const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
|
|
|
|
llvm::outs() << file_name << ":"
|
|
<< line_number << ":"
|
|
<< column_number << ":"
|
|
<< "Binary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
|
|
|
OperationLog log;
|
|
log.line = line_number;
|
|
log.operation = getOpcode(op).str();
|
|
|
|
_processExpressionTypes(log, op, op->getLHS(), op->getRHS());
|
|
|
|
_storage->pushOperation(file_name, log);
|
|
|
|
llvm::outs() << "\n";
|
|
}
|
|
|
|
void OperationFinder::_processUnaryArithmetic(const MatchFinder::MatchResult &result)
|
|
{
|
|
const UnaryOperator* op = result.Nodes.getNodeAs<UnaryOperator>("unary_arithmetic");
|
|
const Expr* lhs = result.Nodes.getNodeAs<Expr>("lhs");
|
|
|
|
assert(op);
|
|
assert(lhs);
|
|
|
|
const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
|
|
|
|
llvm::outs() << file_name << ":"
|
|
<< line_number << ":"
|
|
<< column_number << ":"
|
|
<< "Unary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
|
|
|
OperationLog log;
|
|
log.line = line_number;
|
|
log.operation = getOpcode(op).str();
|
|
|
|
_processExpressionTypes(log, op, lhs, nullptr);
|
|
|
|
_storage->pushOperation(file_name, log);
|
|
|
|
llvm::outs() << "\n";
|
|
}
|
|
|
|
void OperationFinder::_processExpressionTypes(OperationLog& log, const Expr* source, const Expr* op1, const Expr* op2)
|
|
{
|
|
|
|
auto printTypeName = [](const QualType& t) -> std::string
|
|
{
|
|
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();
|
|
}
|
|
};
|
|
|
|
llvm::outs() << "Expression types:\n\tExpression eval type: ";
|
|
log.operand_result = printTypeName(source->getType());
|
|
|
|
if (op1)
|
|
{
|
|
llvm::outs() << "\n\tLHS eval type: ";
|
|
log.operand_lhs = printTypeName(op1->getType());
|
|
}
|
|
if (op2)
|
|
{
|
|
llvm::outs() << "\n\tRHS eval type: ";
|
|
log.operand_rhs = printTypeName(op2->getType());
|
|
}
|
|
}
|