From 854321cf62cd27d97dcf9006521df5596ec033d4 Mon Sep 17 00:00:00 2001 From: James Lee-Jones Date: Tue, 21 Nov 2023 12:05:08 +0000 Subject: [PATCH] Make --mutation-info-file optional Make `--mutation-info-file` parameter optional as writing this file can cause issues if the mutation tree is too deep. --- README.md | 11 +++---- src/dredd/src/main.cc | 15 ++++++--- .../new_mutate_frontend_action_factory.h | 3 +- .../include/libdredd/protobufs/dredd.proto | 5 ++- .../include/libdredd/mutate_ast_consumer.h | 7 +++-- src/libdredd/src/mutate_ast_consumer.cc | 31 ++++++++++++------- .../src/new_mutate_frontend_action_factory.cc | 10 +++--- 7 files changed, 50 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 41ef7fb5..09d92dad 100644 --- a/README.md +++ b/README.md @@ -72,11 +72,7 @@ We first show how to apply Dredd to a simple stand-alone program. We will then s ``` # This will modify pi.cc in-place. -# The --mutation-info-file argument is used to specify a JSON file to -# which Dredd will output machine-readable information about the -# mutations it applied. For the purposes of this example, this file -# can be ignored. -${DREDD_EXECUTABLE} examples/simple/pi.cc --mutation-info-file temp.json +${DREDD_EXECUTABLE} examples/simple/pi.cc # Now compile the mutated version of the example ${DREDD_CLANG_BIN_DIR}/clang++ examples/simple/pi.cc -o examples/simple/pi ``` @@ -98,7 +94,6 @@ You can also enable multiple mutants by setting the environment variable to a co To clean up and restore the file `pi.cc` to it's initial state, run ``` rm examples/simple/pi -rm temp.json git checkout HEAD examples/simple/pi.cc ``` @@ -141,6 +136,10 @@ ${DREDD_EXECUTABLE} -p build math/src/*.cc --mutation-info-file mutant-info.json The `-p` option allows the compilation database generated by CMake above to be passed to Dredd: the `compile_commands.json` file in `build` will be used as a compilation database. This is so that Dredd knows the correct compiler options to use when processing each source file. +The optional `--mutation-info-file` argument is used to specify a JSON file to which Dredd will output +machine-readable information about the mutations it applied. We explain how the `mutant-info.json` file created +via the `--mutation-info-file` argument can be used to query the mutants that Dredd has introduced. + You can run `git status` to see which files have changed, and `git diff` to see the effect that Dredd has had on these files. These changes will be hard to understand as they are not intended to be readable by humans. diff --git a/src/dredd/src/main.cc b/src/dredd/src/main.cc index 4e20ba48..99bb4d8c 100644 --- a/src/dredd/src/main.cc +++ b/src/dredd/src/main.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include "clang/Tooling/CommonOptionsParser.h" @@ -61,7 +62,7 @@ static llvm::cl::opt dump_asts( llvm::cl::cat(mutate_category)); // NOLINTNEXTLINE static llvm::cl::opt mutation_info_file( - "mutation-info-file", llvm::cl::Required, + "mutation-info-file", llvm::cl::desc( ".json file into which mutation information should be written"), llvm::cl::cat(mutate_category)); @@ -94,7 +95,13 @@ int main(int argc, const char** argv) { // Keeps track of the mutations that are applied to each source file, // including their hierarchical structure. - dredd::protobufs::MutationInfo mutation_info; + std::optional mutation_info; + + if (mutation_info_file.empty()) { + mutation_info = std::nullopt; + } else { + mutation_info = dredd::protobufs::MutationInfo(); + } const std::unique_ptr factory = dredd::NewMutateFrontendActionFactory(!no_mutation_opts, dump_asts, @@ -103,7 +110,7 @@ int main(int argc, const char** argv) { const int return_code = Tool.run(factory.get()); - if (return_code == 0) { + if (mutation_info.has_value() && return_code == 0) { // Application of mutations was successful, so write out the mutation info // in JSON format. std::string json_string; @@ -111,7 +118,7 @@ int main(int argc, const char** argv) { json_options.add_whitespace = true; json_options.always_print_primitive_fields = true; auto json_generation_status = google::protobuf::util::MessageToJsonString( - mutation_info, &json_string, json_options); + mutation_info.value(), &json_string, json_options); if (json_generation_status.ok()) { std::ofstream transformations_json_file(mutation_info_file); transformations_json_file << json_string; diff --git a/src/libdredd/include/libdredd/new_mutate_frontend_action_factory.h b/src/libdredd/include/libdredd/new_mutate_frontend_action_factory.h index b8b6f282..e41650b8 100644 --- a/src/libdredd/include/libdredd/new_mutate_frontend_action_factory.h +++ b/src/libdredd/include/libdredd/new_mutate_frontend_action_factory.h @@ -16,6 +16,7 @@ #define LIBDREDD_NEW_MUTATE_FRONTEND_ACTION_FACTORY_H #include +#include #include "clang/Tooling/Tooling.h" #include "libdredd/protobufs/dredd_protobufs.h" @@ -26,7 +27,7 @@ std::unique_ptr NewMutateFrontendActionFactory(bool optimise_mutations, bool dump_asts, bool only_track_mutant_coverage, int& mutation_id, - protobufs::MutationInfo& mutation_info); + std::optional &mutation_info); } // namespace dredd diff --git a/src/libdredd/include/libdredd/protobufs/dredd.proto b/src/libdredd/include/libdredd/protobufs/dredd.proto index ee26e030..e7b7661a 100644 --- a/src/libdredd/include/libdredd/protobufs/dredd.proto +++ b/src/libdredd/include/libdredd/protobufs/dredd.proto @@ -15,7 +15,10 @@ syntax = "proto3"; package dredd.protobufs; -message MutationInfo { repeated MutationInfoForFile info_for_files = 1; } +message MutationInfo { + repeated MutationInfoForFile info_for_files = 1; + bool use = 2; +} message MutationInfoForFile { string filename = 1; diff --git a/src/libdredd/include_private/include/libdredd/mutate_ast_consumer.h b/src/libdredd/include_private/include/libdredd/mutate_ast_consumer.h index 29e23a53..f13f6967 100644 --- a/src/libdredd/include_private/include/libdredd/mutate_ast_consumer.h +++ b/src/libdredd/include_private/include/libdredd/mutate_ast_consumer.h @@ -16,6 +16,7 @@ #define LIBDREDD_MUTATE_AST_CONSUMER_H #include +#include #include #include @@ -34,7 +35,7 @@ class MutateAstConsumer : public clang::ASTConsumer { MutateAstConsumer(const clang::CompilerInstance& compiler_instance, bool optimise_mutations, bool dump_ast, bool only_track_mutant_coverage, int& mutation_id, - protobufs::MutationInfo& mutation_info) + std::optional &mutation_info) : compiler_instance_(&compiler_instance), optimise_mutations_(optimise_mutations), dump_ast_(dump_ast), @@ -68,7 +69,7 @@ class MutateAstConsumer : public clang::ASTConsumer { clang::ASTContext& context, protobufs::MutationInfoForFile& protobufs_mutation_info_for_file, protobufs::MutationTreeNode& protobufs_mutation_tree_node, - std::unordered_set& dredd_declarations); + std::unordered_set& dredd_declarations, bool build_tree); const clang::CompilerInstance* compiler_instance_; @@ -89,7 +90,7 @@ class MutateAstConsumer : public clang::ASTConsumer { // for different translation units. int* mutation_id_; - protobufs::MutationInfo* mutation_info_; + std::optional* mutation_info_; }; } // namespace dredd diff --git a/src/libdredd/src/mutate_ast_consumer.cc b/src/libdredd/src/mutate_ast_consumer.cc index 4d237e50..d642b651 100644 --- a/src/libdredd/src/mutate_ast_consumer.cc +++ b/src/libdredd/src/mutate_ast_consumer.cc @@ -83,16 +83,20 @@ void MutateAstConsumer::HandleTranslationUnit(clang::ASTContext& ast_context) { std::unordered_set dredd_declarations; protobufs::MutationInfoForFile mutation_info_for_file; - mutation_info_for_file.set_filename( - ast_context.getSourceManager() - .getFileEntryForID(ast_context.getSourceManager().getMainFileID()) - ->getName() - .str()); + + if (mutation_info_->has_value()) { + mutation_info_for_file.set_filename( + ast_context.getSourceManager() + .getFileEntryForID(ast_context.getSourceManager().getMainFileID()) + ->getName() + .str()); + } + protobufs::MutationTreeNode* root_protobuf_mutation_tree_node = mutation_info_for_file.add_mutation_tree(); ApplyMutations(visitor_->GetMutations(), initial_mutation_id, ast_context, mutation_info_for_file, *root_protobuf_mutation_tree_node, - dredd_declarations); + dredd_declarations, mutation_info_->has_value()); if (initial_mutation_id == *mutation_id_) { // No possibilities for mutation were found; nothing else to do. @@ -135,7 +139,9 @@ void MutateAstConsumer::HandleTranslationUnit(clang::ASTContext& ast_context) { } } - *mutation_info_->add_info_for_files() = mutation_info_for_file; + if (mutation_info_->has_value()) { + *mutation_info_->value().add_info_for_files() = mutation_info_for_file; + } auto& source_manager = ast_context.getSourceManager(); const clang::SourceLocation start_of_source_file = @@ -411,7 +417,7 @@ void MutateAstConsumer::ApplyMutations( clang::ASTContext& context, protobufs::MutationInfoForFile& protobufs_mutation_info_for_file, protobufs::MutationTreeNode& protobufs_mutation_tree_node, - std::unordered_set& dredd_declarations) { + std::unordered_set& dredd_declarations, bool build_tree) { assert(!(dredd_mutation_tree_node.IsEmpty() && dredd_mutation_tree_node.GetChildren().size() == 1) && "The mutation tree should already be compressed."); @@ -422,17 +428,18 @@ void MutateAstConsumer::ApplyMutations( protobufs_mutation_info_for_file.mutation_tree_size())); protobufs::MutationTreeNode* new_protobufs_mutation_tree_node = protobufs_mutation_info_for_file.add_mutation_tree(); - ApplyMutations(*child, initial_mutation_id, context, - protobufs_mutation_info_for_file, - *new_protobufs_mutation_tree_node, dredd_declarations); + ApplyMutations( + *child, initial_mutation_id, context, protobufs_mutation_info_for_file, + *new_protobufs_mutation_tree_node, dredd_declarations, build_tree); } + for (const auto& mutation : dredd_mutation_tree_node.GetMutations()) { const int mutation_id_old = *mutation_id_; const auto mutation_group = mutation->Apply( context, compiler_instance_->getPreprocessor(), optimise_mutations_, only_track_mutant_coverage_, initial_mutation_id, *mutation_id_, rewriter_, dredd_declarations); - if (*mutation_id_ > mutation_id_old) { + if (build_tree && *mutation_id_ > mutation_id_old) { // Only add the result of applying the mutation if it had an effect. *protobufs_mutation_tree_node.add_mutation_groups() = mutation_group; } diff --git a/src/libdredd/src/new_mutate_frontend_action_factory.cc b/src/libdredd/src/new_mutate_frontend_action_factory.cc index ac3b4a0e..d06348b0 100644 --- a/src/libdredd/src/new_mutate_frontend_action_factory.cc +++ b/src/libdredd/src/new_mutate_frontend_action_factory.cc @@ -33,7 +33,7 @@ class MutateFrontendAction : public clang::ASTFrontendAction { public: MutateFrontendAction(bool optimise_mutations, bool dump_asts, bool only_track_mutant_coverage, int& mutation_id, - protobufs::MutationInfo& mutation_info, + std::optional &mutation_info, std::set& processed_files) : optimise_mutations_(optimise_mutations), dump_asts_(dump_asts), @@ -65,7 +65,7 @@ class MutateFrontendAction : public clang::ASTFrontendAction { bool dump_asts_; bool only_track_mutant_coverage_; int* mutation_id_; - protobufs::MutationInfo* mutation_info_; + std::optional* mutation_info_; std::set* processed_files_; }; @@ -73,14 +73,14 @@ std::unique_ptr NewMutateFrontendActionFactory(bool optimise_mutations, bool dump_asts, bool only_track_mutant_coverage, int& mutation_id, - protobufs::MutationInfo& mutation_info) { + std::optional &mutation_info) { class MutateFrontendActionFactory : public clang::tooling::FrontendActionFactory { public: MutateFrontendActionFactory(bool optimise_mutations, bool dump_asts, bool only_track_mutant_coverage, int& mutation_id, - protobufs::MutationInfo& mutation_info) + std::optional &mutation_info) : optimise_mutations_(optimise_mutations), dump_asts_(dump_asts), only_track_mutant_coverage_(only_track_mutant_coverage), @@ -98,7 +98,7 @@ NewMutateFrontendActionFactory(bool optimise_mutations, bool dump_asts, bool dump_asts_; bool only_track_mutant_coverage_; int* mutation_id_; - protobufs::MutationInfo* mutation_info_; + std::optional* mutation_info_; // Stores the ids of the files that have been processed so far, to avoid // processing a file multiple times.