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 |