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

net.sourceforge.cobertura.instrument.pass3.AbstractCodeProvider Maven / Gradle / Ivy

Go to download

Cobertura is a free Java tool that calculates the percentage of code accessed by tests. It can be used to identify which parts of your Java program are lacking test coverage. It is based on jcoverage.

There is a newer version: 2.1.1
Show newest version
/*
 * Cobertura - http://cobertura.sourceforge.net/
 *
 * Copyright (C) 2011 Piotr Tabor
 *
 * Note: This file is dual licensed under the GPL and the Apache
 * Source License (so that it can be used from both the main
 * Cobertura classes and the ant tasks).
 *
 * Cobertura is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * Cobertura is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cobertura; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

package net.sourceforge.cobertura.instrument.pass3;

import net.sourceforge.cobertura.coveragedata.LightClassmapListener;
import net.sourceforge.cobertura.coveragedata.TouchCollector;
import net.sourceforge.cobertura.instrument.tp.*;
import org.objectweb.asm.*;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
 * Common method used by most of {@link AbstractCodeProvider} implementations.
 * The methods realized here are independent on counters storing structure.
 *
 * @author [email protected]
 */
public abstract class AbstractCodeProvider implements CodeProvider {

	/**
	 * CounterId used to store unnecessary events to avoid fake jump counting in
	 * instrumented(generated) code
	 */
	public static final int FAKE_COUNTER_ID = 0;

	public AbstractCodeProvider() {
		super();
	}

	public void generateCodeThatSetsJumpCounterIdVariable(
			MethodVisitor nextMethodVisitor, int new_value,
			int lastJumpIdVariableIndex) {
		nextMethodVisitor.visitLdcInsn(new_value);
		nextMethodVisitor.visitVarInsn(Opcodes.ISTORE, lastJumpIdVariableIndex);
	}

	public void generateCodeThatZeroJumpCounterIdVariable(
			MethodVisitor nextMethodVisitor, int lastJumpIdVariableIndex) {
		generateCodeThatSetsJumpCounterIdVariable(nextMethodVisitor,
				FAKE_COUNTER_ID, lastJumpIdVariableIndex);
	}

	public void generateCodeThatIncrementsCoberturaCounterIfVariableEqualsAndCleanVariable(
			MethodVisitor nextMethodVisitor,
			Integer neededJumpCounterIdVariableValue,
			Integer counterIdToIncrement, int lastJumpIdVariableIndex,
			String className) {

		nextMethodVisitor.visitLdcInsn((int) neededJumpCounterIdVariableValue);
		nextMethodVisitor.visitVarInsn(Opcodes.ILOAD, lastJumpIdVariableIndex);
		Label afterJump = new Label();
		nextMethodVisitor.visitJumpInsn(Opcodes.IF_ICMPNE, afterJump);
		generateCodeThatIncrementsCoberturaCounter(nextMethodVisitor,
				counterIdToIncrement, className);
		generateCodeThatZeroJumpCounterIdVariable(nextMethodVisitor,
				lastJumpIdVariableIndex);
		nextMethodVisitor.visitLabel(afterJump);
	}

	/**
	 * {@inheritDoc}
	 * 

* The code injected by this implementation just registers the class using {@link TouchCollector#registerClass(Class)}. This way, during the * execution, touch collector knows that is responsible to ask the class after execution about a current status of the counters. */ protected void generateRegisterClass(MethodVisitor mv, String className) { mv.visitLdcInsn(className); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type .getInternalName(TouchCollector.class), "registerClass", "(Ljava/lang/String;)V"); } final String CLASSMAP_LISTENER_INTERNALNAME = Type .getInternalName(LightClassmapListener.class); /** * {@inheritDoc}

*

* Generates method (named {@link #COBERTURA_CLASSMAP_METHOD_NAME}) with such a signature: * __cobertura_classmap( {@link LightClassmapListener} listener).
*

* The method informs the listener about all lines, jumps and switches found, and about all counters tracking * the constructions. */ public void generateCoberturaClassMapMethod(ClassVisitor cv, ClassMap classMap) { LinkedList touchPointDescriptors = new LinkedList( classMap.getTouchPointsInLineOrder()); int parts = 0; for (int j = 0; touchPointDescriptors.size() > 0; j++) { List bufor = new LinkedList(); for (int i = 0; i < 1000 && touchPointDescriptors.size() > 0; i++) { bufor.add(touchPointDescriptors.removeFirst()); } classMapContent(cv, j, bufor); parts++; } MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, COBERTURA_CLASSMAP_METHOD_NAME, "(" + Type.getType(LightClassmapListener.class).toString() + ")V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(classMap.getClassName()); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, CLASSMAP_LISTENER_INTERNALNAME, "setClazz", "(Ljava/lang/String;)V"); if (classMap.getSource() != null) { mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(classMap.getSource()); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, CLASSMAP_LISTENER_INTERNALNAME, "setSource", "(Ljava/lang/String;)V"); } for (int i = 0; i < parts; i++) { mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn(Opcodes.INVOKESTATIC, classMap.getClassName(), COBERTURA_CLASSMAP_METHOD_NAME + "_" + i, "(" + Type.getType(LightClassmapListener.class) .toString() + ")V"); } mv.visitInsn(Opcodes.POP); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0);//will be recalculated by writer mv.visitEnd(); } enum Abcd { A, B, C; } private void classMapContent(ClassVisitor cv, int nr, List touchPointDescriptors) { MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, COBERTURA_CLASSMAP_METHOD_NAME + "_" + nr, "(" + Type.getType(LightClassmapListener.class).toString() + ")V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); for (TouchPointDescriptor tpd : touchPointDescriptors) { mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(tpd.getLineNumber()); if (tpd instanceof LineTouchPointDescriptor) { mv .visitLdcInsn(((LineTouchPointDescriptor) tpd) .getCounterId()); mv.visitLdcInsn(((LineTouchPointDescriptor) tpd) .getMethodName()); mv.visitLdcInsn(((LineTouchPointDescriptor) tpd) .getMethodSignature()); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, CLASSMAP_LISTENER_INTERNALNAME, "putLineTouchPoint", "(IILjava/lang/String;Ljava/lang/String;)V"); } else if (tpd instanceof JumpTouchPointDescriptor) { mv.visitLdcInsn(((JumpTouchPointDescriptor) tpd) .getCounterIdForTrue()); mv.visitLdcInsn(((JumpTouchPointDescriptor) tpd) .getCounterIdForFalse()); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, CLASSMAP_LISTENER_INTERNALNAME, "putJumpTouchPoint", "(III)V"); } else if (tpd instanceof SwitchTouchPointDescriptor) { SwitchTouchPointDescriptor stpd = (SwitchTouchPointDescriptor) tpd; final String enum_sign = ((SwitchTouchPointDescriptor) tpd) .getEnumType(); if (enum_sign == null) { mv.visitLdcInsn(Integer.MAX_VALUE); } else { mv.visitMethodInsn(Opcodes.INVOKESTATIC, enum_sign, "values", "()[L" + enum_sign + ";"); mv.visitInsn(Opcodes.ARRAYLENGTH); } Collection ci = stpd.getCountersForLabels(); mv.visitLdcInsn(ci.size());//Size of a new table mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT); int i = 0; for (Integer counterId : ci) { mv.visitInsn(Opcodes.DUP); //First for addition of items, second ad putSwitchTouchPoint parameter (or next loop iteration) mv.visitLdcInsn(i); mv.visitLdcInsn(counterId); mv.visitInsn(Opcodes.IASTORE); i++; } mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, CLASSMAP_LISTENER_INTERNALNAME, "putSwitchTouchPoint", "(II[I)V"); } } mv.visitInsn(Opcodes.POP); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0);//will be recalculated by writer mv.visitEnd(); } /** * Generates code that is injected into static constructor of an instrumented class. *

* It is good place to initiate static fields inserted into a class ({@link #generateCountersField(ClassVisitor)}), * or execute other code that should be executed when the class it used for the first time. Registering the class in * {@link TouchCollector} would be a bright idea. *

* It is expected that all counter will be set to zero after that operation. * * @param mv - {@link MethodVisitor} that is listener of code-generation events * @param className - internal name (asm) of class being instrumented * @param counters_cnt - information about how many counters are expected to be used by instrumentation code. * In most cases the method is responsible for allocating objects that will be used to store counters. */ protected abstract void generateCINITmethod(MethodVisitor mv, String className, int counters_cnt); public void generateCoberturaInitMethod(ClassVisitor cv, String className, int countersCnt) { MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, COBERTURA_INIT_METHOD_NAME, "()V", null, null); mv.visitCode(); generateCINITmethod(mv, className, countersCnt); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); //will be recalculated by writer mv.visitEnd(); } public void generateCallCoberturaInitMethod(MethodVisitor mv, String className) { mv.visitCode(); // Since we are using the ASM Check Adapter, we need to visit the code before visiting any instructions. mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, COBERTURA_INIT_METHOD_NAME, "()V"); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy