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 #SPC-mutation_ror 11 */ 12 module dextool.plugin.mutate.backend.mutation_type.ror; 13 14 import std.array : empty; 15 16 import dextool.plugin.mutate.backend.type; 17 18 import dextool.plugin.mutate.backend.analyze.ast; 19 20 @safe: 21 22 /// Information used to intelligently generate ror mutants; 23 struct RorInfo { 24 Kind operator; 25 Type lhs; 26 Symbol lhsSym; 27 Type rhs; 28 Symbol rhsSym; 29 } 30 31 /** Produce the mutations that can be applied on an operator. 32 * 33 * The resulting schema is intended to be: 34 * normal + pointer - float - enum - bool 35 * 36 * The schema when used is: 37 * ror = normal - float - enum - bool 38 * rorp = pointer - float - enum - bool 39 * 40 * See SPC-mutation_ror for the subsumed table. 41 */ 42 auto rorMutations(RorInfo info) { 43 import std.typecons : Tuple; 44 import std.algorithm : among; 45 46 alias Rval = Tuple!(Mutation.Kind[], "op", Mutation.Kind[], "expr"); 47 Rval rval; 48 49 // initialize rval with the basic ROR schema 50 switch (info.operator) with (Mutation.Kind) { 51 case Kind.OpLess: 52 rval = Rval([rorLE, rorpLE, rorNE, rorpNE], [rorFalse]); 53 break; 54 case Kind.OpGreater: 55 rval = Rval([rorGE, rorpGE, rorNE, rorpNE], [rorFalse]); 56 break; 57 case Kind.OpLessEq: 58 rval = Rval([rorLT, rorpLT, rorEQ, rorpEQ], [rorTrue]); 59 break; 60 case Kind.OpGreaterEq: 61 rval = Rval([rorGT, rorpGT, rorEQ, rorpEQ], [rorTrue]); 62 break; 63 case Kind.OpEqual: 64 rval = Rval([rorLE, rorpLE, rorGE, rorpGE], [rorFalse]); 65 break; 66 case Kind.OpNotEqual: 67 rval = Rval([rorLT, rorpLT, rorGT, rorpGT], [rorTrue]); 68 break; 69 default: 70 } 71 72 // in case the operator isn't a ROR operator. 73 if (rval.op.empty && rval.expr.empty) 74 return rval; 75 76 // #SPC-mutation_ror_enum 77 void discreteSchema() { 78 // information about the type and the concrete value of lhs is available 79 if (info.lhs !is null && info.lhsSym !is null) 80 with (Mutation.Kind) { 81 const c = info.lhs.range.compare(info.lhsSym.value); 82 83 if (c == Range.CompareResult.inside) { 84 // do nothing because lhs is inside thus all ROR mutants are possible 85 } else if (info.operator.among(Kind.OpEqual, Kind.OpNotEqual) 86 && c.among(Range.CompareResult.onLowerBound, 87 Range.CompareResult.onUpperBound)) { 88 rval = Rval(null, [rorTrue, rorFalse]); 89 } 90 } 91 92 if (info.rhs !is null && info.rhsSym !is null) 93 with (Mutation.Kind) { 94 const c = info.rhs.range.compare(info.rhsSym.value); 95 96 if (c == Range.CompareResult.inside) { 97 // do nothing because lhs is inside thus all ROR mutants are possible 98 } else if (info.operator.among(Kind.OpEqual, Kind.OpNotEqual) 99 && c.among(Range.CompareResult.onLowerBound, 100 Range.CompareResult.onUpperBound)) { 101 rval = Rval(null, [rorTrue, rorFalse]); 102 } 103 } 104 } 105 106 // #SPC-mutation_ror_float 107 void continuesSchema() { 108 switch (info.operator) with (Mutation.Kind) { 109 case Kind.OpLess: 110 rval.op = [rorGT, rorpGT]; 111 break; 112 case Kind.OpGreater: 113 rval.op = [rorLT, rorpLT]; 114 break; 115 case Kind.OpLessEq: 116 rval.op = [rorGT, rorpGT]; 117 break; 118 case Kind.OpGreaterEq: 119 rval.op = [rorLT, rorpLT]; 120 break; 121 default: 122 } 123 } 124 125 // #SPC-mutation_ror_bool 126 void boolSchema() { 127 switch (info.operator) with (Mutation.Kind) { 128 case Kind.OpEqual: 129 rval.op = [rorNE, rorpNE]; 130 break; 131 case Kind.OpNotEqual: 132 rval.op = [rorEQ, rorpEQ]; 133 break; 134 default: 135 } 136 } 137 138 // #SPC-mutation_ror_ptr 139 void unorderedSchema() { 140 switch (info.operator) with (Mutation.Kind) { 141 case Kind.OpEqual: 142 rval.op = [rorLE, rorGE, rorpNE]; 143 break; 144 case Kind.OpNotEqual: 145 rval.op = [rorLT, rorGT, rorpEQ]; 146 break; 147 default: 148 } 149 } 150 151 // Returns: true if either the type for lhs or rhs match `k`. 152 bool isAny(TypeKind k) { 153 if (info.lhs !is null && info.lhs.kind == k) 154 return true; 155 if (info.rhs !is null && info.rhs.kind == k) 156 return true; 157 return false; 158 } 159 160 if (isAny(TypeKind.unordered)) 161 unorderedSchema; 162 else if (isAny(TypeKind.boolean)) 163 boolSchema; 164 else if (isAny(TypeKind.continues)) 165 continuesSchema; 166 else if (isAny(TypeKind.discrete)) 167 discreteSchema; 168 169 return rval; 170 } 171 172 immutable Mutation.Kind[] rorMutationsAll; 173 immutable Mutation.Kind[] rorpMutationsAll; 174 175 shared static this() { 176 with (Mutation.Kind) { 177 rorMutationsAll = [ 178 rorLT, rorLE, rorGT, rorGE, rorEQ, rorNE, rorTrue, rorFalse 179 ]; 180 rorpMutationsAll = [ 181 rorpLT, rorpLE, rorpGT, rorpGE, rorpEQ, rorpNE, rorTrue, rorFalse 182 ]; 183 } 184 }