Compare commits

...

5 Commits

17 changed files with 496 additions and 173 deletions

View File

@ -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
View 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

View File

@ -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

View 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);
}
}

View 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

View File

@ -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

View File

@ -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

View 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));
}

View 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

View 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);
}

View 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

View 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();
}
}

View 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

View 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

View File

@ -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;
} }

View File

@ -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();

View File

@ -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());
} }