Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make --mutation-info-file optional #195

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
JamesLee-Jones marked this conversation as resolved.
Show resolved Hide resolved
# Now compile the mutated version of the example
${DREDD_CLANG_BIN_DIR}/clang++ examples/simple/pi.cc -o examples/simple/pi
```
Expand All @@ -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
```

Expand Down Expand Up @@ -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.
Expand Down
15 changes: 11 additions & 4 deletions src/dredd/src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <fstream>
#include <memory>
#include <optional>
#include <string>

#include "clang/Tooling/CommonOptionsParser.h"
Expand Down Expand Up @@ -61,7 +62,7 @@ static llvm::cl::opt<bool> dump_asts(
llvm::cl::cat(mutate_category));
// NOLINTNEXTLINE
static llvm::cl::opt<std::string> 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));
Expand Down Expand Up @@ -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<dredd::protobufs::MutationInfo> mutation_info;

if (mutation_info_file.empty()) {
mutation_info = std::nullopt;
} else {
mutation_info = dredd::protobufs::MutationInfo();
}

const std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
dredd::NewMutateFrontendActionFactory(!no_mutation_opts, dump_asts,
Expand All @@ -103,15 +110,15 @@ 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;
auto json_options = google::protobuf::util::JsonOptions();
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
#define LIBDREDD_NEW_MUTATE_FRONTEND_ACTION_FACTORY_H

#include <memory>
#include <optional>

#include "clang/Tooling/Tooling.h"
#include "libdredd/protobufs/dredd_protobufs.h"

namespace dredd {

std::unique_ptr<clang::tooling::FrontendActionFactory>
NewMutateFrontendActionFactory(bool optimise_mutations, bool dump_asts,
bool only_track_mutant_coverage,
int& mutation_id,
protobufs::MutationInfo& mutation_info);
NewMutateFrontendActionFactory(
bool optimise_mutations, bool dump_asts, bool only_track_mutant_coverage,
int& mutation_id, std::optional<protobufs::MutationInfo>& mutation_info);

} // namespace dredd

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define LIBDREDD_MUTATE_AST_CONSUMER_H

#include <memory>
#include <optional>
#include <string>
#include <unordered_set>

Expand All @@ -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<protobufs::MutationInfo>& mutation_info)
: compiler_instance_(&compiler_instance),
optimise_mutations_(optimise_mutations),
dump_ast_(dump_ast),
Expand Down Expand Up @@ -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<std::string>& dredd_declarations);
std::unordered_set<std::string>& dredd_declarations, bool build_tree);

const clang::CompilerInstance* compiler_instance_;

Expand All @@ -89,7 +90,7 @@ class MutateAstConsumer : public clang::ASTConsumer {
// for different translation units.
int* mutation_id_;

protobufs::MutationInfo* mutation_info_;
std::optional<protobufs::MutationInfo>* mutation_info_;
};

} // namespace dredd
Expand Down
28 changes: 16 additions & 12 deletions src/libdredd/src/mutate_ast_consumer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,12 @@ void MutateAstConsumer::HandleTranslationUnit(clang::ASTContext& ast_context) {
std::unordered_set<std::string> dredd_declarations;

protobufs::MutationInfoForFile mutation_info_for_file;
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.
Expand Down Expand Up @@ -135,7 +131,14 @@ void MutateAstConsumer::HandleTranslationUnit(clang::ASTContext& ast_context) {
}
}

*mutation_info_->add_info_for_files() = mutation_info_for_file;
if (mutation_info_->has_value()) {
mutation_info_for_file.set_filename(
ast_context.getSourceManager()
.getFileEntryForID(ast_context.getSourceManager().getMainFileID())
->getName()
.str());
*mutation_info_->value().add_info_for_files() = mutation_info_for_file;
}

auto& source_manager = ast_context.getSourceManager();
const clang::SourceLocation start_of_source_file =
Expand Down Expand Up @@ -411,7 +414,7 @@ void MutateAstConsumer::ApplyMutations(
clang::ASTContext& context,
protobufs::MutationInfoForFile& protobufs_mutation_info_for_file,
protobufs::MutationTreeNode& protobufs_mutation_tree_node,
std::unordered_set<std::string>& dredd_declarations) {
std::unordered_set<std::string>& 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.");
Expand All @@ -422,17 +425,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;
}
Expand Down
21 changes: 10 additions & 11 deletions src/libdredd/src/new_mutate_frontend_action_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<protobufs::MutationInfo>& mutation_info,
std::set<std::string>& processed_files)
: optimise_mutations_(optimise_mutations),
dump_asts_(dump_asts),
Expand Down Expand Up @@ -65,22 +65,21 @@ class MutateFrontendAction : public clang::ASTFrontendAction {
bool dump_asts_;
bool only_track_mutant_coverage_;
int* mutation_id_;
protobufs::MutationInfo* mutation_info_;
std::optional<protobufs::MutationInfo>* mutation_info_;
std::set<std::string>* processed_files_;
};

std::unique_ptr<clang::tooling::FrontendActionFactory>
NewMutateFrontendActionFactory(bool optimise_mutations, bool dump_asts,
bool only_track_mutant_coverage,
int& mutation_id,
protobufs::MutationInfo& mutation_info) {
NewMutateFrontendActionFactory(
bool optimise_mutations, bool dump_asts, bool only_track_mutant_coverage,
int& mutation_id, std::optional<protobufs::MutationInfo>& 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)
MutateFrontendActionFactory(
bool optimise_mutations, bool dump_asts,
bool only_track_mutant_coverage, int& mutation_id,
std::optional<protobufs::MutationInfo>& mutation_info)
: optimise_mutations_(optimise_mutations),
dump_asts_(dump_asts),
only_track_mutant_coverage_(only_track_mutant_coverage),
Expand All @@ -98,7 +97,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<protobufs::MutationInfo>* mutation_info_;

// Stores the ids of the files that have been processed so far, to avoid
// processing a file multiple times.
Expand Down
Loading