Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework NFA matching and try with resources filtering #1020

Merged
merged 10 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.objectweb.asm.Opcodes.ICONST_M1;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.ISTORE;
import static org.pitest.sequence.Result.result;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
Expand Down Expand Up @@ -41,27 +42,37 @@ public static Match<AbstractInsnNode> notAnInstruction() {
}

public static Match<AbstractInsnNode> opCode(final int opcode) {
return (c, a) -> a.getOpcode() == opcode;
return (c, a) -> result(a.getOpcode() == opcode, c);
}

public static <T extends AbstractInsnNode> Match<AbstractInsnNode> isA(
final Class<T> cls) {
return (c, a) -> a.getClass().isAssignableFrom(cls);
return (c, a) -> result(a.getClass().isAssignableFrom(cls), c);
}

public static Match<AbstractInsnNode> incrementsVariable(final SlotRead<Integer> counterVariable) {
return (context, a) -> (a instanceof IincInsnNode)
&& context.retrieve(counterVariable).filter(isEqual(((IincInsnNode)a).var)).isPresent();
return (context, a) -> result((a instanceof IincInsnNode)
&& context.retrieve(counterVariable).filter(isEqual(((IincInsnNode)a).var)).isPresent(), context);
}

public static Match<AbstractInsnNode> anIStore(
final SlotWrite<Integer> counterVariable) {
return opCode(Opcodes.ISTORE).and(aVariableAccess(counterVariable));
}

public static Match<AbstractInsnNode> anILoad(
final SlotWrite<Integer> counterVariable) {
return opCode(Opcodes.ILOAD).and(aVariableAccess(counterVariable));
}

public static Match<AbstractInsnNode> aVariableAccess(
final SlotWrite<Integer> counterVariable) {
return (c, t) -> (t instanceof VarInsnNode) && c.store(counterVariable, ((VarInsnNode) t).var);
return (c, t) -> {
if (t instanceof VarInsnNode) {
return result(true, c.store(counterVariable, ((VarInsnNode) t).var));
}
return result(false, c);
};
}

public static Match<AbstractInsnNode> anIStoreTo(
Expand All @@ -76,8 +87,8 @@ public static Match<AbstractInsnNode> anILoadOf(

public static Match<AbstractInsnNode> variableMatches(
final SlotRead<Integer> counterVariable) {
return (c, t) -> (t instanceof VarInsnNode)
&& c.retrieve(counterVariable).filter(isEqual(((VarInsnNode) t).var)).isPresent();
return (c, t) -> result((t instanceof VarInsnNode)
&& c.retrieve(counterVariable).filter(isEqual(((VarInsnNode) t).var)).isPresent(), c);
}


Expand All @@ -100,9 +111,9 @@ public static Match<AbstractInsnNode> aJump() {
}

public static Match<AbstractInsnNode> aConditionalJump() {
return (c, t) -> (t instanceof JumpInsnNode)
return (c, t) -> result((t instanceof JumpInsnNode)
&& (t.getOpcode() != Opcodes.GOTO)
&& (t.getOpcode() != Opcodes.JSR);
&& (t.getOpcode() != Opcodes.JSR), c);
}

public static Match<AbstractInsnNode> aConditionalJumpTo(Slot<LabelNode> label) {
Expand All @@ -113,19 +124,18 @@ public static Match<AbstractInsnNode> aConditionalJumpTo(Slot<LabelNode> label)
public static <T extends AbstractInsnNode> Match<AbstractInsnNode> writeNodeToSlot(final SlotWrite<T> slot, final Class<T> clazz) {
return (c, t) -> {
if (clazz.isAssignableFrom(t.getClass()) ) {
c.store(slot, clazz.cast(t));
return true;
return result(true, c.store(slot, clazz.cast(t)));
}
return false;
return result(false, c);
};
}

public static Match<AbstractInsnNode> methodCallThatReturns(final ClassName type) {
return (c, t) -> {
if ( t instanceof MethodInsnNode ) {
return ((MethodInsnNode) t).desc.endsWith(type.asInternalName() + ";");
return result(((MethodInsnNode) t).desc.endsWith(type.asInternalName() + ";"), c);
}
return false;
return result(false, c);
};
}

Expand All @@ -137,34 +147,43 @@ public static Match<AbstractInsnNode> methodCallNamed(String name) {
return (c, t) -> {
if ( t instanceof MethodInsnNode ) {
final MethodInsnNode call = (MethodInsnNode) t;
return call.name.equals(name);
return result(call.name.equals(name), c);
}
return result(false, c);
};
}

public static Match<AbstractInsnNode> methodDescEquals(final String desc) {
return (c, t) -> {
if ( t instanceof MethodInsnNode ) {
return result(((MethodInsnNode) t).desc.equals(desc), c);
}
return false;
return result(false, c);
};
}

public static Match<AbstractInsnNode> methodCallTo(final ClassName owner, final String name) {
return (c, t) -> {
if ( t instanceof MethodInsnNode ) {
final MethodInsnNode call = (MethodInsnNode) t;
return call.name.equals(name) && call.owner.equals(owner.asInternalName());
return result( call.name.equals(name) && call.owner.equals(owner.asInternalName()), c);
}
return false;
return result(false, c);
};
}


public static Match<AbstractInsnNode> isInstruction(final SlotRead<AbstractInsnNode> target) {
return (c, t) -> c.retrieve(target).get() == t;
return (c, t) -> result(c.retrieve(target).get() == t, c);
}

public static Match<AbstractInsnNode> getStatic(String owner, String field) {
return (c, t) -> {
if (t instanceof FieldInsnNode) {
FieldInsnNode fieldNode = (FieldInsnNode) t;
return t.getOpcode() == Opcodes.GETSTATIC && fieldNode.name.equals(field) && fieldNode.owner.equals(owner);
return result( t.getOpcode() == Opcodes.GETSTATIC && fieldNode.name.equals(field) && fieldNode.owner.equals(owner), c);
}
return false;
return result(false, c);
};
}

Expand All @@ -174,9 +193,9 @@ public static Match<AbstractInsnNode> getStatic(String owner, String field) {
public static Match<AbstractInsnNode> recordTarget(final SlotRead<AbstractInsnNode> target, final SlotWrite<Boolean> found) {
return (c, t) -> {
if (c.retrieve(target).get() == t) {
c.store(found, true);
return result(true, c.store(found, true));
}
return true;
return result(true, c);
};
}

Expand All @@ -185,22 +204,21 @@ private static Match<AbstractInsnNode> storeJumpTarget(
final SlotWrite<LabelNode> label) {
return (c, t) -> {
if (t instanceof JumpInsnNode ) {
c.store(label, ((JumpInsnNode) t).label);
return true;
return result(true, c.store(label, ((JumpInsnNode) t).label));
}
return false;
return result(false, c);
};
}

public static Match<AbstractInsnNode> jumpsTo(
final SlotRead<LabelNode> loopStart) {
return (context, a) -> {
if (!(a instanceof JumpInsnNode)) {
return false;
return result(false, context);
}
final JumpInsnNode jump = (JumpInsnNode) a;

return context.retrieve(loopStart).filter(isEqual(jump.label)).isPresent();
return result(context.retrieve(loopStart).filter(isEqual(jump.label)).isPresent(), context);
};
}

Expand All @@ -218,19 +236,19 @@ public static Match<AbstractInsnNode> labelNode(
final SlotRead<LabelNode> loopEnd) {
return (c, t) -> {
if (!(t instanceof LabelNode)) {
return false;
return result(false, c);
}

final LabelNode l = (LabelNode) t;
return c.retrieve(loopEnd).filter(isEqual(l)).isPresent();
return result(c.retrieve(loopEnd).filter(isEqual(l)).isPresent(), c);

};
}

public static Match<AbstractInsnNode> debug(final String msg) {
return (context, a) -> {
context.debug(msg);
return true;
context.debug(msg, a);
return result(true, context);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,27 @@
*
* OTHER -
* MODIFY - Modify mutants in a way that is functionally significant (e.g mark as poisoning JVM)
* PRE_SCAN_FILTER - Remove mutants from processing, in prescan and main scan
* FILTER - Remove mutants from processing
* MODIFY_COSMETIC - Modify mutants in way that will not affect processing (e.g update descriptions)
* REPORT - Output mutant in their final state
*
*/
public enum InterceptorType {
OTHER, MODIFY, FILTER, MODIFY_COSMETIC, REPORT
OTHER(true),
MODIFY(true),
PRE_SCAN_FILTER(true),
FILTER(false),
MODIFY_COSMETIC(false),
REPORT(false);

private final boolean includeInPrescan;

InterceptorType(boolean includeInPrescan) {
this.includeInPrescan = includeInPrescan;
}

public boolean includeInPrescan() {
return includeInPrescan;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import org.pitest.bytecode.analysis.InstructionMatchers;
import org.pitest.bytecode.analysis.MethodMatchers;
import org.pitest.bytecode.analysis.MethodTree;
import org.pitest.functional.FCollection;
import org.pitest.mutationtest.build.InterceptorType;
import org.pitest.mutationtest.build.MutationInterceptor;
import org.pitest.mutationtest.engine.Location;
Expand All @@ -31,7 +30,7 @@ public class EqualsPerformanceShortcutFilter implements MutationInterceptor {

private static final boolean DEBUG = false;

// Looks fairly specifically for a conditional mutated to a unconditional
// Looks fairly specifically for a conditional mutated to an unconditional
// rather than any always false condition
static final SequenceMatcher<AbstractInsnNode> ALWAYS_FALSE = QueryStart
.any(AbstractInsnNode.class)
Expand Down Expand Up @@ -60,9 +59,14 @@ public void begin(ClassTree clazz) {
@Override
public Collection<MutationDetails> intercept(
Collection<MutationDetails> mutations, Mutater m) {
final List<MutationDetails> doNotTouch = FCollection.filter(mutations, inEqualsMethod().negate());
final List<MutationDetails> doNotTouch = mutations.stream()
.filter(inEqualsMethod().negate())
.collect(Collectors.toList());

if (doNotTouch.size() != mutations.size()) {
final List<MutationDetails> inEquals = FCollection.filter(mutations, inEqualsMethod());
final List<MutationDetails> inEquals = mutations.stream()
.filter(inEqualsMethod())
.collect(Collectors.toList());
final List<MutationDetails> filtered = filter(inEquals, m);
doNotTouch.addAll(filtered);
}
Expand All @@ -83,10 +87,10 @@ private List<MutationDetails> filter(
}

private Predicate<MutationDetails> isShortcutEquals(final MethodTree tree, final Mutater m) {
return a -> shortCutEquals(tree,a, m);
return a -> shortCutEquals(tree, a, m);
}

private Boolean shortCutEquals(MethodTree tree, MutationDetails a, Mutater m) {
private boolean shortCutEquals(MethodTree tree, MutationDetails a, Mutater m) {
if (!mutatesAConditionalJump(tree, a.getInstructionIndex())) {
return false;
}
Expand All @@ -102,7 +106,7 @@ private Boolean shortCutEquals(MethodTree tree, MutationDetails a, Mutater m) {

private boolean mutatesAConditionalJump(MethodTree tree, int index) {
final AbstractInsnNode mutatedInsns = tree.instruction(index);
return InstructionMatchers.aConditionalJump().test(null, mutatedInsns);
return InstructionMatchers.aConditionalJump().test(null, mutatedInsns).result();
}

private Predicate<MutationDetails> inEqualsMethod() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static org.pitest.bytecode.analysis.InstructionMatchers.notAnInstruction;
import static org.pitest.bytecode.analysis.InstructionMatchers.opCode;
import static org.pitest.bytecode.analysis.InstructionMatchers.variableMatches;
import static org.pitest.sequence.Result.result;

import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -151,8 +152,8 @@ private boolean primitiveTrue(int instruction, MethodTree method) {
}

private boolean boxedTrue(int instruction, MethodTree method) {
final Context<AbstractInsnNode> context = Context.start(method.instructions(), false);
context.store(MUTATED_INSTRUCTION.write(), method.instruction(instruction));
Context context = Context.start();
context = context.store(MUTATED_INSTRUCTION.write(), method.instruction(instruction));
return EQUIVALENT_TRUE.matches(method.instructions(), context);
}
};
Expand Down Expand Up @@ -295,7 +296,7 @@ private static Match<AbstractInsnNode> aStoreTo(Slot<Integer> variable) {
}

private static Match<AbstractInsnNode> isZeroConstant() {
return (context,node) -> ZERO_CONSTANTS.contains(node.getOpcode());
return (context,node) -> result(ZERO_CONSTANTS.contains(node.getOpcode()), context);
}

private Predicate<MutationDetails> isEquivalent(Mutater m) {
Expand All @@ -318,8 +319,8 @@ public boolean test(MutationDetails a) {

private Boolean returnsZeroValue(SequenceMatcher<AbstractInsnNode> sequence, MethodTree method,
int mutatedInstruction) {
final Context<AbstractInsnNode> context = Context.start(method.instructions(), false);
context.store(MUTATED_INSTRUCTION.write(), method.instruction(mutatedInstruction));
Context context = Context.start();
context = context.store(MUTATED_INSTRUCTION.write(), method.instruction(mutatedInstruction));
return sequence.matches(method.instructions(), context);
}

Expand Down Expand Up @@ -354,9 +355,9 @@ private static Match<AbstractInsnNode> takesNoArgs() {
return (c,node) -> {
if (node instanceof MethodInsnNode ) {
final MethodInsnNode call = (MethodInsnNode) node;
return Type.getArgumentTypes(call.desc).length == 0;
return result(Type.getArgumentTypes(call.desc).length == 0, c);
}
return false;
return result(false, c);
};
}

Expand Down
Loading