All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pitest.bytecode.analysis.InstructionMatchers Maven / Gradle / Ivy

There is a newer version: 1.17.1
Show newest version
package org.pitest.bytecode.analysis;

import static java.util.function.Predicate.isEqual;
import static org.objectweb.asm.Opcodes.ICONST_0;
import static org.objectweb.asm.Opcodes.ICONST_1;
import static org.objectweb.asm.Opcodes.ICONST_2;
import static org.objectweb.asm.Opcodes.ICONST_3;
import static org.objectweb.asm.Opcodes.ICONST_4;
import static org.objectweb.asm.Opcodes.ICONST_5;
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;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LineNumberNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.pitest.classinfo.ClassName;
import org.pitest.sequence.Match;
import org.pitest.sequence.Slot;
import org.pitest.sequence.SlotRead;
import org.pitest.sequence.SlotWrite;

import java.util.function.Predicate;

public class InstructionMatchers {

  public static Match anyInstruction() {
    return Match.always();
  }

  /**
   * Matches nodes that do not represent an instruction or label
   */
  public static Match notAnInstruction() {
     return isA(LineNumberNode.class).or(isA(FrameNode.class));
  }

  public static Match newCall(ClassName target) {
    final String clazz = target.asInternalName();
    return (c, t) -> {
      if ( t instanceof TypeInsnNode ) {
        final TypeInsnNode call = (TypeInsnNode) t;
        return result(call.getOpcode() == Opcodes.NEW && call.desc.equals(clazz), c);
      }
      return result(false, c);
    };
  }

  public static Match ldcString(Predicate match) {
    return (c, t) -> {
      if ( t instanceof LdcInsnNode) {
        final LdcInsnNode ldc = (LdcInsnNode) t;
        return result(ldc.cst instanceof String && match.test((String) ldc.cst), c);
      }
      return result(false, c);
    };
  }

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

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

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

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

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

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

  public static Match anIStoreTo(
      final SlotRead counterVariable) {
    return opCode(ISTORE).and(variableMatches(counterVariable));
  }

  public static Match anILoadOf(
      final SlotRead counterVariable) {
    return opCode(ILOAD).and(variableMatches(counterVariable));
  }

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


  public static Match anIntegerConstant() {
    return opCode(ICONST_M1)
        .or(opCode(ICONST_0))
        .or(opCode(ICONST_1))
        .or(opCode(ICONST_2))
        .or(opCode(ICONST_3))
        .or(opCode(ICONST_4))
        .or(opCode(ICONST_5));
  }

  public static Match aLabelNode(SlotWrite slot) {
    return isA(LabelNode.class).and(writeNodeToSlot(slot, LabelNode.class));
  }

  public static Match aJump() {
    return isA(JumpInsnNode.class);
  }

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

  public static Match aConditionalJumpTo(Slot label) {
    return jumpsTo(label.read()).and(aConditionalJump());
  }


  public static  Match writeNodeToSlot(final SlotWrite slot, final Class clazz) {
    return (c, t) -> {
      if (clazz.isAssignableFrom(t.getClass()) ) {
        return result(true, c.store(slot, clazz.cast(t)));
      }
      return result(false, c);
    };
  }

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

  public static  Match methodCall() {
    return isA(MethodInsnNode.class);
  }
  
  public static Match methodCallNamed(String name) {
    return (c, t) -> {
      if ( t instanceof MethodInsnNode ) {
        final MethodInsnNode call = (MethodInsnNode) t;
        return result(call.name.equals(name), c);
      }
      return result(false, c);
    };
  }

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

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


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

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

  /**
   * Records if a instruction matches the target, but always returns true
   */
  public static  Match recordTarget(final SlotRead target, final SlotWrite found) {
    return (c, t) -> {
      if (c.retrieve(target).get() == t) {
        return result(true, c.store(found, true));
      }
      return result(true, c);
    };
  }


  private static Match storeJumpTarget(
      final SlotWrite label) {
    return (c, t) -> {
      if (t instanceof JumpInsnNode ) {
        return result(true, c.store(label, ((JumpInsnNode) t).label));
      }
      return result(false, c);
    };
  }

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

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

  public static Match jumpsTo(
      final SlotWrite label) {
    return storeJumpTarget(label);
  }

  public static Match gotoLabel(
      final SlotWrite loopEnd) {
        return opCode(Opcodes.GOTO).and(storeJumpTarget(loopEnd));
  }

  public static Match labelNode(
      final SlotRead loopEnd) {
    return (c, t) -> {
     if (!(t instanceof LabelNode)) {
       return result(false, c);
     }

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

    };
  }

  public static Match debug(final String msg) {
    return (context, a) -> {
      context.debug(msg, a);
      return result(true, context);
    };
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy