| 1 | package com.github.valid8j.pcond.core.refl; | |
| 2 | ||
| 3 | import com.github.valid8j.pcond.internals.InternalUtils; | |
| 4 | import com.github.valid8j.pcond.internals.InternalChecks; | |
| 5 | ||
| 6 | import java.lang.reflect.Method; | |
| 7 | import java.util.*; | |
| 8 | import java.util.stream.IntStream; | |
| 9 | ||
| 10 | import static java.lang.String.format; | |
| 11 | import static java.util.Objects.requireNonNull; | |
| 12 | import static java.util.stream.Collectors.toList; | |
| 13 | ||
| 14 | /** | |
| 15 | * //@formater:off | |
| 16 | * An interface representing an object that selects {@link Method}s from given ones. | |
| 17 | * | |
| 18 | * This interface is used to choose methods that are appropriate to invoke with | |
| 19 | * given arguments. | |
| 20 | * //@formater:on | |
| 21 | */ | |
| 22 | public interface MethodSelector extends Formattable { | |
| 23 | /** | |
| 24 | * Selects methods that can be invoked with given {@code args}. | |
| 25 | * | |
| 26 | * @param methods Methods from which returned methods are selected. | |
| 27 | * @param args Arguments to be passed to selected methods. | |
| 28 | * @return Selected methods. | |
| 29 | */ | |
| 30 | List<Method> select(List<Method> methods, Object[] args); | |
| 31 | ||
| 32 | /** | |
| 33 | * Returns a string that describes this object. | |
| 34 | * | |
| 35 | * @return A description of this object | |
| 36 | */ | |
| 37 | String describe(); | |
| 38 | ||
| 39 | /** | |
| 40 | * Returns a composed {@link MethodSelector} that first applies this and | |
| 41 | * then applies {@code another}. | |
| 42 | * | |
| 43 | * @param another The method selector to apply after this. | |
| 44 | * @return The composed method selector | |
| 45 | */ | |
| 46 | default MethodSelector andThen(MethodSelector another) { | |
| 47 |
1
1. andThen : replaced return value with null for com/github/valid8j/pcond/core/refl/MethodSelector::andThen → KILLED |
return new MethodSelector() { |
| 48 | @Override | |
| 49 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 50 |
1
1. select : replaced return value with Collections.emptyList for com/github/valid8j/pcond/core/refl/MethodSelector$1::select → KILLED |
return another.select(MethodSelector.this.select(methods, args), args); |
| 51 | } | |
| 52 | ||
| 53 | @Override | |
| 54 | public String describe() { | |
| 55 |
1
1. describe : replaced return value with "" for com/github/valid8j/pcond/core/refl/MethodSelector$1::describe → KILLED |
return format("%s&&%s", MethodSelector.this.describe(), another.describe()); |
| 56 | } | |
| 57 | }; | |
| 58 | } | |
| 59 | ||
| 60 | /** | |
| 61 | * Formats this object using the {@link MethodSelector#describe()} method. | |
| 62 | */ | |
| 63 | @Override | |
| 64 | default void formatTo(Formatter formatter, int flags, int width, int precision) { | |
| 65 | formatter.format("%s", this.describe()); | |
| 66 | } | |
| 67 | ||
| 68 | class Default implements MethodSelector { | |
| 69 | @Override | |
| 70 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 71 |
1
1. select : replaced return value with Collections.emptyList for com/github/valid8j/pcond/core/refl/MethodSelector$Default::select → KILLED |
return methods |
| 72 | .stream() | |
| 73 |
2
1. lambda$select$0 : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$Default::lambda$select$0 → KILLED 2. lambda$select$0 : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$Default::lambda$select$0 → KILLED |
.filter(m -> areArgsCompatible(m.getParameterTypes(), args)) |
| 74 | .collect(toList()); | |
| 75 | } | |
| 76 | ||
| 77 | @Override | |
| 78 | public String describe() { | |
| 79 |
1
1. describe : replaced return value with "" for com/github/valid8j/pcond/core/refl/MethodSelector$Default::describe → KILLED |
return "default"; |
| 80 | } | |
| 81 | ||
| 82 | private static boolean areArgsCompatible(Class<?>[] formalParameters, Object[] args) { | |
| 83 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (formalParameters.length != args.length) |
| 84 |
1
1. areArgsCompatible : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return false; |
| 85 |
2
1. areArgsCompatible : changed conditional boundary → KILLED 2. areArgsCompatible : negated conditional → KILLED |
for (int i = 0; i < args.length; i++) { |
| 86 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (args[i] == null) |
| 87 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (formalParameters[i].isPrimitive()) |
| 88 |
1
1. areArgsCompatible : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return false; |
| 89 | else | |
| 90 | continue; | |
| 91 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (!Utils.isAssignableWithBoxingFrom(formalParameters[i], Utils.toClass(args[i]))) |
| 92 |
1
1. areArgsCompatible : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return false; |
| 93 | } | |
| 94 |
1
1. areArgsCompatible : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return true; |
| 95 | } | |
| 96 | } | |
| 97 | ||
| 98 | /** | |
| 99 | * A method selector that selects "narrower" methods over "wider" ones. | |
| 100 | */ | |
| 101 | class PreferNarrower implements MethodSelector { | |
| 102 | @Override | |
| 103 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 104 |
2
1. select : changed conditional boundary → KILLED 2. select : negated conditional → KILLED |
if (methods.size() < 2) |
| 105 |
1
1. select : replaced return value with Collections.emptyList for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::select → KILLED |
return methods; |
| 106 | List<Method> ret = new LinkedList<>(); | |
| 107 | for (Method i : methods) { | |
| 108 |
6
1. lambda$select$0 : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::lambda$select$0 → SURVIVED 2. lambda$select$0 : negated conditional → KILLED 3. lambda$select$1 : changed conditional boundary → KILLED 4. lambda$select$1 : negated conditional → KILLED 5. lambda$select$1 : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::lambda$select$1 → KILLED 6. select : negated conditional → KILLED |
if (methods.stream().filter(j -> j != i).noneMatch(j -> compareNarrowness(j, i) > 0)) |
| 109 | ret.add(i); | |
| 110 | } | |
| 111 |
1
1. select : replaced return value with Collections.emptyList for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::select → KILLED |
return ret; |
| 112 | } | |
| 113 | ||
| 114 | @Override | |
| 115 | public String describe() { | |
| 116 |
1
1. describe : replaced return value with "" for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::describe → KILLED |
return "preferNarrower"; |
| 117 | } | |
| 118 | ||
| 119 | /** | |
| 120 | * If {@code a} is 'narrower' than {@code b}, positive integer will be returned. | |
| 121 | * If {@code b} is 'narrower' than {@code a}, negative integer will be returned. | |
| 122 | * Otherwise {@code zero}. | |
| 123 | * | |
| 124 | * 'Narrower' means that every parameter of {@code a} is assignable to corresponding | |
| 125 | * one of {@code b}, but any of {@code b} cannot be assigned to {@code a}'s | |
| 126 | * corresponding parameter. | |
| 127 | * | |
| 128 | * @param a A method. | |
| 129 | * @param b A method to be compared with {@code a}. | |
| 130 | * @return a negative integer, zero, or a positive integer as method {@code a} | |
| 131 | * is less compatible than, as compatible as, or more compatible than | |
| 132 | * the method {@code b} object. | |
| 133 | */ | |
| 134 | private static int compareNarrowness(Method a, Method b) { | |
| 135 |
2
1. compareNarrowness : negated conditional → SURVIVED 2. compareNarrowness : negated conditional → KILLED |
if (isCompatibleWith(a, b) && isCompatibleWith(b, a)) |
| 136 | return 0; | |
| 137 |
2
1. compareNarrowness : negated conditional → KILLED 2. compareNarrowness : negated conditional → KILLED |
if (!isCompatibleWith(a, b) && !isCompatibleWith(b, a)) |
| 138 | return 0; | |
| 139 |
2
1. compareNarrowness : negated conditional → KILLED 2. compareNarrowness : replaced int return with 0 for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::compareNarrowness → KILLED |
return isCompatibleWith(a, b) |
| 140 | ? -1 | |
| 141 | : 1; | |
| 142 | } | |
| 143 | ||
| 144 | private static boolean isCompatibleWith(Method a, Method b) { | |
| 145 |
1
1. isCompatibleWith : removed call to com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::requireSameParameterCounts → KILLED |
requireSameParameterCounts(a, b); |
| 146 |
1
1. isCompatibleWith : negated conditional → KILLED |
if (Objects.equals(a, b)) |
| 147 |
1
1. isCompatibleWith : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::isCompatibleWith → SURVIVED |
return true; |
| 148 |
2
1. isCompatibleWith : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::isCompatibleWith → KILLED 2. isCompatibleWith : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::isCompatibleWith → KILLED |
return IntStream |
| 149 | .range(0, a.getParameterCount()) | |
| 150 |
2
1. lambda$isCompatibleWith$2 : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::lambda$isCompatibleWith$2 → KILLED 2. lambda$isCompatibleWith$2 : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::lambda$isCompatibleWith$2 → KILLED |
.allMatch(i -> Utils.isAssignableWithBoxingFrom(a.getParameterTypes()[i], b.getParameterTypes()[i])); |
| 151 | } | |
| 152 | ||
| 153 | private static void requireSameParameterCounts(Method a, Method b) { | |
| 154 | InternalChecks.requireArgument( | |
| 155 | requireNonNull(a), | |
| 156 |
2
1. lambda$requireSameParameterCounts$3 : negated conditional → KILLED 2. lambda$requireSameParameterCounts$3 : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::lambda$requireSameParameterCounts$3 → KILLED |
(Method v) -> v.getParameterCount() == requireNonNull(b).getParameterCount(), |
| 157 |
1
1. lambda$requireSameParameterCounts$4 : replaced return value with "" for com/github/valid8j/pcond/core/refl/MethodSelector$PreferNarrower::lambda$requireSameParameterCounts$4 → KILLED |
() -> format("Parameter counts are different: a: %s, b: %s", a, b)); |
| 158 | } | |
| 159 | } | |
| 160 | ||
| 161 | class PreferExact implements MethodSelector { | |
| 162 | @Override | |
| 163 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 164 |
2
1. select : changed conditional boundary → SURVIVED 2. select : negated conditional → SURVIVED |
if (methods.size() < 2) |
| 165 |
1
1. select : replaced return value with Collections.emptyList for com/github/valid8j/pcond/core/refl/MethodSelector$PreferExact::select → KILLED |
return methods; |
| 166 | List<Method> work = methods; | |
| 167 | for (Object ignored : args) { | |
| 168 | List<Method> tmp = new ArrayList<>(work); | |
| 169 |
1
1. select : negated conditional → SURVIVED |
if (!tmp.isEmpty()) { |
| 170 | work = tmp; | |
| 171 | break; | |
| 172 | } | |
| 173 | } | |
| 174 |
1
1. select : replaced return value with Collections.emptyList for com/github/valid8j/pcond/core/refl/MethodSelector$PreferExact::select → KILLED |
return work; |
| 175 | } | |
| 176 | ||
| 177 | @Override | |
| 178 | public String describe() { | |
| 179 |
1
1. describe : replaced return value with "" for com/github/valid8j/pcond/core/refl/MethodSelector$PreferExact::describe → KILLED |
return "preferExact"; |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | enum Utils { | |
| 184 | ; | |
| 185 | ||
| 186 | static boolean isAssignableWithBoxingFrom(Class<?> a, Class<?> b) { | |
| 187 |
1
1. isAssignableWithBoxingFrom : negated conditional → KILLED |
if (a.isAssignableFrom(b)) |
| 188 |
1
1. isAssignableWithBoxingFrom : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → KILLED |
return true; |
| 189 |
2
1. isAssignableWithBoxingFrom : negated conditional → KILLED 2. isAssignableWithBoxingFrom : negated conditional → KILLED |
if (InternalChecks.isPrimitiveWrapperClassOrPrimitive(a) && InternalChecks.isPrimitiveWrapperClassOrPrimitive(b)) |
| 190 |
2
1. isAssignableWithBoxingFrom : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → SURVIVED 2. isAssignableWithBoxingFrom : replaced boolean return with false for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → KILLED |
return InternalChecks.isWiderThanOrEqualTo(toWrapperIfPrimitive(a), toWrapperIfPrimitive(b)); |
| 191 |
1
1. isAssignableWithBoxingFrom : replaced boolean return with true for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → KILLED |
return false; |
| 192 | } | |
| 193 | ||
| 194 | private static Class<?> toWrapperIfPrimitive(Class<?> in) { | |
| 195 |
1
1. toWrapperIfPrimitive : negated conditional → KILLED |
if (in.isPrimitive()) |
| 196 |
1
1. toWrapperIfPrimitive : replaced return value with null for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::toWrapperIfPrimitive → KILLED |
return InternalUtils.wrapperClassOf(in); |
| 197 |
1
1. toWrapperIfPrimitive : replaced return value with null for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::toWrapperIfPrimitive → KILLED |
return in; |
| 198 | } | |
| 199 | ||
| 200 | private static Class<?> toClass(Object value) { | |
| 201 |
1
1. toClass : replaced return value with null for com/github/valid8j/pcond/core/refl/MethodSelector$Utils::toClass → KILLED |
return value.getClass(); |
| 202 | } | |
| 203 | } | |
| 204 | } | |
Mutations | ||
| 47 |
1.1 |
|
| 50 |
1.1 |
|
| 55 |
1.1 |
|
| 71 |
1.1 |
|
| 73 |
1.1 2.2 |
|
| 79 |
1.1 |
|
| 83 |
1.1 |
|
| 84 |
1.1 |
|
| 85 |
1.1 2.2 |
|
| 86 |
1.1 |
|
| 87 |
1.1 |
|
| 88 |
1.1 |
|
| 91 |
1.1 |
|
| 92 |
1.1 |
|
| 94 |
1.1 |
|
| 104 |
1.1 2.2 |
|
| 105 |
1.1 |
|
| 108 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
| 111 |
1.1 |
|
| 116 |
1.1 |
|
| 135 |
1.1 2.2 |
|
| 137 |
1.1 2.2 |
|
| 139 |
1.1 2.2 |
|
| 145 |
1.1 |
|
| 146 |
1.1 |
|
| 147 |
1.1 |
|
| 148 |
1.1 2.2 |
|
| 150 |
1.1 2.2 |
|
| 156 |
1.1 2.2 |
|
| 157 |
1.1 |
|
| 164 |
1.1 2.2 |
|
| 165 |
1.1 |
|
| 169 |
1.1 |
|
| 174 |
1.1 |
|
| 179 |
1.1 |
|
| 187 |
1.1 |
|
| 188 |
1.1 |
|
| 189 |
1.1 2.2 |
|
| 190 |
1.1 2.2 |
|
| 191 |
1.1 |
|
| 195 |
1.1 |
|
| 196 |
1.1 |
|
| 197 |
1.1 |
|
| 201 |
1.1 |