Compare commits
4 Commits
83ca2deb0e
...
6e27e99735
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e27e99735 | |||
| 326decd3de | |||
| 7b294045bf | |||
| 53c24c6d5e |
@ -1,8 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.17)
|
cmake_minimum_required(VERSION 3.17)
|
||||||
project("C Analyzer")
|
project("C Analyzer")
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
||||||
|
|
||||||
|
option(WITH_TESTS "Build unit tests as well." OFF)
|
||||||
|
|
||||||
|
add_subdirectory(op-finder-lib)
|
||||||
add_subdirectory(op-finder)
|
add_subdirectory(op-finder)
|
||||||
|
|
||||||
|
if(WITH_TESTS)
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(op-finder-tests)
|
||||||
|
endif()
|
||||||
|
|||||||
11
README.md
11
README.md
@ -1,2 +1,13 @@
|
|||||||
# masters-thesis
|
# masters-thesis
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Conan is recommended. Otherwise you have to provide `Catch2_ROOT`
|
||||||
|
and `nlohmann_json_ROOT` yourself.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
> mkdir build
|
||||||
|
> cd build
|
||||||
|
> conan install .. --build=missing
|
||||||
|
> cmake .. -DWITH_TESTS=ON -DClang_ROOT=${CLANG_ROOT} -DLLVM_ROOT=${LLVM_ROOT}
|
||||||
|
```
|
||||||
|
|||||||
6
conanfile.txt
Normal file
6
conanfile.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[requires]
|
||||||
|
catch2/2.13.4
|
||||||
|
nlohmann_json/3.9.1
|
||||||
|
|
||||||
|
[generators]
|
||||||
|
cmake_find_package
|
||||||
25447
dependencies/nlohmann/json.hpp
vendored
25447
dependencies/nlohmann/json.hpp
vendored
File diff suppressed because it is too large
Load Diff
49
op-finder-lib/CMakeLists.txt
Normal file
49
op-finder-lib/CMakeLists.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
|
||||||
|
find_package(nlohmann_json REQUIRED)
|
||||||
|
find_package(Clang REQUIRED)
|
||||||
|
find_package(LLVM REQUIRED COMPONENTS Support Option Core)
|
||||||
|
|
||||||
|
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
||||||
|
# you keep RTTI on and try to link.
|
||||||
|
if (NOT LLVM_ENABLE_RTTI)
|
||||||
|
if (MSVC)
|
||||||
|
string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
|
||||||
|
else ()
|
||||||
|
string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
llvm_map_components_to_libnames(llvm_libs support option core)
|
||||||
|
|
||||||
|
add_library(op-finder-lib STATIC
|
||||||
|
src/OperationFinder.cpp
|
||||||
|
src/OperationStorage.cpp
|
||||||
|
src/OperationAstMatcher.cpp
|
||||||
|
src/OperationFinderAstVisitor.cpp
|
||||||
|
src/OperationFinderAstConsumer.cpp
|
||||||
|
src/OperationFinderAstAction.cpp
|
||||||
|
src/OperationLog.cpp)
|
||||||
|
|
||||||
|
target_include_directories(op-finder-lib
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
${LLVM_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(op-finder-lib
|
||||||
|
PUBLIC
|
||||||
|
${LLVM_DEFINITIONS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(op-finder-lib
|
||||||
|
PUBLIC
|
||||||
|
nlohmann_json::nlohmann_json
|
||||||
|
PRIVATE
|
||||||
|
${llvm_libs}
|
||||||
|
clangTooling
|
||||||
|
clangBasic
|
||||||
|
clangASTMatchers
|
||||||
|
)
|
||||||
@ -14,22 +14,21 @@
|
|||||||
class OperationStorage : public IOperationOutput
|
class OperationStorage : public IOperationOutput
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OperationStorage() = delete;
|
OperationStorage() = default;
|
||||||
OperationStorage(const OperationStorage&) = delete;
|
OperationStorage(const OperationStorage&) = delete;
|
||||||
|
|
||||||
explicit OperationStorage(const std::string& output_filename);
|
|
||||||
~OperationStorage() override;
|
~OperationStorage() override;
|
||||||
|
|
||||||
void enablePrettyPrint();
|
void enablePrettyPrint();
|
||||||
|
void toStream(std::ostream& stream);
|
||||||
|
void toFile(const std::string& output_filename);
|
||||||
|
|
||||||
void pushOperation(const std::string& filename, OperationLog&& op) override;
|
void pushOperation(const std::string& filename, OperationLog&& op) override;
|
||||||
[[nodiscard]] const std::unordered_map<std::string, std::vector<OperationLog>>& getOperations() const;
|
[[nodiscard]] const std::unordered_map<std::string, std::vector<OperationLog>>& getOperations() const;
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::vector<OperationLog>> _operations;
|
std::unordered_map<std::string, std::vector<OperationLog>> _operations;
|
||||||
std::string _output_filename;
|
|
||||||
|
|
||||||
bool _pretty_print = false;
|
bool _pretty_print = false;
|
||||||
|
|
||||||
void _dumpToFile();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONSTORAGE_HPP
|
#endif //C_ANALYZER_OPERATIONSTORAGE_HPP
|
||||||
@ -1,4 +1,4 @@
|
|||||||
//
|
//src
|
||||||
// Created by erki on 02.03.21.
|
// Created by erki on 02.03.21.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -9,20 +9,32 @@
|
|||||||
|
|
||||||
#include <llvm/Support/CommandLine.h>
|
#include <llvm/Support/CommandLine.h>
|
||||||
|
|
||||||
OperationStorage::OperationStorage(const std::string& output_filename)
|
|
||||||
: _output_filename(output_filename)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
OperationStorage::~OperationStorage()
|
OperationStorage::~OperationStorage()
|
||||||
{
|
{ }
|
||||||
_dumpToFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationStorage::enablePrettyPrint()
|
void OperationStorage::enablePrettyPrint()
|
||||||
{
|
{
|
||||||
_pretty_print = true;
|
_pretty_print = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OperationStorage::toStream(std::ostream& stream)
|
||||||
|
{
|
||||||
|
nlohmann::json json = _operations;
|
||||||
|
|
||||||
|
if (_pretty_print)
|
||||||
|
stream << std::setw(4) << json;
|
||||||
|
else
|
||||||
|
stream << json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationStorage::toFile(const std::string& output_filename)
|
||||||
|
{
|
||||||
|
std::ofstream file(output_filename);
|
||||||
|
|
||||||
|
toStream(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void OperationStorage::pushOperation(const std::string& filename, OperationLog&& op)
|
void OperationStorage::pushOperation(const std::string& filename, OperationLog&& op)
|
||||||
{
|
{
|
||||||
auto it = _operations.find(filename);
|
auto it = _operations.find(filename);
|
||||||
@ -37,15 +49,3 @@ const std::unordered_map<std::string, std::vector<OperationLog>>& OperationStora
|
|||||||
{
|
{
|
||||||
return _operations;
|
return _operations;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OperationStorage::_dumpToFile()
|
|
||||||
{
|
|
||||||
nlohmann::json json = _operations;
|
|
||||||
|
|
||||||
std::ofstream file(_output_filename);
|
|
||||||
|
|
||||||
if (_pretty_print)
|
|
||||||
file << std::setw(4) << json;
|
|
||||||
else
|
|
||||||
file << json;
|
|
||||||
}
|
|
||||||
30
op-finder-tests/CMakeLists.txt
Normal file
30
op-finder-tests/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
|
||||||
|
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
||||||
|
# you keep RTTI on and try to link.
|
||||||
|
if (NOT LLVM_ENABLE_RTTI)
|
||||||
|
if (MSVC)
|
||||||
|
string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
|
||||||
|
else ()
|
||||||
|
string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
add_executable(op-finder-tests
|
||||||
|
main.cpp
|
||||||
|
fixtures/RunOnCodeFixture.cpp
|
||||||
|
basic_operations.cpp
|
||||||
|
branches.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(op-finder-tests
|
||||||
|
PUBLIC
|
||||||
|
op-finder-lib
|
||||||
|
Catch2::Catch2)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
catch_discover_tests(op-finder-tests)
|
||||||
95
op-finder-tests/basic_operations.cpp
Normal file
95
op-finder-tests/basic_operations.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 07.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "fixtures/RunOnCodeFixture.hpp"
|
||||||
|
|
||||||
|
TEST_CASE("Finds binary operations", "[basic_operation]")
|
||||||
|
{
|
||||||
|
auto binary_operand = GENERATE(std::string("="), std::string("+"), std::string("-"), std::string("/"),
|
||||||
|
std::string("*"), std::string("<<"), std::string(">>"),
|
||||||
|
std::string("^"), std::string("=="), std::string("|"), std::string("&"));
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; (void)(a " + binary_operand + " 4); }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 1);
|
||||||
|
|
||||||
|
const OperationLog& log = operations.front();
|
||||||
|
|
||||||
|
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
||||||
|
|
||||||
|
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
||||||
|
|
||||||
|
REQUIRE(op->operation_name == binary_operand);
|
||||||
|
REQUIRE(op->type_lhs == "int");
|
||||||
|
REQUIRE(op->type_rhs == "int");
|
||||||
|
REQUIRE(op->type_result == "int");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Find unary operations", "[basic_operation]")
|
||||||
|
{
|
||||||
|
auto unary_operand = GENERATE(std::string("++"), std::string("--"), std::string("~"), std::string("!"));
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; (void)(" + unary_operand + "a); }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 1);
|
||||||
|
|
||||||
|
const OperationLog& log = operations.front();
|
||||||
|
|
||||||
|
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
||||||
|
|
||||||
|
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
||||||
|
|
||||||
|
REQUIRE(op->operation_name == unary_operand);
|
||||||
|
REQUIRE(op->type_lhs == "int");
|
||||||
|
REQUIRE(op->type_rhs.empty());
|
||||||
|
REQUIRE(op->type_result == "int");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Find subscript operation", "[basic_operation]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a[4]; (void)a[4]; }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 1);
|
||||||
|
|
||||||
|
const OperationLog& log = operations.front();
|
||||||
|
|
||||||
|
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
||||||
|
|
||||||
|
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
||||||
|
|
||||||
|
REQUIRE(op->operation_name == "subscript");
|
||||||
|
REQUIRE(op->type_lhs == "int *");
|
||||||
|
REQUIRE(op->type_rhs == "int");
|
||||||
|
REQUIRE(op->type_result == "int");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Find subscript operation reversed", "[basic_operation]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a[4]; (void)4[a]; }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 1);
|
||||||
|
|
||||||
|
const OperationLog& log = operations.front();
|
||||||
|
|
||||||
|
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
||||||
|
|
||||||
|
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
||||||
|
|
||||||
|
REQUIRE(op->operation_name == "subscript");
|
||||||
|
REQUIRE(op->type_lhs == "int *");
|
||||||
|
REQUIRE(op->type_rhs == "int");
|
||||||
|
REQUIRE(op->type_result == "int");
|
||||||
|
}
|
||||||
125
op-finder-tests/branches.cpp
Normal file
125
op-finder-tests/branches.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 07.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "fixtures/RunOnCodeFixture.hpp"
|
||||||
|
|
||||||
|
TEST_CASE("For loop without header", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (;;) {} }";
|
||||||
|
REQUIRE(fixture.runCode(code));
|
||||||
|
|
||||||
|
REQUIRE(fixture.storage.getOperations().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("For loop with init only.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (a = 4;;) {} }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 1);
|
||||||
|
|
||||||
|
const OperationLog& log = operations.front();
|
||||||
|
|
||||||
|
REQUIRE(log.branch_number == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("For loop with init & cond.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (a = 4; a < 4;) {} }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 2);
|
||||||
|
|
||||||
|
const OperationLog& log_init = operations.at(0);
|
||||||
|
REQUIRE(log_init.branch_number == 1);
|
||||||
|
|
||||||
|
const OperationLog& log_cond = operations.at(1);
|
||||||
|
REQUIRE(log_cond.branch_number == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("For loop with init & inc.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (a = 4;;a++) {} }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 2);
|
||||||
|
|
||||||
|
const OperationLog& log_init = operations.at(0);
|
||||||
|
REQUIRE(log_init.branch_number == 1);
|
||||||
|
|
||||||
|
const OperationLog& log_inc = operations.at(1);
|
||||||
|
REQUIRE(log_inc.branch_number == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("For loop with full header.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (a = 4; a < 4 ;a++) {} }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 3);
|
||||||
|
|
||||||
|
const OperationLog& log_init = operations.at(0);
|
||||||
|
REQUIRE(log_init.branch_number == 1);
|
||||||
|
|
||||||
|
const OperationLog& log_cond = operations.at(1);
|
||||||
|
REQUIRE(log_cond.branch_number == 2);
|
||||||
|
|
||||||
|
const OperationLog& log_inc = operations.at(2);
|
||||||
|
REQUIRE(log_inc.branch_number == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("For loop without init.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (;a < 4 ;a++) {} }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 2);
|
||||||
|
|
||||||
|
const OperationLog& log_cond = operations.at(0);
|
||||||
|
REQUIRE(log_cond.branch_number == 0);
|
||||||
|
|
||||||
|
const OperationLog& log_inc = operations.at(1);
|
||||||
|
REQUIRE(log_inc.branch_number == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("For loop closes branches inside the loop.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (a = 4; a < 4 ; a++) { a = 5; } }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 4);
|
||||||
|
|
||||||
|
const OperationLog& log_inner = operations.back();
|
||||||
|
REQUIRE(log_inner.branch_number == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("For loop closes branches outside the loop.", "[branches][for_loops]")
|
||||||
|
{
|
||||||
|
RunOnCodeFixture fixture;
|
||||||
|
|
||||||
|
const std::string code = "int main() { int a; for (a = 4; a < 4 ; a++) {} a = 5; }";
|
||||||
|
const auto& operations = fixture(code);
|
||||||
|
|
||||||
|
REQUIRE(operations.size() == 4);
|
||||||
|
|
||||||
|
const OperationLog& log_outer = operations.back();
|
||||||
|
REQUIRE(log_outer.branch_number == 0);
|
||||||
|
}
|
||||||
37
op-finder-tests/fixtures/RunOnCodeFixture.cpp
Normal file
37
op-finder-tests/fixtures/RunOnCodeFixture.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 07.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "RunOnCodeFixture.hpp"
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include <clang/Tooling/Tooling.h>
|
||||||
|
#include <clang/Frontend/FrontendActions.h>
|
||||||
|
|
||||||
|
RunOnCodeFixture::RunOnCodeFixture()
|
||||||
|
: finder(&storage)
|
||||||
|
, action(&finder)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool RunOnCodeFixture::runCode(const std::string& code)
|
||||||
|
{
|
||||||
|
return clang::tooling::runToolOnCode(
|
||||||
|
clang::tooling::newFrontendActionFactory(&action)->create(),
|
||||||
|
code,
|
||||||
|
RunOnCodeFixture::INPUT_FILE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<OperationLog>& RunOnCodeFixture::operator()(const std::string& code)
|
||||||
|
{
|
||||||
|
const bool success = runCode(code);
|
||||||
|
|
||||||
|
REQUIRE(success);
|
||||||
|
|
||||||
|
const auto& operations = storage.getOperations();
|
||||||
|
|
||||||
|
REQUIRE(operations.count(RunOnCodeFixture::INPUT_FILE) == 1);
|
||||||
|
|
||||||
|
return operations.at(RunOnCodeFixture::INPUT_FILE);
|
||||||
|
}
|
||||||
27
op-finder-tests/fixtures/RunOnCodeFixture.hpp
Normal file
27
op-finder-tests/fixtures/RunOnCodeFixture.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 07.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_RUNONCODEFIXTURE_HPP
|
||||||
|
#define C_ANALYZER_RUNONCODEFIXTURE_HPP
|
||||||
|
|
||||||
|
#include <OperationStorage.hpp>
|
||||||
|
#include <OperationFinder.hpp>
|
||||||
|
#include <OperationFinderAstAction.hpp>
|
||||||
|
|
||||||
|
struct RunOnCodeFixture
|
||||||
|
{
|
||||||
|
constexpr static char INPUT_FILE[] = "input.c";
|
||||||
|
|
||||||
|
OperationStorage storage;
|
||||||
|
OperationFinder finder;
|
||||||
|
OperationFinderAstAction action;
|
||||||
|
|
||||||
|
RunOnCodeFixture();
|
||||||
|
|
||||||
|
bool runCode(const std::string& code);
|
||||||
|
|
||||||
|
const std::vector<OperationLog>& operator()(const std::string& code);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_RUNONCODEFIXTURE_HPP
|
||||||
6
op-finder-tests/main.cpp
Normal file
6
op-finder-tests/main.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 07.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
@ -1,8 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.17)
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
|
||||||
find_package(Clang REQUIRED)
|
|
||||||
find_package(LLVM REQUIRED COMPONENTS Support Option Core)
|
|
||||||
|
|
||||||
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
||||||
# you keep RTTI on and try to link.
|
# you keep RTTI on and try to link.
|
||||||
if (NOT LLVM_ENABLE_RTTI)
|
if (NOT LLVM_ENABLE_RTTI)
|
||||||
@ -15,33 +12,9 @@ if (NOT LLVM_ENABLE_RTTI)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
llvm_map_components_to_libnames(llvm_libs support option core)
|
|
||||||
|
|
||||||
add_executable(op-finder
|
add_executable(op-finder
|
||||||
main.cpp
|
main.cpp)
|
||||||
OperationFinder.cpp
|
|
||||||
OperationStorage.cpp
|
|
||||||
OperationAstMatcher.cpp
|
|
||||||
OperationFinderAstVisitor.cpp
|
|
||||||
OperationFinderAstConsumer.cpp
|
|
||||||
OperationFinderAstAction.cpp
|
|
||||||
OperationLog.cpp)
|
|
||||||
|
|
||||||
target_include_directories(op-finder
|
|
||||||
PRIVATE
|
|
||||||
${LLVM_INCLUDE_DIRS}
|
|
||||||
${PROJECT_SOURCE_DIR}/dependencies
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_definitions(op-finder
|
|
||||||
PRIVATE
|
|
||||||
${LLVM_DEFINITIONS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(op-finder
|
target_link_libraries(op-finder
|
||||||
PRIVATE
|
PUBLIC
|
||||||
${llvm_libs}
|
op-finder-lib)
|
||||||
clangTooling
|
|
||||||
clangBasic
|
|
||||||
clangASTMatchers
|
|
||||||
)
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
// Declares llvm::cl::extrahelp.
|
// Declares llvm::cl::extrahelp.
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "OperationAstMatcher.hpp"
|
#include "OperationAstMatcher.hpp"
|
||||||
#include "OperationFinder.hpp"
|
#include "OperationFinder.hpp"
|
||||||
#include "OperationStorage.hpp"
|
#include "OperationStorage.hpp"
|
||||||
@ -50,7 +52,7 @@ int main(int argc, const char** argv)
|
|||||||
ClangTool Tool(OptionsParser.getCompilations(),
|
ClangTool Tool(OptionsParser.getCompilations(),
|
||||||
OptionsParser.getSourcePathList());
|
OptionsParser.getSourcePathList());
|
||||||
|
|
||||||
OperationStorage storage(OutputFile.getValue());
|
OperationStorage storage;
|
||||||
|
|
||||||
if (PrettyPrint.getValue())
|
if (PrettyPrint.getValue())
|
||||||
storage.enablePrettyPrint();
|
storage.enablePrettyPrint();
|
||||||
@ -70,5 +72,10 @@ int main(int argc, const char** argv)
|
|||||||
|
|
||||||
OperationFinderAstAction action(&op_finder);
|
OperationFinderAstAction action(&op_finder);
|
||||||
|
|
||||||
return Tool.run(newFrontendActionFactory(&action).get());
|
assert(!Tool.run(newFrontendActionFactory(&action).get()));
|
||||||
|
|
||||||
|
if (!OutputFile.getValue().empty())
|
||||||
|
storage.toFile(OutputFile.getValue());
|
||||||
|
else
|
||||||
|
storage.toStream(std::cout);
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user