// // Created by erki on 16.02.21. // #include "OperationFinder.hpp" #include #include 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 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("assignment")) { _processAssignment(result); } else if (result.Nodes.getNodeAs("arithmetic")) { _processArithmetic(result); } else if (result.Nodes.getNodeAs("compound_stmt")) { _processCompoundStmt(result); } else if (result.Nodes.getNodeAs("unary_arithmetic")) { _processUnaryArithmetic(result); } } void OperationFinder::_processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result) { const BinaryOperator* op = result.Nodes.getNodeAs("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("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("compound_stmt"); assert(stmt); const CompoundAssignOperator* op = dyn_cast(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("unary_arithmetic"); const Expr* lhs = result.Nodes.getNodeAs("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(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()); } }