Compare commits

..

3 Commits

Author SHA1 Message Date
b609c48bfe .idea configuration 2021-02-28 18:54:29 +02:00
cff605642f Add output serialization to JSON file. 2021-02-28 18:50:09 +02:00
375e3f9af6 Add nlohmann::json as a dependency. 2021-02-28 18:49:23 +02:00
16 changed files with 25784 additions and 61 deletions

66
.clang-format Normal file
View File

@ -0,0 +1,66 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignOperands: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterUnion: true
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeComma
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 2
UseTab: Never

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
C Analyzer

2
.idea/analyzer.git.iml generated Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

54
.idea/codeStyles/Project.xml generated Normal file
View File

@ -0,0 +1,54 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
<option name="INDENT_CLASS_MEMBERS" value="2" />
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
<option name="NAMESPACE_BRACE_PLACEMENT" value="2" />
<option name="FUNCTION_BRACE_PLACEMENT" value="2" />
<option name="BLOCK_BRACE_PLACEMENT" value="2" />
<option name="SUPERCLASS_LIST_COMMA_ON_NEXT_LINE" value="true" />
<option name="SPACE_WITHIN_EMPTY_BRACES" value="true" />
<option name="SPACE_BEFORE_POINTER_IN_DECLARATION" value="false" />
<option name="SPACE_AFTER_POINTER_IN_DECLARATION" value="true" />
<option name="SPACE_BEFORE_REFERENCE_IN_DECLARATION" value="false" />
<option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" />
</Objective-C>
<Objective-C-extensions>
<extensions>
<pair source="cpp" header="hpp" fileNamingConvention="PASCAL_CASE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
<pair source="cu" header="cuh" fileNamingConvention="NONE" />
</extensions>
<rules>
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
<rule entity="CLASS_MEMBER_FUNCTION,STRUCT_MEMBER_FUNCTION" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="PASCAL_CASE" suffix="" />
</rules>
</Objective-C-extensions>
<codeStyleSettings language="ObjectiveC">
<option name="BRACE_STYLE" value="2" />
<option name="CLASS_BRACE_STYLE" value="2" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

4
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/analyzer.git.iml" filepath="$PROJECT_DIR$/.idea/analyzer.git.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

25447
dependencies/nlohmann/json.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -20,10 +20,13 @@ llvm_map_components_to_libnames(llvm_libs support option core)
add_executable(op-finder add_executable(op-finder
main.cpp main.cpp
OperationFinder.cpp OperationFinder.cpp
OperationStorage.cpp
) )
target_include_directories(op-finder target_include_directories(op-finder
PRIVATE ${LLVM_INCLUDE_DIRS} PRIVATE
${LLVM_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/dependencies
) )
target_compile_definitions(op-finder target_compile_definitions(op-finder

View File

@ -5,7 +5,6 @@
#include "OperationFinder.hpp" #include "OperationFinder.hpp"
#include <iostream> #include <iostream>
#include <sstream>
using namespace clang; using namespace clang;
using namespace clang::ast_matchers; using namespace clang::ast_matchers;
@ -50,13 +49,28 @@ SourceLocation ResolveOperationSourceLocation(const SourceManager& source_manage
return 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) void OperationFinder::addMatcher(MatchFinder &finder)
{ {
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this); finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this);
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this); finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this);
//finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, CompoundMatcher), this);
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, UnaryArithmeticMatcher), this); finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, UnaryArithmeticMatcher), this);
} }
@ -70,10 +84,6 @@ void OperationFinder::run(const MatchFinder::MatchResult &result)
{ {
_processArithmetic(result); _processArithmetic(result);
} }
else if (result.Nodes.getNodeAs<clang::CompoundStmt>("compound_stmt"))
{
_processCompoundStmt(result);
}
else if (result.Nodes.getNodeAs<clang::UnaryOperator>("unary_arithmetic")) else if (result.Nodes.getNodeAs<clang::UnaryOperator>("unary_arithmetic"))
{ {
_processUnaryArithmetic(result); _processUnaryArithmetic(result);
@ -86,15 +96,20 @@ void OperationFinder::_processAssignment(const clang::ast_matchers::MatchFinder:
assert(op); assert(op);
const auto& source_manager = *result.SourceManager; const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":" llvm::outs() << file_name << ":"
<< source_manager.getSpellingLineNumber(loc) << ":" << line_number << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":" << column_number << ":"
<< "Assignment: Assigned to: "; << "Assignment: Assigned to: ";
_processExpressionTypes(op, op->getLHS(), op->getRHS()); OperationStorage::Log log;
log.line = line_number;
log.operation = "=";
_processExpressionTypes(log, op, op->getLHS(), op->getRHS());
_storage.pushOperation(file_name, log);
llvm::outs() << "\n"; llvm::outs() << "\n";
} }
@ -105,39 +120,20 @@ void OperationFinder::_processArithmetic(const MatchFinder::MatchResult& result)
assert(op); assert(op);
const auto& source_manager = *result.SourceManager; const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":" llvm::outs() << file_name << ":"
<< source_manager.getSpellingLineNumber(loc) << ":" << line_number << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":" << column_number << ":"
<< "Arithmetic: Type: " << getOpcode(op) << " LHS: "; << "Binary arithmetic: Type: " << getOpcode(op) << " LHS: ";
_processExpressionTypes(op, op->getLHS(), op->getRHS()); OperationStorage::Log log;
log.line = line_number;
log.operation = getOpcode(op).str();
llvm::outs() << "\n"; _processExpressionTypes(log, op, op->getLHS(), op->getRHS());
}
void OperationFinder::_processCompoundStmt(const clang::ast_matchers::MatchFinder::MatchResult& result) _storage.pushOperation(file_name, log);
{
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"; llvm::outs() << "\n";
} }
@ -150,22 +146,28 @@ void OperationFinder::_processUnaryArithmetic(const MatchFinder::MatchResult &re
assert(op); assert(op);
assert(lhs); assert(lhs);
const auto& source_manager = *result.SourceManager; const auto [file_name, line_number, column_number] = resolveLocations(op, *result.SourceManager);
const auto& loc = ResolveOperationSourceLocation(source_manager, op->getBeginLoc());
llvm::outs() << source_manager.getFilename(loc) << ":" llvm::outs() << file_name << ":"
<< source_manager.getSpellingLineNumber(loc) << ":" << line_number << ":"
<< source_manager.getSpellingColumnNumber(loc) << ":" << column_number << ":"
<< "Unary arithmetic: Type: " << getOpcode(op) << " LHS: "; << "Unary arithmetic: Type: " << getOpcode(op) << " LHS: ";
_processExpressionTypes(op, lhs, nullptr); OperationStorage::Log log;
log.line = line_number;
log.operation = getOpcode(op).str();
_processExpressionTypes(log, op, lhs, nullptr);
_storage.pushOperation(file_name, log);
llvm::outs() << "\n"; llvm::outs() << "\n";
} }
void OperationFinder::_processExpressionTypes(const Expr* source, const Expr* op1, const Expr* op2) void OperationFinder::_processExpressionTypes(OperationStorage::Log& log, const Expr* source, const Expr* op1, const Expr* op2)
{ {
auto printTypeName = [](const QualType& t) -> void
auto printTypeName = [](const QualType& t) -> std::string
{ {
if (t->isTypedefNameType()) if (t->isTypedefNameType())
{ {
@ -174,28 +176,32 @@ void OperationFinder::_processExpressionTypes(const Expr* source, const Expr* op
llvm::outs() << "Typedef type: " << t.getAsString() llvm::outs() << "Typedef type: " << t.getAsString()
<< ", underlying: " << tdt->desugar().getAsString() << ", underlying: " << tdt->desugar().getAsString()
<< "."; << ".";
return tdt->desugar().getAsString();
} }
else if (t->isBuiltinType()) else if (t->isBuiltinType())
{ {
llvm::outs() << "Builtin type: " << t.getAsString() << "."; llvm::outs() << "Builtin type: " << t.getAsString() << ".";
return t.getAsString();
} }
else else
{ {
llvm::outs() << "Other type: " << t.getAsString() << "."; llvm::outs() << "Other type: " << t.getAsString() << ".";
return t.getAsString();
} }
}; };
llvm::outs() << "Expression types:\n\tExpression eval type: "; llvm::outs() << "Expression types:\n\tExpression eval type: ";
printTypeName(source->getType()); log.operand_result = printTypeName(source->getType());
if (op1) if (op1)
{ {
llvm::outs() << "\n\tLHS eval type: "; llvm::outs() << "\n\tLHS eval type: ";
printTypeName(op1->getType()); log.operand_lhs = printTypeName(op1->getType());
} }
if (op2) if (op2)
{ {
llvm::outs() << "\n\tRHS eval type: "; llvm::outs() << "\n\tRHS eval type: ";
printTypeName(op2->getType()); log.operand_rhs = printTypeName(op2->getType());
} }
} }

View File

@ -8,19 +8,24 @@
#include <clang/ASTMatchers/ASTMatchers.h> #include <clang/ASTMatchers/ASTMatchers.h>
#include <clang/ASTMatchers/ASTMatchFinder.h> #include <clang/ASTMatchers/ASTMatchFinder.h>
#include "OperationStorage.hpp"
class OperationFinder : public clang::ast_matchers::MatchFinder::MatchCallback class OperationFinder : public clang::ast_matchers::MatchFinder::MatchCallback
{ {
public: public:
OperationFinder(const std::string& output_dir);
void addMatcher(clang::ast_matchers::MatchFinder& finder); void addMatcher(clang::ast_matchers::MatchFinder& finder);
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override; void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override;
private: private:
void _processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result); void _processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result);
void _processArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result); void _processArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result);
void _processCompoundStmt(const clang::ast_matchers::MatchFinder::MatchResult& result);
void _processUnaryArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result); void _processUnaryArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result);
void _processExpressionTypes(const clang::Expr* source, const clang::Expr* op1, const clang::Expr* op2); void _processExpressionTypes(OperationStorage::Log& log, const clang::Expr* source, const clang::Expr* op1, const clang::Expr* op2);
OperationStorage _storage;
}; };
#endif //LLVM_PROTO_OPERATIONFINDER_HPP #endif //LLVM_PROTO_OPERATIONFINDER_HPP

View File

@ -0,0 +1,64 @@
//
// Created by erki on 28.02.21.
//
#include "OperationStorage.hpp"
#include <fstream>
#include <filesystem>
#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)
: _output_filename(output_filename)
{ }
OperationStorage::~OperationStorage()
{
_dumpToFile();
}
void OperationStorage::pushOperation(const std::string& filename, const Log& op)
{
auto it = _operations.find(filename);
if (it == _operations.end())
it = _operations.insert({ filename, {} }).first;
it->second.push_back(op);
}
const std::unordered_map<std::string, std::vector<OperationStorage::Log>>& OperationStorage::getOperations() const
{
return _operations;
}
void OperationStorage::_dumpToFile()
{
nlohmann::json json = _operations;
std::ofstream file(_output_filename);
file << json;
}

View File

@ -0,0 +1,39 @@
//
// Created by erki on 28.02.21.
//
#ifndef C_ANALYZER_OPERATIONSTORAGE_HPP
#define C_ANALYZER_OPERATIONSTORAGE_HPP
#include <string>
#include <unordered_map>
#include <vector>
class OperationStorage
{
public:
struct Log
{
std::string operation;
unsigned int line;
std::string operand_lhs;
std::string operand_rhs;
std::string operand_result;
};
OperationStorage() = delete;
OperationStorage(const OperationStorage&) = delete;
explicit OperationStorage(const std::string& output_filename);
~OperationStorage();
void pushOperation(const std::string& filename, const Log& op);
[[nodiscard]] const std::unordered_map<std::string, std::vector<Log>>& getOperations() const;
private:
std::unordered_map<std::string, std::vector<Log>> _operations;
std::string _output_filename;
void _dumpToFile();
};
#endif //C_ANALYZER_OPERATIONSTORAGE_HPP

View File

@ -13,15 +13,20 @@ 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("opcounter options"); static llvm::cl::OptionCategory MyToolCategory("op-finder options");
static llvm::cl::opt<std::string> OutputFile("o", cl::desc("File to output the JSON to."),
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 cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); static llvm::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 cl::extrahelp MoreHelp("\nMore help text...\n"); static llvm::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"
"for later analysis.\n");
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
@ -37,7 +42,7 @@ int main(int argc, const char** argv)
ClangTool Tool(OptionsParser.getCompilations(), ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList()); OptionsParser.getSourcePathList());
OperationFinder op_finder; OperationFinder op_finder(OutputFile.getValue());
MatchFinder finder; MatchFinder finder;
op_finder.addMatcher(finder); op_finder.addMatcher(finder);