From d8e66dcbcc20c82ce2dcfd7a0bdb66c731c47638 Mon Sep 17 00:00:00 2001 From: Nicolas van Kempen Date: Wed, 4 Sep 2024 23:39:08 -0400 Subject: [PATCH] Delete mutations directory --- mutations/.gitignore | 1 - mutations/CMakeLists.txt | 45 -------- mutations/README.md | 19 ---- mutations/src/main.cpp | 214 --------------------------------------- 4 files changed, 279 deletions(-) delete mode 100644 mutations/.gitignore delete mode 100644 mutations/CMakeLists.txt delete mode 100644 mutations/README.md delete mode 100644 mutations/src/main.cpp diff --git a/mutations/.gitignore b/mutations/.gitignore deleted file mode 100644 index 378eac2..0000000 --- a/mutations/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/mutations/CMakeLists.txt b/mutations/CMakeLists.txt deleted file mode 100644 index 3b5e709..0000000 --- a/mutations/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(CWhyMutations) - -include(FetchContent) -include(CheckIPOSupported) - -set(CMAKE_CXX_STANDARD 20) - -find_package(LLVM REQUIRED CONFIG) -find_package(Clang REQUIRED CONFIG) -message(STATUS "Found LLVM/Clang ${LLVM_PACKAGE_VERSION}") - -FetchContent_Declare( - boost - GIT_REPOSITORY https://github.com/boostorg/boost.git - GIT_TAG b6928ae5c92e21a04bbe17a558e6e066dbe632f6 # boost-1.82.0 -) - -message(STATUS "Downloading and configuring Boost") -FetchContent_MakeAvailable(boost) - -FetchContent_Declare( - range-v3 - GIT_REPOSITORY https://github.com/ericniebler/range-v3.git - GIT_TAG a81477931a8aa2ad025c6bda0609f38e09e4d7ec # 0.12.0 -) - -message(STATUS "Downloading and configuring Range-v3") -FetchContent_MakeAvailable(range-v3) - -add_executable(mutations src/main.cpp) -target_compile_options(mutations PRIVATE -Wall -Wextra -Wpedantic -Werror) -target_include_directories(mutations SYSTEM PRIVATE ${CLANG_INCLUDE_DIRS}) -target_link_libraries(mutations PRIVATE Boost::program_options) -target_link_libraries(mutations PRIVATE clangAST clangASTMatchers clangFrontend clangTooling) -target_link_libraries(mutations PRIVATE range-v3) - -check_ipo_supported(RESULT IPO_SUPPORTED) -if(IPO_SUPPORTED) - message(STATUS "IPO/LTO supported") - set_property(TARGET mutations PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) -else() - message(STATUS "IPO/LTO not supported") -endif() diff --git a/mutations/README.md b/mutations/README.md deleted file mode 100644 index 344afe8..0000000 --- a/mutations/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Mutations - -> **Warning** -> Experimental. - -The goal of this sub-project is to automatically generate small mutations in C++ source files, and then see if CWhy is -capable of providing a fix returning to the original source code. - -## Build - -``` -[~] sudo apt install -y llvm-15 clang-15 libclang-15-dev -[cwhy/mutations] cmake . \ - -B build \ - -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DLLVM_DIR=/usr/lib/llvm-15/lib/cmake/llvm \ - -DClang_DIR=/usr/lib/llvm-15/lib/cmake/clang -``` diff --git a/mutations/src/main.cpp b/mutations/src/main.cpp deleted file mode 100644 index 2e0c54f..0000000 --- a/mutations/src/main.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace { -std::size_t getRandom(std::size_t max) { - std::random_device generator; - return std::uniform_int_distribution(0, max - 1)(generator); -} - -template -Iterator getRandom(Iterator begin, Iterator end) { - std::advance(begin, getRandom(std::distance(begin, end))); - return begin; -} - -[[maybe_unused]] std::vector getAllFunctionDeclarations(clang::ASTContext& context) { - using namespace clang::ast_matchers; - const auto matcher = functionDecl(isExpansionInMainFile(), isDefinition(), unless(isImplicit())).bind("root"); - const auto matches = match(matcher, context); - - std::vector declarations; - for (const auto& match : matches) { - declarations.push_back(match.getNodeAs("root")); - } - - return declarations; -} - -[[maybe_unused]] std::vector getAllFunctionCallExpressions(clang::ASTContext& context) { - using namespace clang::ast_matchers; - const auto matcher = callExpr(isExpansionInMainFile(), unless(cxxOperatorCallExpr())).bind("root"); - const auto matches = match(matcher, context); - - std::vector declarations; - for (const auto& match : matches) { - declarations.push_back(match.getNodeAs("root")); - } - - return declarations; -} - -std::optional flipSourceRanges(const clang::SourceRange& a, const clang::SourceRange& b, - const clang::SourceManager& sm, - const clang::LangOptions& lo) { - const auto firstSourceRange = clang::CharSourceRange::getTokenRange(a); - const auto secondSourceRange = clang::CharSourceRange::getTokenRange(b); - - const auto firstSourceText = clang::Lexer::getSourceText(firstSourceRange, sm, lo); - const auto secondSourceText = clang::Lexer::getSourceText(secondSourceRange, sm, lo); - - clang::tooling::Replacements replacements; - if (auto error = replacements.add(clang::tooling::Replacement(sm, firstSourceRange, secondSourceText, lo))) { - return std::nullopt; - } - - if (auto error = replacements.add(clang::tooling::Replacement(sm, secondSourceRange, firstSourceText, lo))) { - return std::nullopt; - } - - return replacements; -} - -std::optional flipFunctionParameters(const clang::FunctionDecl& f, - clang::ASTContext& context) { - if (f.getNumParams() < 2) { - return std::nullopt; - } - - const auto first = getRandom(f.getNumParams()); - const auto options = ranges::views::iota(0u, f.getNumParams()) | ranges::views::filter([&](auto index) { - return f.getParamDecl(index)->getType() != f.getParamDecl(first)->getType(); - }) - | ranges::to(); - - if (options.empty()) { - return std::nullopt; - } - - const auto second = *getRandom(options.begin(), options.end()); - - return flipSourceRanges(f.getParamDecl(first)->getSourceRange(), f.getParamDecl(second)->getSourceRange(), - context.getSourceManager(), context.getLangOpts()); -} - -std::optional flipFunctionCallArguments(const clang::CallExpr& e, - clang::ASTContext& context) { - if (e.getNumArgs() < 2) { - return std::nullopt; - } - - const auto nonDefaultArguments = ranges::views::iota(0u, e.getNumArgs()) | ranges::views::filter([&](auto index) { - using namespace clang::ast_matchers; - const auto matches = match(cxxDefaultArgExpr(), *e.getArg(index), context); - return matches.empty(); - }) - | ranges::to(); - - const auto first = *getRandom(nonDefaultArguments.begin(), nonDefaultArguments.end()); - const auto options - = nonDefaultArguments - | ranges::views::filter([&](auto index) { return e.getArg(index)->getType() != e.getArg(first)->getType(); }) - | ranges::to(); - - if (options.empty()) { - return std::nullopt; - } - - const auto second = *getRandom(options.begin(), options.end()); - - return flipSourceRanges(e.getArg(first)->getSourceRange(), e.getArg(second)->getSourceRange(), - context.getSourceManager(), context.getLangOpts()); -} -} // namespace - -int main(int argc, char** argv) { - namespace po = boost::program_options; - - po::options_description required("Required options"); - po::options_description optional("Optional options"); - - // clang-format off - required.add_options() - ("compile-commands,p", po::value()->required(), "path to compile_commands.json") - ("filename", po::value()->required(), "path to the file to mutate"); - - optional.add_options() - ("help", "produce help message"); - // clang-format on - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, po::options_description().add(required).add(optional)), vm); - - if (vm.count("help")) { - std::cout << required << std::endl; - std::cout << optional << std::endl; - return 1; - } - - try { - po::notify(vm); - } catch (const po::error& e) { - std::cerr << "Error: " << e.what() << std::endl; - std::cerr << std::endl; - std::cerr << required << std::endl; - return 1; - } - - std::string error; - const auto database = clang::tooling::JSONCompilationDatabase::loadFromFile( - vm.at("compile-commands").as(), error, clang::tooling::JSONCommandLineSyntax::AutoDetect); - if (!database) { - std::cerr << "Could not load compilation database." << std::endl << error << std::endl; - return 1; - } - - clang::tooling::ClangTool tool(*database, {vm.at("filename").as()}); - std::vector> ASTs; - if (tool.buildASTs(ASTs) != 0) { - std::cerr << "Failed to build the AST." << std::endl; - return 1; - } - - assert(ASTs.size() == 1); - auto& sm = ASTs[0]->getSourceManager(); - const auto& lo = ASTs[0]->getLangOpts(); - - // auto candidates = getAllFunctionDeclarations(ASTs[0]->getASTContext()); - auto candidates = getAllFunctionCallExpressions(ASTs[0]->getASTContext()); - std::shuffle(candidates.begin(), candidates.end(), std::random_device()); - - for (const auto& function : candidates) { - // const auto replacements = flipFunctionParameters(*function, sm, lo); - const auto replacements = flipFunctionCallArguments(*function, ASTs[0]->getASTContext()); - if (!replacements) { - continue; - } - - clang::Rewriter rewriter(sm, lo); - if (!clang::tooling::applyAllReplacements(*replacements, rewriter)) { - std::cerr << "Error: could not apply replacements." << std::endl; - return 1; - } - - rewriter.overwriteChangedFiles(); - - return 0; - } - - std::cout << "Could not find any suitable candidates." << std::endl; - return 1; -}