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 }