Skip to content

Commit

Permalink
Merge pull request #1020 from hcoles/feature/extract_state_in_sequenc…
Browse files Browse the repository at this point in the history
…e_match

Rework NFA matching and try with resources filtering
  • Loading branch information
hcoles authored May 18, 2022
2 parents 28cc342 + fcb95e6 commit 98f4c55
Show file tree
Hide file tree
Showing 55 changed files with 1,299 additions and 610 deletions.
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

0 comments on commit 98f4c55

Please sign in to comment.