Compare commits
5 Commits
b609c48bfe
...
5a2d5ed933
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a2d5ed933 | |||
| be4a71325d | |||
| 16f4c85f6d | |||
| aff90d5a9d | |||
| 0e7cf93c9b |
5
.idea/codeStyles/Project.xml
generated
5
.idea/codeStyles/Project.xml
generated
@ -42,6 +42,11 @@
|
|||||||
<rule entity="CLASS_MEMBER_FUNCTION,STRUCT_MEMBER_FUNCTION" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="PASCAL_CASE" suffix="" />
|
<rule entity="CLASS_MEMBER_FUNCTION,STRUCT_MEMBER_FUNCTION" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="PASCAL_CASE" suffix="" />
|
||||||
</rules>
|
</rules>
|
||||||
</Objective-C-extensions>
|
</Objective-C-extensions>
|
||||||
|
<codeStyleSettings language="CMake">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
<codeStyleSettings language="ObjectiveC">
|
<codeStyleSettings language="ObjectiveC">
|
||||||
<option name="BRACE_STYLE" value="2" />
|
<option name="BRACE_STYLE" value="2" />
|
||||||
<option name="CLASS_BRACE_STYLE" value="2" />
|
<option name="CLASS_BRACE_STYLE" value="2" />
|
||||||
|
|||||||
52
op-finder/ASTHelpers.hpp
Normal file
52
op-finder/ASTHelpers.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_ASTHELPERS_HPP
|
||||||
|
#define C_ANALYZER_ASTHELPERS_HPP
|
||||||
|
|
||||||
|
#include <clang/AST/ASTContext.h>
|
||||||
|
|
||||||
|
template<typename TOp>
|
||||||
|
clang::StringRef getOpcode(const TOp *op)
|
||||||
|
{
|
||||||
|
return op->getOpcodeStr(op->getOpcode());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline clang::SourceLocation resolveOperationSourceLocation(const clang::SourceManager& source_manager,
|
||||||
|
const clang::SourceLocation& original)
|
||||||
|
{
|
||||||
|
if (source_manager.isMacroBodyExpansion(original))
|
||||||
|
{
|
||||||
|
return source_manager.getExpansionLoc(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::tuple<std::string, unsigned int, unsigned int> resolveLocationsWithLoc(const clang::SourceLocation& loc,
|
||||||
|
const clang::SourceManager& source_manager)
|
||||||
|
{
|
||||||
|
const auto& loc_resolved = resolveOperationSourceLocation(source_manager, loc);
|
||||||
|
|
||||||
|
return {
|
||||||
|
source_manager.getFilename(loc_resolved).str(),
|
||||||
|
source_manager.getSpellingLineNumber(loc_resolved),
|
||||||
|
source_manager.getSpellingColumnNumber(loc_resolved)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TStmt>
|
||||||
|
std::tuple<std::string, unsigned int, unsigned int> resolveLocations(const TStmt* op,
|
||||||
|
const clang::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)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_ASTHELPERS_HPP
|
||||||
@ -21,6 +21,10 @@ add_executable(op-finder
|
|||||||
main.cpp
|
main.cpp
|
||||||
OperationFinder.cpp
|
OperationFinder.cpp
|
||||||
OperationStorage.cpp
|
OperationStorage.cpp
|
||||||
|
OperationAstMatcher.cpp
|
||||||
|
OperationFinderAstVisitor.cpp
|
||||||
|
OperationFinderAstConsumer.cpp
|
||||||
|
OperationFinderAstAction.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(op-finder
|
target_include_directories(op-finder
|
||||||
|
|||||||
57
op-finder/OperationAstMatcher.cpp
Normal file
57
op-finder/OperationAstMatcher.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationAstMatcher.hpp"
|
||||||
|
|
||||||
|
#include "OperationFinder.hpp"
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
OperationASTMatcher::OperationASTMatcher(OperationFinder* finder)
|
||||||
|
: _op_finder(finder)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void OperationASTMatcher::addToFinder(clang::ast_matchers::MatchFinder& finder)
|
||||||
|
{
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this);
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this);
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, UnaryArithmeticMatcher), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationASTMatcher::run(const clang::ast_matchers::MatchFinder::MatchResult& result)
|
||||||
|
{
|
||||||
|
if (const auto* op = result.Nodes.getNodeAs<clang::BinaryOperator>("assignment"))
|
||||||
|
{
|
||||||
|
_op_finder->processArithmetic(op, *result.SourceManager);
|
||||||
|
}
|
||||||
|
else if (const auto* op = result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic"))
|
||||||
|
{
|
||||||
|
_op_finder->processArithmetic(op, *result.SourceManager);
|
||||||
|
}
|
||||||
|
else if (const auto* op = result.Nodes.getNodeAs<clang::UnaryOperator>("unary_arithmetic"))
|
||||||
|
{
|
||||||
|
_op_finder->processUnaryArithmetic(op, *result.SourceManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
op-finder/OperationAstMatcher.hpp
Normal file
25
op-finder/OperationAstMatcher.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONASTMATCHER_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONASTMATCHER_HPP
|
||||||
|
|
||||||
|
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
||||||
|
|
||||||
|
class OperationFinder;
|
||||||
|
|
||||||
|
class OperationASTMatcher : public clang::ast_matchers::MatchFinder::MatchCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OperationASTMatcher(OperationFinder* finder);
|
||||||
|
|
||||||
|
void addToFinder(clang::ast_matchers::MatchFinder& finder);
|
||||||
|
|
||||||
|
void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override;
|
||||||
|
private:
|
||||||
|
OperationFinder* _op_finder;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONASTMATCHER_HPP
|
||||||
@ -6,165 +6,77 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ASTHelpers.hpp"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace clang::ast_matchers;
|
using namespace clang::ast_matchers;
|
||||||
|
|
||||||
namespace
|
OperationFinder::OperationFinder(IOperationOutput* storage)
|
||||||
|
: _storage(storage)
|
||||||
{
|
{
|
||||||
|
assert(storage);
|
||||||
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)
|
void OperationFinder::processArithmetic(const clang::BinaryOperator* op, const clang::SourceManager& source_manager)
|
||||||
{
|
{
|
||||||
if (source_manager.isMacroBodyExpansion(original))
|
const auto [file_name, line_number, column_number] = resolveLocations(op, source_manager);
|
||||||
{
|
|
||||||
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(const std::string& output_dir)
|
|
||||||
: _storage(output_dir)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
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: ";
|
|
||||||
|
|
||||||
OperationStorage::Log 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 << ":"
|
llvm::outs() << file_name << ":"
|
||||||
<< line_number << ":"
|
<< line_number << ":"
|
||||||
<< column_number << ":"
|
<< column_number << ":"
|
||||||
<< "Binary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
<< "Binary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
||||||
|
|
||||||
OperationStorage::Log log;
|
OperationLog log;
|
||||||
log.line = line_number;
|
log.line = line_number;
|
||||||
log.operation = getOpcode(op).str();
|
log.operation = getOpcode(op).str();
|
||||||
|
log.current_for_loops = _for_loop_stack;
|
||||||
|
|
||||||
_processExpressionTypes(log, op, op->getLHS(), op->getRHS());
|
_processExpressionTypes(log, op, op->getLHS(), op->getRHS());
|
||||||
|
|
||||||
_storage.pushOperation(file_name, log);
|
_storage->pushOperation(file_name, log);
|
||||||
|
|
||||||
llvm::outs() << "\n";
|
llvm::outs() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationFinder::_processUnaryArithmetic(const MatchFinder::MatchResult &result)
|
void OperationFinder::processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager)
|
||||||
{
|
{
|
||||||
const UnaryOperator* op = result.Nodes.getNodeAs<UnaryOperator>("unary_arithmetic");
|
const Expr* lhs = op->getExprStmt();
|
||||||
const Expr* lhs = result.Nodes.getNodeAs<Expr>("lhs");
|
|
||||||
|
|
||||||
assert(op);
|
assert(op);
|
||||||
assert(lhs);
|
assert(lhs);
|
||||||
|
|
||||||
const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
|
const auto [file_name, line_number, column_number] = resolveLocations(op, source_manager);
|
||||||
|
|
||||||
llvm::outs() << file_name << ":"
|
llvm::outs() << file_name << ":"
|
||||||
<< line_number << ":"
|
<< line_number << ":"
|
||||||
<< column_number << ":"
|
<< column_number << ":"
|
||||||
<< "Unary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
<< "Unary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
||||||
|
|
||||||
OperationStorage::Log log;
|
OperationLog log;
|
||||||
log.line = line_number;
|
log.line = line_number;
|
||||||
log.operation = getOpcode(op).str();
|
log.operation = getOpcode(op).str();
|
||||||
|
log.current_for_loops = _for_loop_stack;
|
||||||
|
|
||||||
_processExpressionTypes(log, op, lhs, nullptr);
|
_processExpressionTypes(log, op, lhs, nullptr);
|
||||||
|
|
||||||
_storage.pushOperation(file_name, log);
|
_storage->pushOperation(file_name, log);
|
||||||
|
|
||||||
llvm::outs() << "\n";
|
llvm::outs() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationFinder::_processExpressionTypes(OperationStorage::Log& log, const Expr* source, const Expr* op1, const Expr* op2)
|
void OperationFinder::forLoopEntered()
|
||||||
|
{
|
||||||
|
_for_loop_stack.push_back(_next_for_loop_id);
|
||||||
|
|
||||||
|
_next_for_loop_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::forLoopExited()
|
||||||
|
{
|
||||||
|
_for_loop_stack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::_processExpressionTypes(OperationLog& log, const Expr* source, const Expr* op1, const Expr* op2)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto printTypeName = [](const QualType& t) -> std::string
|
auto printTypeName = [](const QualType& t) -> std::string
|
||||||
|
|||||||
@ -5,27 +5,27 @@
|
|||||||
#ifndef LLVM_PROTO_OPERATIONFINDER_HPP
|
#ifndef LLVM_PROTO_OPERATIONFINDER_HPP
|
||||||
#define LLVM_PROTO_OPERATIONFINDER_HPP
|
#define LLVM_PROTO_OPERATIONFINDER_HPP
|
||||||
|
|
||||||
#include <clang/ASTMatchers/ASTMatchers.h>
|
|
||||||
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
||||||
|
|
||||||
#include "OperationStorage.hpp"
|
#include "OperationLog.hpp"
|
||||||
|
|
||||||
class OperationFinder : public clang::ast_matchers::MatchFinder::MatchCallback
|
class OperationFinder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OperationFinder(const std::string& output_dir);
|
explicit OperationFinder(IOperationOutput* storage);
|
||||||
|
|
||||||
void addMatcher(clang::ast_matchers::MatchFinder& finder);
|
void processArithmetic(const clang::BinaryOperator* op, const clang::SourceManager& source_manager);
|
||||||
|
void processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager);
|
||||||
|
|
||||||
|
void forLoopEntered();
|
||||||
|
void forLoopExited();
|
||||||
|
|
||||||
void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override;
|
|
||||||
private:
|
private:
|
||||||
void _processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
void _processExpressionTypes(OperationLog& log, const clang::Expr* source, const clang::Expr* op1, const clang::Expr* op2);
|
||||||
void _processArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
|
||||||
void _processUnaryArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
|
||||||
|
|
||||||
void _processExpressionTypes(OperationStorage::Log& log, const clang::Expr* source, const clang::Expr* op1, const clang::Expr* op2);
|
int _next_for_loop_id = 0;
|
||||||
|
std::vector<int> _for_loop_stack;
|
||||||
OperationStorage _storage;
|
IOperationOutput* _storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //LLVM_PROTO_OPERATIONFINDER_HPP
|
#endif //LLVM_PROTO_OPERATIONFINDER_HPP
|
||||||
|
|||||||
17
op-finder/OperationFinderAstAction.cpp
Normal file
17
op-finder/OperationFinderAstAction.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationFinderAstAction.hpp"
|
||||||
|
|
||||||
|
#include "OperationFinderAstConsumer.hpp"
|
||||||
|
|
||||||
|
OperationFinderAstAction::OperationFinderAstAction(OperationFinder* op_finder)
|
||||||
|
: _op_finder(op_finder)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
std::unique_ptr<clang::ASTConsumer> OperationFinderAstAction::newASTConsumer()
|
||||||
|
{
|
||||||
|
return std::unique_ptr<clang::ASTConsumer>(
|
||||||
|
new OperationFinderAstConsumer(_op_finder));
|
||||||
|
}
|
||||||
24
op-finder/OperationFinderAstAction.hpp
Normal file
24
op-finder/OperationFinderAstAction.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONFINDERASTACTION_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONFINDERASTACTION_HPP
|
||||||
|
|
||||||
|
#include <clang/Frontend/CompilerInstance.h>
|
||||||
|
#include <clang/Frontend/FrontendActions.h>
|
||||||
|
|
||||||
|
class OperationFinder;
|
||||||
|
|
||||||
|
class OperationFinderAstAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OperationFinderAstAction(OperationFinder* op_finder);
|
||||||
|
|
||||||
|
std::unique_ptr<clang::ASTConsumer> newASTConsumer();
|
||||||
|
private:
|
||||||
|
OperationFinder* _op_finder;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONFINDERASTACTION_HPP
|
||||||
19
op-finder/OperationFinderAstConsumer.cpp
Normal file
19
op-finder/OperationFinderAstConsumer.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationFinderAstConsumer.hpp"
|
||||||
|
|
||||||
|
OperationFinderAstConsumer::OperationFinderAstConsumer(OperationFinder* op_finder)
|
||||||
|
: _visitor(op_finder)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void OperationFinderAstConsumer::Initialize(clang::ASTContext& context)
|
||||||
|
{
|
||||||
|
_visitor.NewContext(&context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinderAstConsumer::HandleTranslationUnit(clang::ASTContext& context)
|
||||||
|
{
|
||||||
|
_visitor.TraverseAST(context);
|
||||||
|
}
|
||||||
27
op-finder/OperationFinderAstConsumer.hpp
Normal file
27
op-finder/OperationFinderAstConsumer.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONFINDERASTCONSUMER_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONFINDERASTCONSUMER_HPP
|
||||||
|
|
||||||
|
#include <clang/AST/ASTConsumer.h>
|
||||||
|
|
||||||
|
#include "OperationFinderAstVisitor.hpp"
|
||||||
|
|
||||||
|
class OperationFinder;
|
||||||
|
|
||||||
|
class OperationFinderAstConsumer : public clang::ASTConsumer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OperationFinderAstConsumer(OperationFinder* op_finder);
|
||||||
|
|
||||||
|
void Initialize(clang::ASTContext& context) override;
|
||||||
|
|
||||||
|
void HandleTranslationUnit(clang::ASTContext& context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OperationFinderAstVisitor _visitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONFINDERASTCONSUMER_HPP
|
||||||
103
op-finder/OperationFinderAstVisitor.cpp
Normal file
103
op-finder/OperationFinderAstVisitor.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationFinderAstVisitor.hpp"
|
||||||
|
|
||||||
|
#include "OperationFinder.hpp"
|
||||||
|
#include "ASTHelpers.hpp"
|
||||||
|
|
||||||
|
OperationFinderAstVisitor::OperationFinderAstVisitor(OperationFinder* op_finder)
|
||||||
|
: _context(nullptr)
|
||||||
|
, _op_finder(op_finder)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void OperationFinderAstVisitor::NewContext(clang::ASTContext* context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OperationFinderAstVisitor::VisitForStmt(clang::ForStmt* stmt)
|
||||||
|
{
|
||||||
|
assert(_context);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OperationFinderAstVisitor::VisitBinaryOperator(clang::BinaryOperator* op)
|
||||||
|
{
|
||||||
|
assert(_context);
|
||||||
|
|
||||||
|
if (!op->isCompoundAssignmentOp())
|
||||||
|
_op_finder->processArithmetic(op, _context->getSourceManager());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OperationFinderAstVisitor::VisitUnaryOperator(clang::UnaryOperator* op)
|
||||||
|
{
|
||||||
|
assert(_context);
|
||||||
|
|
||||||
|
_op_finder->processUnaryArithmetic(op, _context->getSourceManager());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OperationFinderAstVisitor::dataTraverseStmtPre(clang::Stmt* stmt)
|
||||||
|
{
|
||||||
|
assert(_context);
|
||||||
|
|
||||||
|
if (auto* loop = clang::dyn_cast<clang::ForStmt>(stmt))
|
||||||
|
{
|
||||||
|
if (loop->getInit())
|
||||||
|
{
|
||||||
|
_loop_init = loop->getInit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_op_finder->forLoopEntered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_checkIfForLoopInitDone(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OperationFinderAstVisitor::dataTraverseStmtPost(clang::Stmt* stmt)
|
||||||
|
{
|
||||||
|
assert(_context);
|
||||||
|
|
||||||
|
if (clang::dyn_cast<clang::ForStmt>(stmt))
|
||||||
|
_op_finder->forLoopExited();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinderAstVisitor::_checkIfForLoopInitDone(clang::Stmt* stmt)
|
||||||
|
{
|
||||||
|
if (!_loop_init || stmt == _loop_init)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto [file, line, column] = resolveLocationsWithLoc(stmt->getEndLoc(), _context->getSourceManager());
|
||||||
|
const auto [for_file, for_line, for_column] = resolveLocationsWithLoc(_loop_init->getEndLoc(), _context->getSourceManager());
|
||||||
|
|
||||||
|
bool is_done = false;
|
||||||
|
|
||||||
|
if (line > for_line)
|
||||||
|
{
|
||||||
|
is_done = true;
|
||||||
|
}
|
||||||
|
else if (line == for_line && column > for_column)
|
||||||
|
{
|
||||||
|
is_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_done)
|
||||||
|
{
|
||||||
|
_loop_init = nullptr;
|
||||||
|
_op_finder->forLoopEntered();
|
||||||
|
}
|
||||||
|
}
|
||||||
36
op-finder/OperationFinderAstVisitor.hpp
Normal file
36
op-finder/OperationFinderAstVisitor.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 02.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
||||||
|
|
||||||
|
#include <clang/AST/RecursiveASTVisitor.h>
|
||||||
|
|
||||||
|
class OperationFinder;
|
||||||
|
|
||||||
|
class OperationFinderAstVisitor
|
||||||
|
: public clang::RecursiveASTVisitor<OperationFinderAstVisitor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OperationFinderAstVisitor(OperationFinder* op_finder);
|
||||||
|
|
||||||
|
void NewContext(clang::ASTContext* context);
|
||||||
|
|
||||||
|
bool VisitForStmt(clang::ForStmt* stmt);
|
||||||
|
bool VisitBinaryOperator(clang::BinaryOperator* op);
|
||||||
|
bool VisitUnaryOperator(clang::UnaryOperator* op);
|
||||||
|
|
||||||
|
bool dataTraverseStmtPre(clang::Stmt* stmt);
|
||||||
|
bool dataTraverseStmtPost(clang::Stmt* stmt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _checkIfForLoopInitDone(clang::Stmt* stmt);
|
||||||
|
|
||||||
|
clang::ASTContext* _context;
|
||||||
|
OperationFinder* _op_finder;
|
||||||
|
|
||||||
|
clang::Stmt* _loop_init = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
||||||
52
op-finder/OperationLog.hpp
Normal file
52
op-finder/OperationLog.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 28.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONLOG_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONLOG_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct OperationLog
|
||||||
|
{
|
||||||
|
std::string operation;
|
||||||
|
unsigned int line;
|
||||||
|
std::string operand_lhs;
|
||||||
|
std::string operand_rhs;
|
||||||
|
std::string operand_result;
|
||||||
|
std::vector<int> current_for_loops;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IOperationOutput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IOperationOutput() = default;
|
||||||
|
|
||||||
|
virtual void pushOperation(const std::string& filename, const OperationLog& op) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
inline void to_json(nlohmann::json& j, const OperationLog& l)
|
||||||
|
{
|
||||||
|
j = nlohmann::json{
|
||||||
|
{"operation", l.operation},
|
||||||
|
{"line", l.line},
|
||||||
|
{"operand_lhs", l.operand_lhs},
|
||||||
|
{"operand_rhs", l.operand_rhs},
|
||||||
|
{"operand_result", l.operand_result},
|
||||||
|
{"current_for_loops", l.current_for_loops}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void from_json(const nlohmann::json& j, OperationLog& l)
|
||||||
|
{
|
||||||
|
j.at("operation").get_to(l.operation);
|
||||||
|
j.at("line").get_to(l.line);
|
||||||
|
j.at("operand_lhs").get_to(l.operand_lhs);
|
||||||
|
j.at("operand_rhs").get_to(l.operand_rhs);
|
||||||
|
j.at("operand_result").get_to(l.operand_result);
|
||||||
|
j.at("current_for_loops").get_to(l.current_for_loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONLOG_HPP
|
||||||
@ -8,27 +8,6 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include <llvm/Support/CommandLine.h>
|
#include <llvm/Support/CommandLine.h>
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
void to_json(nlohmann::json& j, const OperationStorage::Log& l)
|
|
||||||
{
|
|
||||||
j = nlohmann::json{
|
|
||||||
{"operation", l.operation},
|
|
||||||
{"line", l.line},
|
|
||||||
{"operand_lhs", l.operand_lhs},
|
|
||||||
{"operand_rhs", l.operand_rhs},
|
|
||||||
{"operand_result", l.operand_result}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void from_json(const nlohmann::json& j, OperationStorage::Log& l)
|
|
||||||
{
|
|
||||||
j.at("operation").get_to(l.operation);
|
|
||||||
j.at("line").get_to(l.line);
|
|
||||||
j.at("operand_lhs").get_to(l.operand_lhs);
|
|
||||||
j.at("operand_rhs").get_to(l.operand_rhs);
|
|
||||||
j.at("operand_result").get_to(l.operand_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationStorage::OperationStorage(const std::string& output_filename)
|
OperationStorage::OperationStorage(const std::string& output_filename)
|
||||||
: _output_filename(output_filename)
|
: _output_filename(output_filename)
|
||||||
@ -39,7 +18,7 @@ OperationStorage::~OperationStorage()
|
|||||||
_dumpToFile();
|
_dumpToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationStorage::pushOperation(const std::string& filename, const Log& op)
|
void OperationStorage::pushOperation(const std::string& filename, const OperationLog& op)
|
||||||
{
|
{
|
||||||
auto it = _operations.find(filename);
|
auto it = _operations.find(filename);
|
||||||
|
|
||||||
@ -49,7 +28,7 @@ void OperationStorage::pushOperation(const std::string& filename, const Log& op)
|
|||||||
it->second.push_back(op);
|
it->second.push_back(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, std::vector<OperationStorage::Log>>& OperationStorage::getOperations() const
|
const std::unordered_map<std::string, std::vector<OperationLog>>& OperationStorage::getOperations() const
|
||||||
{
|
{
|
||||||
return _operations;
|
return _operations;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,28 +9,21 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class OperationStorage
|
#include "OperationLog.hpp"
|
||||||
|
|
||||||
|
class OperationStorage : public IOperationOutput
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Log
|
|
||||||
{
|
|
||||||
std::string operation;
|
|
||||||
unsigned int line;
|
|
||||||
std::string operand_lhs;
|
|
||||||
std::string operand_rhs;
|
|
||||||
std::string operand_result;
|
|
||||||
};
|
|
||||||
|
|
||||||
OperationStorage() = delete;
|
OperationStorage() = delete;
|
||||||
OperationStorage(const OperationStorage&) = delete;
|
OperationStorage(const OperationStorage&) = delete;
|
||||||
|
|
||||||
explicit OperationStorage(const std::string& output_filename);
|
explicit OperationStorage(const std::string& output_filename);
|
||||||
~OperationStorage();
|
~OperationStorage() override;
|
||||||
|
|
||||||
void pushOperation(const std::string& filename, const Log& op);
|
void pushOperation(const std::string& filename, const OperationLog& op) override;
|
||||||
[[nodiscard]] const std::unordered_map<std::string, std::vector<Log>>& getOperations() const;
|
[[nodiscard]] const std::unordered_map<std::string, std::vector<OperationLog>>& getOperations() const;
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::vector<Log>> _operations;
|
std::unordered_map<std::string, std::vector<OperationLog>> _operations;
|
||||||
std::string _output_filename;
|
std::string _output_filename;
|
||||||
|
|
||||||
void _dumpToFile();
|
void _dumpToFile();
|
||||||
|
|||||||
@ -5,7 +5,10 @@
|
|||||||
// Declares llvm::cl::extrahelp.
|
// Declares llvm::cl::extrahelp.
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
|
#include "OperationAstMatcher.hpp"
|
||||||
#include "OperationFinder.hpp"
|
#include "OperationFinder.hpp"
|
||||||
|
#include "OperationStorage.hpp"
|
||||||
|
#include "OperationFinderAstAction.hpp"
|
||||||
|
|
||||||
using namespace clang::tooling;
|
using namespace clang::tooling;
|
||||||
using namespace clang::ast_matchers;
|
using namespace clang::ast_matchers;
|
||||||
@ -13,18 +16,21 @@ using namespace llvm;
|
|||||||
|
|
||||||
// Apply a custom category to all command-line options so that they are the
|
// Apply a custom category to all command-line options so that they are the
|
||||||
// only ones displayed.
|
// only ones displayed.
|
||||||
static llvm::cl::OptionCategory MyToolCategory("op-finder options");
|
static cl::OptionCategory MyToolCategory("op-finder options");
|
||||||
|
|
||||||
static llvm::cl::opt<std::string> OutputFile("o", cl::desc("File to output the JSON to."),
|
static cl::opt<std::string> OutputFile("o", cl::desc("File to output the JSON to."),
|
||||||
|
cl::cat(MyToolCategory));
|
||||||
|
|
||||||
|
static cl::opt<std::string> RootDirectory("r", cl::desc("The root directory of the source files."),
|
||||||
cl::cat(MyToolCategory));
|
cl::cat(MyToolCategory));
|
||||||
|
|
||||||
// CommonOptionsParser declares HelpMessage with a description of the common
|
// CommonOptionsParser declares HelpMessage with a description of the common
|
||||||
// command-line options related to the compilation database and input files.
|
// command-line options related to the compilation database and input files.
|
||||||
// It's nice to have this help message in all tools.
|
// It's nice to have this help message in all tools.
|
||||||
static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||||
|
|
||||||
// A help message for this specific tool can be added afterwards.
|
// A help message for this specific tool can be added afterwards.
|
||||||
static llvm::cl::extrahelp MoreHelp("\nThe program takes the input <source0> ... files, parses their\n"
|
static cl::extrahelp MoreHelp("\nThe program takes the input <source0> ... files, parses their\n"
|
||||||
"AST and outputs a singular file containing a list of all noteworthy operations\n"
|
"AST and outputs a singular file containing a list of all noteworthy operations\n"
|
||||||
"for later analysis.\n");
|
"for later analysis.\n");
|
||||||
|
|
||||||
@ -42,10 +48,22 @@ int main(int argc, const char** argv)
|
|||||||
ClangTool Tool(OptionsParser.getCompilations(),
|
ClangTool Tool(OptionsParser.getCompilations(),
|
||||||
OptionsParser.getSourcePathList());
|
OptionsParser.getSourcePathList());
|
||||||
|
|
||||||
OperationFinder op_finder(OutputFile.getValue());
|
OperationStorage storage(OutputFile.getValue());
|
||||||
MatchFinder finder;
|
|
||||||
|
|
||||||
op_finder.addMatcher(finder);
|
OperationFinder op_finder(&storage);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
MatchFinder matcher;
|
||||||
|
OperationASTMatcher finder(&op_finder);
|
||||||
|
|
||||||
|
finder.addToFinder(matcher);
|
||||||
|
|
||||||
|
//Tool.run(newFrontendActionFactory<DebuggeringASTAction>().get());
|
||||||
|
|
||||||
return Tool.run(newFrontendActionFactory(&finder).get());
|
return Tool.run(newFrontendActionFactory(&finder).get());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OperationFinderAstAction action(&op_finder);
|
||||||
|
|
||||||
|
return Tool.run(newFrontendActionFactory(&action).get());
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user