Java tutorial
/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.test.metric.asm; import static com.google.test.metric.asm.SignatureParser.parse; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import com.google.test.metric.ClassInfo; import com.google.test.metric.ClassRepository; import com.google.test.metric.FieldInfo; import com.google.test.metric.FieldNotFoundException; import com.google.test.metric.JavaType; import com.google.test.metric.LocalVariableInfo; import com.google.test.metric.MethodInfo; import com.google.test.metric.ParameterInfo; import com.google.test.metric.Type; import com.google.test.metric.Variable; import com.google.test.metric.Visibility; import com.google.test.metric.method.BlockDecomposer; import com.google.test.metric.method.Constant; import com.google.test.metric.method.op.stack.ArrayLoad; import com.google.test.metric.method.op.stack.ArrayStore; import com.google.test.metric.method.op.stack.Convert; import com.google.test.metric.method.op.stack.Duplicate; import com.google.test.metric.method.op.stack.Duplicate2; import com.google.test.metric.method.op.stack.GetField; import com.google.test.metric.method.op.stack.Increment; import com.google.test.metric.method.op.stack.Invoke; import com.google.test.metric.method.op.stack.Load; import com.google.test.metric.method.op.stack.MonitorEnter; import com.google.test.metric.method.op.stack.MonitorExit; import com.google.test.metric.method.op.stack.MultiANewArrayIns; import com.google.test.metric.method.op.stack.Pop; import com.google.test.metric.method.op.stack.RetSub; import com.google.test.metric.method.op.stack.Return; import com.google.test.metric.method.op.stack.Store; import com.google.test.metric.method.op.stack.Swap; import com.google.test.metric.method.op.stack.Throw; import com.google.test.metric.method.op.stack.Transform; public class MethodVisitorBuilder implements MethodVisitor { private final ClassInfo classInfo; private final String name; private final String desc; private final Visibility visibility; private final Map<Integer, Variable> slots = new HashMap<Integer, Variable>(); private final BlockDecomposer block = new BlockDecomposer(); private final List<Runnable> recorder = new ArrayList<Runnable>(); private final ClassRepository repository; private final List<Integer> cyclomaticComplexity = new ArrayList<Integer>(); private Variable methodThis; private int lineNumber; private final Map<Label, Integer> lineNumbers = new HashMap<Label, Integer>(); private int startingLineNumber; private final List<ParameterInfo> parameters = new ArrayList<ParameterInfo>(); private final List<LocalVariableInfo> localVariables = new ArrayList<LocalVariableInfo>(); private final boolean isFinal; private final JavaNamer namer = new JavaNamer(); public MethodVisitorBuilder(ClassRepository repository, ClassInfo classInfo, String name, String desc, String signature, String[] exceptions, boolean isStatic, boolean isFinal, Visibility visibility) { this.repository = repository; this.classInfo = classInfo; this.name = name; this.desc = desc; this.isFinal = isFinal; this.visibility = visibility; int slot = 0; if (!isStatic) { Type thisType = JavaType.fromJava(classInfo.getName()); methodThis = new LocalVariableInfo("this", thisType); slots.put(slot++, methodThis); localVariables.add((LocalVariableInfo) methodThis); } for (Type type : parse(desc).getParameters()) { ParameterInfo parameterInfo = new ParameterInfo("param_" + slot, type); parameters.add(parameterInfo); slots.put(slot++, parameterInfo); if (JavaType.isDoubleSlot(type)) { slot++; } } } public void visitJumpInsn(final int opcode, final Label label) { if (opcode == Opcodes.GOTO) { recorder.add(new Runnable() { public void run() { block.addOp(new Transform(lineNumber, "GOTO", null, null, null)); block.unconditionalGoto(label); } }); } else if (opcode == Opcodes.JSR) { recorder.add(new Runnable() { public void run() { block.jumpSubroutine(label, lineNumber); } }); } else { recorder.add(new Runnable() { public void run() { cyclomaticComplexity.add(lineNumber); switch (opcode) { case Opcodes.IFEQ: if1("IFEQ"); break; case Opcodes.IFNE: if1("IFNE"); break; case Opcodes.IFLT: if1("IFLT"); break; case Opcodes.IFGE: if1("IFGE"); break; case Opcodes.IFGT: if1("IFGT"); break; case Opcodes.IFLE: if1("IFLE"); break; case Opcodes.IFNONNULL: if1("IFNONNULL"); break; case Opcodes.IFNULL: if1("IFNULL"); break; case Opcodes.IF_ACMPEQ: if2("IF_ACMPEQ"); break; case Opcodes.IF_ACMPNE: if2("IF_ACMPNE"); break; case Opcodes.IF_ICMPEQ: if2("IF_ICMPEQ"); break; case Opcodes.IF_ICMPGE: if2("IF_ICMPGE"); break; case Opcodes.IF_ICMPGT: if2("IF_ICMPGT"); break; case Opcodes.IF_ICMPLE: if2("IF_ICMPLE"); break; case Opcodes.IF_ICMPLT: if2("IF_ICMPLT"); break; case Opcodes.IF_ICMPNE: if2("IF_ICMPNE"); break; default: throw new UnsupportedOperationException("" + opcode); } block.conditionalGoto(label); } private void if1(String name) { block.addOp(new Transform(lineNumber, name, JavaType.INT, null, null)); } private void if2(String name) { block.addOp(new Transform(lineNumber, name, JavaType.INT, JavaType.INT, null)); } }); } } public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) { recorder.add(new Runnable() { public void run() { if (type != null) { cyclomaticComplexity.add(getLineNumberForLable(handler)); } block.tryCatchBlock(start, end, handler, type); } }); } private Integer getLineNumberForLable(final Label label) { Integer line = lineNumbers.get(label); return line == null ? -1 : line; } public void visitTableSwitchInsn(int min, int max, final Label dflt, final Label[] labels) { recorder.add(new Runnable() { public void run() { for (Label label : labels) { if (label != dflt) { cyclomaticComplexity.add(getLineNumberForLable(label)); } } block.addOp(new Pop(lineNumber, 1)); block.tableSwitch(dflt, labels); } }); } public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { recorder.add(new Runnable() { public void run() { for (Label label : labels) { if (label != null) { cyclomaticComplexity.add(getLineNumberForLable(label)); } } block.addOp(new Pop(lineNumber, 1)); block.tableSwitch(dflt, labels); } }); } public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int slotNum) { Type type = JavaType.fromDesc(desc); Variable variable = slots.get(slotNum); if (variable == null) { LocalVariableInfo localVar = new LocalVariableInfo(name, type); slots.put(slotNum, localVar); localVariables.add(localVar); } else { variable.setName(name); } } public void visitLineNumber(final int line, final Label start) { lineNumbers.put(start, line); recorder.add(new Runnable() { // $6 public void run() { if (lineNumber == 0) { startingLineNumber = line; } lineNumber = line; } }); } public void visitEnd() { for (Runnable runnable : recorder) { runnable.run(); } block.decomposeIntoBlocks(); try { String javaName = namer.nameMethod(classInfo.getName(), name, desc); boolean isConstructor = name.equals("<init>") || name.equals("<clinit>"); MethodInfo methodInfo = new MethodInfo(classInfo, javaName, startingLineNumber, methodThis, parameters, localVariables, visibility, block.getOperations(), isFinal, isConstructor, cyclomaticComplexity); classInfo.addMethod(methodInfo); } catch (IllegalStateException e) { throw new IllegalStateException("Error in " + classInfo + "." + name + desc, e); } } public void visitTypeInsn(final int opcode, final String desc) { if (desc.length() == 1) { throw new IllegalStateException("WARNING! I don't expect primitive types:" + desc); } final Type type = desc.contains(";") ? JavaType.fromDesc(desc) : JavaType.fromJava(desc); recorder.add(new Runnable() { public void run() { switch (opcode) { case Opcodes.NEW: Constant constant = new Constant("new", type); block.addOp(new Load(lineNumber, constant)); break; case Opcodes.NEWARRAY: case Opcodes.ANEWARRAY: block.addOp(new Transform(lineNumber, "newarray", JavaType.INT, null, type.toArray())); break; case Opcodes.INSTANCEOF: block.addOp(new Transform(lineNumber, "instanceof", JavaType.OBJECT, null, JavaType.INT)); break; case Opcodes.CHECKCAST: block.addOp(new Transform(lineNumber, "checkcast", type, null, type)); break; default: throw new UnsupportedOperationException("" + opcode); } } }); } public void visitVarInsn(final int opcode, final int var) { switch (opcode) { case Opcodes.ILOAD: load(var, JavaType.INT); break; case Opcodes.LLOAD: load(var, JavaType.LONG); break; case Opcodes.FLOAD: load(var, JavaType.FLOAT); break; case Opcodes.DLOAD: load(var, JavaType.DOUBLE); break; case Opcodes.ALOAD: load(var, JavaType.OBJECT); break; case Opcodes.ISTORE: store(var, JavaType.INT); break; case Opcodes.LSTORE: store(var, JavaType.LONG); break; case Opcodes.FSTORE: store(var, JavaType.FLOAT); break; case Opcodes.DSTORE: store(var, JavaType.DOUBLE); break; case Opcodes.ASTORE: store(var, JavaType.OBJECT); break; case Opcodes.RET: recorder.add(new Runnable() { public void run() { block.addOp(new RetSub(lineNumber)); } }); break; default: throw new UnsupportedOperationException("opcode: " + opcode); } } private void store(final int var, final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new Store(lineNumber, variable(var, type))); } }); } private void load(final int var, final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new Load(lineNumber, variable(var, type))); } }); } private Variable variable(int varIndex, Type type) { Variable variable = slots.get(varIndex); if (variable == null) { LocalVariableInfo localVar = new LocalVariableInfo("local_" + varIndex, type); slots.put(varIndex, localVar); localVariables.add(localVar); variable = localVar; } Type varType = variable.getType(); if (!varType.equals(type) && (type.isPrimitive() || varType.isPrimitive())) { // Apparently the compiler reuses local variables and it is possible // that the types change. So if types change we have to drop // the variable and try again. slots.put(varIndex, null); return variable(varIndex, type); } return variable; } public void visitLabel(final Label label) { recorder.add(new Runnable() { // $11 public void run() { block.label(label); } }); } public void visitLdcInsn(final Object cst) { recorder.add(new Runnable() { public void run() { block.addOp(new Load(lineNumber, new Constant(cst, JavaType.fromClass(cst.getClass())))); } }); } public void visitInsn(final int opcode) { switch (opcode) { case Opcodes.ACONST_NULL: recorder.add(new Runnable() { public void run() { block.addOp(new Load(lineNumber, new Constant(null, JavaType.OBJECT))); } }); break; case Opcodes.ICONST_M1: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: loadConstant(opcode - Opcodes.ICONST_M1 - 1, JavaType.INT); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: loadConstant(opcode - Opcodes.LCONST_0, JavaType.LONG); break; case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: loadConstant(opcode - Opcodes.FCONST_0, JavaType.FLOAT); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: loadConstant(opcode - Opcodes.DCONST_0, JavaType.DOUBLE); break; case Opcodes.IALOAD: recordArrayLoad(JavaType.INT); break; case Opcodes.LALOAD: recordArrayLoad(JavaType.LONG); break; case Opcodes.FALOAD: recordArrayLoad(JavaType.FLOAT); break; case Opcodes.DALOAD: recordArrayLoad(JavaType.DOUBLE); break; case Opcodes.AALOAD: recordArrayLoad(JavaType.OBJECT); break; case Opcodes.BALOAD: recordArrayLoad(JavaType.BYTE); break; case Opcodes.CALOAD: recordArrayLoad(JavaType.CHAR); break; case Opcodes.SALOAD: recordArrayLoad(JavaType.SHORT); break; case Opcodes.IASTORE: recordArrayStore(JavaType.INT); break; case Opcodes.LASTORE: recordArrayStore(JavaType.LONG); break; case Opcodes.FASTORE: recordArrayStore(JavaType.FLOAT); break; case Opcodes.DASTORE: recordArrayStore(JavaType.DOUBLE); break; case Opcodes.AASTORE: recordArrayStore(JavaType.OBJECT); break; case Opcodes.BASTORE: recordArrayStore(JavaType.BYTE); break; case Opcodes.CASTORE: recordArrayStore(JavaType.CHAR); break; case Opcodes.SASTORE: recordArrayStore(JavaType.SHORT); break; case Opcodes.POP: case Opcodes.POP2: recorder.add(new Runnable() { public void run() { block.addOp(new Pop(lineNumber, opcode - Opcodes.POP + 1)); } }); break; case Opcodes.DUP: case Opcodes.DUP_X1: case Opcodes.DUP_X2: recorder.add(new Runnable() { public void run() { int offset = opcode - Opcodes.DUP; block.addOp(new Duplicate(lineNumber, offset)); } }); break; case Opcodes.DUP2: case Opcodes.DUP2_X1: case Opcodes.DUP2_X2: recorder.add(new Runnable() { public void run() { block.addOp(new Duplicate2(lineNumber, opcode - Opcodes.DUP2)); } }); break; case Opcodes.SWAP: recorder.add(new Runnable() { public void run() { block.addOp(new Swap(lineNumber)); } }); break; case Opcodes.IRETURN: _return(JavaType.INT); break; case Opcodes.FRETURN: _return(JavaType.FLOAT); break; case Opcodes.ARETURN: _return(JavaType.OBJECT); break; case Opcodes.LRETURN: _return(JavaType.LONG); break; case Opcodes.DRETURN: _return(JavaType.DOUBLE); break; case Opcodes.ATHROW: recorder.add(new Runnable() { public void run() { block.addOp(new Throw(lineNumber)); } }); break; case Opcodes.RETURN: _return(JavaType.VOID); break; case Opcodes.LCMP: operation("cmp", JavaType.LONG, JavaType.LONG, JavaType.INT); break; case Opcodes.FCMPL: operation("cmpl", JavaType.FLOAT, JavaType.FLOAT, JavaType.INT); break; case Opcodes.FCMPG: operation("cmpg", JavaType.FLOAT, JavaType.FLOAT, JavaType.INT); break; case Opcodes.DCMPL: operation("cmpl", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.INT); break; case Opcodes.DCMPG: operation("cmpg", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.INT); break; case Opcodes.LSHL: operation("shl", JavaType.LONG, JavaType.INT, JavaType.LONG); break; case Opcodes.LSHR: operation("shr", JavaType.LONG, JavaType.INT, JavaType.LONG); break; case Opcodes.LUSHR: operation("ushr", JavaType.LONG, JavaType.INT, JavaType.LONG); break; case Opcodes.LADD: operation("add", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LSUB: operation("sub", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LDIV: operation("div", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LREM: operation("rem", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LAND: operation("and", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LOR: operation("or", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LXOR: operation("xor", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.LMUL: operation("mul", JavaType.LONG, JavaType.LONG, JavaType.LONG); break; case Opcodes.FADD: operation("add", JavaType.FLOAT, JavaType.FLOAT, JavaType.FLOAT); break; case Opcodes.FSUB: operation("sub", JavaType.FLOAT, JavaType.FLOAT, JavaType.FLOAT); break; case Opcodes.FMUL: operation("mul", JavaType.FLOAT, JavaType.FLOAT, JavaType.FLOAT); break; case Opcodes.FREM: operation("rem", JavaType.FLOAT, JavaType.FLOAT, JavaType.FLOAT); break; case Opcodes.FDIV: operation("div", JavaType.FLOAT, JavaType.FLOAT, JavaType.FLOAT); break; case Opcodes.ISHL: operation("shl", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.ISHR: operation("shr", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IUSHR: operation("ushr", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IADD: operation("add", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.ISUB: operation("sub", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IMUL: operation("mul", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IDIV: operation("div", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IREM: operation("rem", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IAND: operation("and", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IOR: operation("or", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.IXOR: operation("xor", JavaType.INT, JavaType.INT, JavaType.INT); break; case Opcodes.DSUB: operation("sub", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.DOUBLE); break; case Opcodes.DADD: operation("add", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.DOUBLE); break; case Opcodes.DMUL: operation("mul", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.DOUBLE); break; case Opcodes.DDIV: operation("div", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.DOUBLE); break; case Opcodes.DREM: operation("rem", JavaType.DOUBLE, JavaType.DOUBLE, JavaType.DOUBLE); break; case Opcodes.L2I: convert(JavaType.LONG, JavaType.INT); break; case Opcodes.L2F: convert(JavaType.LONG, JavaType.FLOAT); break; case Opcodes.L2D: convert(JavaType.LONG, JavaType.DOUBLE); break; case Opcodes.LNEG: operation("neg", JavaType.LONG, null, JavaType.LONG); break; case Opcodes.F2I: convert(JavaType.FLOAT, JavaType.INT); break; case Opcodes.F2L: convert(JavaType.FLOAT, JavaType.LONG); break; case Opcodes.FNEG: operation("neg", JavaType.FLOAT, null, JavaType.FLOAT); break; case Opcodes.F2D: convert(JavaType.FLOAT, JavaType.DOUBLE); break; case Opcodes.D2I: convert(JavaType.DOUBLE, JavaType.INT); break; case Opcodes.D2L: convert(JavaType.DOUBLE, JavaType.LONG); break; case Opcodes.D2F: convert(JavaType.DOUBLE, JavaType.FLOAT); break; case Opcodes.DNEG: operation("neg", JavaType.DOUBLE, null, JavaType.DOUBLE); break; case Opcodes.I2L: convert(JavaType.INT, JavaType.LONG); break; case Opcodes.I2F: convert(JavaType.INT, JavaType.FLOAT); break; case Opcodes.I2D: convert(JavaType.INT, JavaType.DOUBLE); break; case Opcodes.I2B: convert(JavaType.INT, JavaType.BYTE); break; case Opcodes.I2C: convert(JavaType.INT, JavaType.CHAR); break; case Opcodes.I2S: convert(JavaType.INT, JavaType.SHORT); break; case Opcodes.INEG: operation("neg", JavaType.INT, null, JavaType.INT); break; case Opcodes.ARRAYLENGTH: operation("arraylength", JavaType.OBJECT.toArray(), null, JavaType.INT); break; case Opcodes.MONITORENTER: recorder.add(new Runnable() { public void run() { block.addOp(new MonitorEnter(lineNumber)); } }); break; case Opcodes.MONITOREXIT: recorder.add(new Runnable() { public void run() { block.addOp(new MonitorExit(lineNumber)); } }); break; case Opcodes.NOP: recorder.add(new Runnable() { public void run() { block.addOp(new Transform(lineNumber, "NOP", null, null, null)); } }); } } private void operation(final String operation, final Type op1, final Type op2, final Type result) { recorder.add(new Runnable() { public void run() { block.addOp(new Transform(lineNumber, operation, op1, op2, result)); } }); } private void convert(final Type from, final Type to) { recorder.add(new Runnable() { public void run() { block.addOp(new Convert(lineNumber, from, to)); } }); } private void _return(final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new Return(lineNumber, type)); } }); } private void recordArrayLoad(final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new ArrayLoad(lineNumber, type)); } }); } private void recordArrayStore(final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new ArrayStore(lineNumber, type)); } }); } private void loadConstant(final int constant, final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new Load(lineNumber, new Constant(constant, type))); } }); } public void visitFieldInsn(final int opcode, String owner, final String name, final String desc) { owner = namer.nameClass(owner); switch (opcode) { case Opcodes.PUTSTATIC: recorder.add(new PutFieldRunnable(repository, owner, name, desc, true)); break; case Opcodes.PUTFIELD: recorder.add(new PutFieldRunnable(repository, owner, name, desc, false)); break; case Opcodes.GETSTATIC: recorder.add(new GetFieldRunnable(repository, owner, name, desc, true)); break; case Opcodes.GETFIELD: recorder.add(new GetFieldRunnable(repository, owner, name, desc, false)); break; } } public void visitMethodInsn(final int opcode, final String clazz, final String name, final String desc) { SignatureParser signature = parse(desc); final List<Type> params = signature.getParameters(); final Type returnType = signature.getReturnType(); recorder.add(new Runnable() { public void run() { String className = namer.nameClass(clazz); block.addOp(new Invoke(lineNumber, className, namer.nameMethod(className, name, desc), params, opcode == Opcodes.INVOKESTATIC, returnType)); } }); } public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) { return null; } public AnnotationVisitor visitAnnotationDefault() { return null; } public void visitAttribute(Attribute arg0) { } public void visitCode() { } public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, Object[] arg4) { } public void visitIincInsn(final int var, final int increment) { recorder.add(new Runnable() { public void run() { Variable variable = variable(var, JavaType.INT); block.addOp(new Increment(lineNumber, increment, variable)); } }); } public void visitIntInsn(int opcode, int operand) { switch (opcode) { case Opcodes.NEWARRAY: newArray(operand, toType(operand)); break; case Opcodes.BIPUSH: loadConstant(operand, JavaType.INT); break; case Opcodes.SIPUSH: loadConstant(operand, JavaType.INT); break; default: throw new UnsupportedOperationException("Unexpected opcode: " + opcode); } } private Type toType(int operand) { switch (operand) { case Opcodes.T_BOOLEAN: return JavaType.BOOLEAN; case Opcodes.T_BYTE: return JavaType.BYTE; case Opcodes.T_CHAR: return JavaType.CHAR; case Opcodes.T_DOUBLE: return JavaType.DOUBLE; case Opcodes.T_FLOAT: return JavaType.FLOAT; case Opcodes.T_INT: return JavaType.INT; case Opcodes.T_LONG: return JavaType.LONG; case Opcodes.T_SHORT: return JavaType.SHORT; default: throw new IllegalArgumentException(); } } private void newArray(final int operand, final Type type) { recorder.add(new Runnable() { public void run() { block.addOp(new Transform(lineNumber, "newarray", JavaType.INT, null, type.toArray())); } }); } public void visitMaxs(int maxStack, int maxLocals) { } public void visitMultiANewArrayInsn(final String clazz, final int dims) { recorder.add(new Runnable() { public void run() { block.addOp(new MultiANewArrayIns(lineNumber, JavaType.fromDesc(clazz), dims)); } }); } public AnnotationVisitor visitParameterAnnotation(int arg0, String arg1, boolean arg2) { return null; } @Override public String toString() { return classInfo + "." + name + desc + "\n" + block; } private class PutFieldRunnable implements Runnable { private final String fieldOwner; private final String fieldName; private final String fieldDesc; private final boolean isStatic; private final ClassRepository repository; public PutFieldRunnable(ClassRepository repository, String owner, String name, String desc, boolean isStatic) { this.repository = repository; this.fieldOwner = owner; this.fieldName = name; this.fieldDesc = desc; this.isStatic = isStatic; } public void run() { FieldInfo field = null; ClassInfo ownerClass = repository.getClass(fieldOwner); try { field = ownerClass.getField(fieldName); } catch (FieldNotFoundException e) { field = new FieldInfo(ownerClass, "FAKE:" + fieldName, JavaType.fromDesc(fieldDesc), false, isStatic, false); } block.addOp(new com.google.test.metric.method.op.stack.PutField(lineNumber, field)); } } private class GetFieldRunnable implements Runnable { private final String fieldOwner; private final String fieldName; private final String fieldDesc; private final boolean isStatic; private final ClassRepository repository; public GetFieldRunnable(ClassRepository repository, String owner, String name, String desc, boolean isStatic) { this.repository = repository; this.fieldOwner = owner; this.fieldName = name; this.fieldDesc = desc; this.isStatic = isStatic; } public void run() { FieldInfo field = null; ClassInfo ownerClass = repository.getClass(fieldOwner); try { field = ownerClass.getField(fieldName); } catch (FieldNotFoundException e) { field = new FieldInfo(ownerClass, "FAKE:" + fieldName, JavaType.fromDesc(fieldDesc), false, isStatic, false); } block.addOp(new GetField(lineNumber, field)); } } }