1 /** 2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.mutate.backend.mutation_type.aor; 11 12 import std.algorithm : filter, among; 13 import std.array : array; 14 import std.range : only; 15 import std.typecons : Tuple; 16 17 import dextool.plugin.mutate.backend.type; 18 import dextool.clang_extensions : OpKind; 19 20 import dextool.plugin.mutate.backend.analyze.ast; 21 22 /// Information used to intelligently generate ror mutants; 23 struct AorInfo { 24 Kind operator; 25 Type lhs; 26 Type rhs; 27 } 28 29 auto aorMutations(AorInfo info) @safe { 30 // TODO: for AORs it is probably better to do one op and then lhs+rhs. 31 alias Rval = Tuple!(Mutation.Kind[], "op", Mutation.Kind[], "lhs", Mutation.Kind[], "rhs"); 32 33 Rval rval; 34 switch (info.operator) with (Mutation.Kind) { 35 case Kind.OpAdd: 36 rval = Rval([aorMul, aorDiv, aorRem, aorSub], null, null); 37 break; 38 case Kind.OpDiv: 39 rval = Rval([aorMul, aorRem, aorAdd, aorSub], null, null); 40 break; 41 case Kind.OpMod: 42 rval = Rval([aorMul, aorDiv, aorAdd, aorSub], null, null); 43 break; 44 case Kind.OpMul: 45 rval = Rval([aorDiv, aorRem, aorAdd, aorSub], null, null); 46 break; 47 case Kind.OpSub: 48 rval = Rval([aorMul, aorDiv, aorRem, aorAdd], null, null); 49 break; 50 case Kind.OpAssignAdd: 51 rval = Rval([aorDivAssign, aorRemAssign, 52 aorMulAssign, aorSubAssign], null, null); 53 break; 54 case Kind.OpAssignDiv: 55 rval = Rval([aorAddAssign, aorRemAssign, 56 aorMulAssign, aorSubAssign], null, null); 57 break; 58 case Kind.OpAssignMod: 59 rval = Rval([aorAddAssign, aorDivAssign, 60 aorMulAssign, aorSubAssign], null, null); 61 break; 62 case Kind.OpAssignMul: 63 rval = Rval([aorAddAssign, aorDivAssign, 64 aorRemAssign, aorSubAssign], null, null); 65 break; 66 case Kind.OpAssignSub: 67 rval = Rval([aorAddAssign, aorDivAssign, 68 aorRemAssign, aorMulAssign], null, null); 69 break; 70 default: 71 } 72 73 if (info.lhs is null || info.rhs is null) { 74 // block aor when the type is unknown. It is better to only mutate when 75 // it is certain to be a "good" mutant. 76 rval = typeof(rval).init; 77 } else if (info.lhs.kind.among(TypeKind.unordered, TypeKind.bottom) 78 || info.rhs.kind.among(TypeKind.unordered, TypeKind.bottom)) { 79 // TODO: unfortunately this also blocks operator overloading which is [unordered, unordered] 80 // block aor when the type is a pointer 81 //rval = typeof(rval).init; 82 } else if (info.lhs.kind == TypeKind.continues || info.rhs.kind == TypeKind.continues) { 83 // modulo do not work when either side is a floating point. 84 rval.op = rval.op.filter!(a => !a.among(Mutation.Kind.aorRem, 85 Mutation.Kind.aorRemAssign)).array; 86 } 87 88 return rval; 89 } 90 91 immutable Mutation.Kind[] aorMutationsAll; 92 immutable Mutation.Kind[] aorAssignMutationsAll; 93 94 shared static this() { 95 with (Mutation.Kind) { 96 aorMutationsAll = [ 97 aorMul, aorDiv, aorRem, aorAdd, aorSub, aorLhs, aorRhs 98 ]; 99 aorAssignMutationsAll = [ 100 aorMulAssign, aorDivAssign, aorRemAssign, aorAddAssign, aorSubAssign 101 ]; 102 } 103 }