Skip to content

Commit

Permalink
Add a way to ignore mutators
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexDenisov authored and AlexDenisov committed Feb 18, 2022
1 parent 0c39cf9 commit 01d359b
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 22 deletions.
1 change: 1 addition & 0 deletions include/mull/Config/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct Configuration {

std::vector<std::string> bitcodePaths; // TODO: Drop this one
std::vector<std::string> mutators;
std::vector<std::string> ignoreMutators;

std::string executable;
std::string outputFile;
Expand Down
3 changes: 2 additions & 1 deletion include/mull/Mutators/MutatorsFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class Diagnostics;
class MutatorsFactory {
public:
explicit MutatorsFactory(Diagnostics &diagnostics);
std::vector<std::unique_ptr<Mutator>> mutators(const std::vector<std::string> &groups);
std::vector<std::unique_ptr<Mutator>> mutators(const std::vector<std::string> &groups,
const std::vector<std::string> &ignoreGroups);
void init();
static std::string descriptionForGroup(const std::vector<std::string> &groupMembers);
std::vector<std::pair<std::string, std::string>> commandLineOptions();
Expand Down
1 change: 1 addition & 0 deletions lib/Config/ConfigurationParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ template <> struct llvm::yaml::MappingTraits<Configuration> {
io.mapOptional("includeNotCovered", config.includeNotCovered);
io.mapOptional("timeout", config.timeout);
io.mapOptional("mutators", config.mutators);
io.mapOptional("ignoreMutators", config.ignoreMutators);
io.mapOptional("parallelization", config.parallelization);
io.mapOptional("compilationDatabasePath", config.compilationDatabasePath);
io.mapOptional("compilerFlags", config.compilerFlags);
Expand Down
4 changes: 3 additions & 1 deletion lib/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,9 @@ void mull::mutateBitcode(llvm::Module &module) {
}

MutatorsFactory mutatorsFactory(diagnostics);
MutationsFinder mutationsFinder(mutatorsFactory.mutators(configuration.mutators), configuration);
MutationsFinder mutationsFinder(
mutatorsFactory.mutators(configuration.mutators, configuration.ignoreMutators),
configuration);

std::vector<InstructionSelectionTask> instructionSelectionTasks;
instructionSelectionTasks.reserve(configuration.parallelization.workers);
Expand Down
31 changes: 22 additions & 9 deletions lib/Mutators/MutatorsFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
#include "mull/Mutators/NegateConditionMutator.h"
#include "mull/Mutators/ScalarValueMutator.h"
#include <llvm/ADT/STLExtras.h>
#include <set>
#include <sstream>
#include <unordered_set>

using namespace mull;
using namespace std;
Expand Down Expand Up @@ -70,7 +70,7 @@ static string CXX_Default() {
}

static void expandGroups(const vector<string> &groups, const map<string, vector<string>> &mapping,
set<string> &expandedGroups) {
unordered_set<string> &expandedGroups) {
for (const string &group : groups) {
if (mapping.count(group) == 0) {
expandedGroups.insert(group);
Expand Down Expand Up @@ -241,23 +241,36 @@ Mutator *MutatorsFactory::getMutator(const string &mutatorId) {
return mutatorsMapping[mutatorId].get();
}

vector<unique_ptr<Mutator>> MutatorsFactory::mutators(const vector<string> &groups) {
vector<unique_ptr<Mutator>>
MutatorsFactory::mutators(const vector<string> &groups,
const std::vector<std::string> &ignoreGroups) {
/// We need to recreate all mutators in case this method called
/// more than once. It does not happen during normal program execution,
/// but happens a lot during testing
init();

set<string> expandedGroups;
std::unordered_set<std::string> expandedGroups;
std::unordered_set<std::string> expandedIgnoreGroups;
if (!ignoreGroups.empty()) {
expandGroups(ignoreGroups, groupsMapping, expandedIgnoreGroups);
}

if (groups.empty()) {
expandGroups({ CXX_Default() }, groupsMapping, expandedGroups);
} else {
expandGroups(groups, groupsMapping, expandedGroups);
}

vector<unique_ptr<Mutator>> mutators;
for (auto &ignoreGroup : expandedIgnoreGroups) {
expandedGroups.erase(ignoreGroup);
}

std::vector<std::unique_ptr<Mutator>> mutators;
std::vector<std::string> sortedGroups;
std::copy(expandedGroups.begin(), expandedGroups.end(), std::back_inserter(sortedGroups));
std::sort(sortedGroups.begin(), sortedGroups.end());

for (const string &group : expandedGroups) {
for (const std::string &group : sortedGroups) {
if (mutatorsMapping.count(group) == 0) {
diagnostics.warning(std::string("Unknown mutator: ") + group);
continue;
Expand All @@ -277,7 +290,7 @@ vector<unique_ptr<Mutator>> MutatorsFactory::mutators(const vector<string> &grou

std::string MutatorsFactory::descriptionForGroup(const std::vector<std::string> &groupMembers) {
if (groupMembers.empty()) {
return std::string("empty group?");
return "empty group?";
}

std::stringstream members;
Expand All @@ -295,11 +308,11 @@ std::vector<std::pair<std::string, std::string>> MutatorsFactory::commandLineOpt
options.emplace_back(group.first, descriptionForGroup(group.second));
}

std::set<std::string> mutatorsSet;
std::unordered_set<std::string> mutatorsSet;
std::vector<std::string> groups({ AllMutatorsGroup() });
expandGroups({ AllMutatorsGroup() }, groupsMapping, mutatorsSet);

auto allMutators = mutators({ AllMutatorsGroup() });
auto allMutators = mutators({ AllMutatorsGroup() }, {});

for (auto &mutator : allMutators) {
options.emplace_back(mutator->getUniqueIdentifier(), mutator->getDescription());
Expand Down
5 changes: 5 additions & 0 deletions tests-lit/tests/mutations/ignore-mutators/mull-group.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutators:
- cxx_arithmetic
- cxx_logical
ignoreMutators:
- cxx_arithmetic
4 changes: 4 additions & 0 deletions tests-lit/tests/mutations/ignore-mutators/mull.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mutators:
- cxx_arithmetic
ignoreMutators:
- cxx_add_to_sub
17 changes: 17 additions & 0 deletions tests-lit/tests/mutations/ignore-mutators/sample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// clang-format off

int sum(int a, int b) {
return a + b;
}

int main() {
return sum(-2, 2);
}

/**
RUN: %clang_cxx %sysroot %pass_mull_ir_frontend -g %s -o %s.exe
RUN: MULL_CONFIG=%S/mull-group.yml %clang_cxx %sysroot %pass_mull_ir_frontend -g %s -o %s-group.exe
RUN: unset TERM; %mull_runner -reporters=IDE %s.exe | %filecheck %s --dump-input=fail
RUN: unset TERM; %mull_runner -reporters=IDE %s-group.exe | %filecheck %s --dump-input=fail
CHECK:[info] No mutants found. Mutation score: infinitely high
**/
20 changes: 10 additions & 10 deletions tests/MutatorsFactoryTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ TEST(MutatorsFactory, SingleMutators) {
Mutator *mutator = nullptr;

{
mutators = factory.mutators({ "negate_mutator" });
mutators = factory.mutators({ "negate_mutator" }, {});
ASSERT_EQ(mutators.size(), 1UL);
mutator = mutators[0].get();
ASSERT_EQ(mutator->getUniqueIdentifier(), "negate_mutator");
}

{
mutators = factory.mutators({ "cxx_remove_void_call" });
mutators = factory.mutators({ "cxx_remove_void_call" }, {});
ASSERT_EQ(mutators.size(), 1UL);
mutator = mutators[0].get();
ASSERT_EQ(mutator->getUniqueIdentifier(), "cxx_remove_void_call");
}

{
mutators = factory.mutators({ "cxx_replace_scalar_call" });
mutators = factory.mutators({ "cxx_replace_scalar_call" }, {});
ASSERT_EQ(mutators.size(), 1UL);
mutator = mutators[0].get();
ASSERT_EQ(mutator->getUniqueIdentifier(), "cxx_replace_scalar_call");
}

{
mutators = factory.mutators({ "scalar_value_mutator" });
mutators = factory.mutators({ "scalar_value_mutator" }, {});
ASSERT_EQ(mutators.size(), 1UL);
mutator = mutators[0].get();
ASSERT_EQ(mutator->getUniqueIdentifier(), "scalar_value_mutator");
Expand All @@ -55,7 +55,7 @@ TEST(MutatorsFactory, CompositeMutators) {
vector<unique_ptr<Mutator>>::iterator searchResult;

{
mutators = factory.mutators({ "cxx_arithmetic" });
mutators = factory.mutators({ "cxx_arithmetic" }, {});
ASSERT_EQ(mutators.size(), 6UL);

searchResult = find_if(mutators.begin(), mutators.end(), predicate("cxx_div_to_mul"));
Expand All @@ -67,7 +67,7 @@ TEST(MutatorsFactory, CompositeMutators) {
}

{
mutators = factory.mutators({ "cxx_logical" });
mutators = factory.mutators({ "cxx_logical" }, {});
ASSERT_EQ(mutators.size(), 3UL);

searchResult = find_if(mutators.begin(), mutators.end(), predicate("cxx_logical_or_to_and"));
Expand All @@ -79,15 +79,15 @@ TEST(MutatorsFactory, CompositeMutators) {
}

{
mutators = factory.mutators({ "experimental" });
mutators = factory.mutators({ "experimental" }, {});
ASSERT_EQ(mutators.size(), 5UL);

searchResult = find_if(mutators.begin(), mutators.end(), predicate("scalar_value_mutator"));
ASSERT_NE(searchResult, mutators.end());
}

{
mutators = factory.mutators({ "all" });
mutators = factory.mutators({ "all" }, {});
ASSERT_EQ(mutators.size(), 45UL);
}
}
Expand All @@ -100,14 +100,14 @@ TEST(MutatorsFactory, UniqueMutators) {
Mutator *mutator = nullptr;

{
mutators = factory.mutators({ "cxx_add_to_sub", "cxx_add_to_sub" });
mutators = factory.mutators({ "cxx_add_to_sub", "cxx_add_to_sub" }, {});
ASSERT_EQ(mutators.size(), 1UL);
mutator = mutators[0].get();
ASSERT_EQ(mutator->getUniqueIdentifier(), "cxx_add_to_sub");
}

{
mutators = factory.mutators({ "cxx_arithmetic", "cxx_add_to_sub" });
mutators = factory.mutators({ "cxx_arithmetic", "cxx_add_to_sub" }, {});
ASSERT_EQ(mutators.size(), 6UL);

searchResult = find_if(mutators.begin(), mutators.end(), predicate("cxx_add_to_sub"));
Expand Down
2 changes: 1 addition & 1 deletion tools/CLIOptions/CLIOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ std::vector<std::unique_ptr<Mutator>> MutatorsCLIOptions::mutators() {
selectedGroups.push_back(options[name].first);
}

return factory.mutators(selectedGroups);
return factory.mutators(selectedGroups, {});
}

std::vector<std::pair<std::string, std::string>> &MutatorsCLIOptions::getOptions() {
Expand Down

0 comments on commit 01d359b

Please sign in to comment.