masters-thesis/op-finder/OperationFinder.cpp

202 lines
6.1 KiB
C++

//
// Created by erki on 16.02.21.
//
#include "OperationFinder.hpp"
#include <iostream>
#include <sstream>
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;
}
}
void OperationFinder::addMatcher(MatchFinder &finder)
{
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this);
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this);
//finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, CompoundMatcher), 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::CompoundStmt>("compound_stmt"))
{
_processCompoundStmt(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& source_manager = *result.SourceManager;
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":"
<< source_manager.getSpellingLineNumber(loc) << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":"
<< "Assignment: Assigned to: ";
_processExpressionTypes(op, op->getLHS(), op->getRHS());
llvm::outs() << "\n";
}
void OperationFinder::_processArithmetic(const MatchFinder::MatchResult& result)
{
const BinaryOperator* op = result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic");
assert(op);
const auto& source_manager = *result.SourceManager;
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":"
<< source_manager.getSpellingLineNumber(loc) << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":"
<< "Arithmetic: Type: " << getOpcode(op) << " LHS: ";
_processExpressionTypes(op, op->getLHS(), op->getRHS());
llvm::outs() << "\n";
}
void OperationFinder::_processCompoundStmt(const clang::ast_matchers::MatchFinder::MatchResult& result)
{
const CompoundStmt* stmt = result.Nodes.getNodeAs<CompoundStmt>("compound_stmt");
assert(stmt);
const CompoundAssignOperator* op = dyn_cast<CompoundAssignOperator>(stmt->getStmtExprResult());
if (!op || !op->isCompoundAssignmentOp())
return;
const auto& source_manager = *result.SourceManager;
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":"
<< source_manager.getSpellingLineNumber(loc) << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":"
<< "Compound assignment: Op code: " << getOpcode(op) << " ";
_processExpressionTypes(op, op->getLHS(), op->getRHS());
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& source_manager = *result.SourceManager;
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":"
<< source_manager.getSpellingLineNumber(loc) << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":"
<< "Unary arithmetic: Type: " << getOpcode(op) << " LHS: ";
_processExpressionTypes(op, lhs, nullptr);
llvm::outs() << "\n";
}
void OperationFinder::_processExpressionTypes(const Expr* source, const Expr* op1, const Expr* op2)
{
auto printTypeName = [](const QualType& t) -> void
{
if (t->isTypedefNameType())
{
const TypedefType* tdt = cast<TypedefType>(t);
assert(tdt);
llvm::outs() << "Typedef type: " << t.getAsString()
<< ", underlying: " << tdt->desugar().getAsString()
<< ".";
}
else if (t->isBuiltinType())
{
llvm::outs() << "Builtin type: " << t.getAsString() << ".";
}
else
{
llvm::outs() << "Other type: " << t.getAsString() << ".";
}
};
llvm::outs() << "Expression types:\n\tExpression eval type: ";
printTypeName(source->getType());
if (op1)
{
llvm::outs() << "\n\tLHS eval type: ";
printTypeName(op1->getType());
}
if (op2)
{
llvm::outs() << "\n\tRHS eval type: ";
printTypeName(op2->getType());
}
}