207 lines
6.0 KiB
C++
207 lines
6.0 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");
|
|
|
|
bool isInMainFile(const MatchFinder::MatchResult &result, const SourceLocation &loc)
|
|
{
|
|
return result.Context->getSourceManager().isWrittenInMainFile(loc);
|
|
}
|
|
|
|
template<typename TOp>
|
|
StringRef getOpcode(const TOp *op)
|
|
{
|
|
return op->getOpcodeStr(op->getOpcode());
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
if (!isInMainFile(result, op->getBeginLoc()))
|
|
return;
|
|
|
|
const auto& loc = op->getBeginLoc();
|
|
const auto& source_manager = *result.SourceManager;
|
|
|
|
|
|
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);
|
|
|
|
if (!isInMainFile(result, op->getBeginLoc()))
|
|
return;
|
|
|
|
const auto& loc = op->getBeginLoc();
|
|
const auto& source_manager = *result.SourceManager;
|
|
|
|
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;
|
|
|
|
if (!isInMainFile(result, op->getBeginLoc()))
|
|
return;
|
|
|
|
const auto& loc = op->getBeginLoc();
|
|
const auto& source_manager = *result.SourceManager;
|
|
|
|
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);
|
|
|
|
if (!isInMainFile(result, lhs->getBeginLoc()))
|
|
return;
|
|
|
|
const auto& loc = lhs->getBeginLoc();
|
|
const auto& source_manager = *result.SourceManager;
|
|
|
|
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());
|
|
}
|
|
}
|