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

net.sourceforge.cobertura.instrument.pass3.InjectCodeClassInstrumenter 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.instrument.AbstractFindTouchPointsClassInstrumenter;
import net.sourceforge.cobertura.instrument.FindTouchPointsMethodAdapter;
import net.sourceforge.cobertura.instrument.tp.ClassMap;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.LocalVariablesSorter;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 

This class is responsible for real instrumentation of the user's class.

*

*

It uses information acquired * by {@link BuildClassMapClassVisitor} ( {@link #classMap} ) and * {@link DetectDuplicatedCodeClassVisitor} and injects * code snippet provided by {@link CodeProvider} ( {@link #codeProvider} ).

* * @author [email protected] */ public class InjectCodeClassInstrumenter extends AbstractFindTouchPointsClassInstrumenter { /** * This class is responsible for injecting code inside 'interesting places' of methods inside instrumented class */ private final InjectCodeTouchPointListener touchPointListener; /** * {@link ClassMap} generated in previous instrumentation pass by {@link BuildClassMapClassVisitor} */ private final ClassMap classMap; /** * {@link CodeProvider} used to generate pieces of asm code that is injected into instrumented class. *

* We are strictly recommending here using {@link FastArrayCodeProvider} instead of {@link AtomicArrayCodeProvider} because * of performance. */ private final CodeProvider codeProvider; /** * When we processing the class we want to now if we processed 'static initialization block' (clinit method). *

*

If there is no such a method in the instrumented class - we will need to generate it at the end

*/ private boolean wasStaticInitMethodVisited = false; private final Set ignoredMethods; /** * @param cv - a listener for code-instrumentation events * @param ignoreRegexes - list of patters of method calls that should be ignored from line-coverage-measurement * @param classMap - map of all interesting places in the class. You should acquire it by {@link BuildClassMapClassVisitor} and remember to * prepare it using {@link ClassMap#assignCounterIds()} before using it with {@link InjectCodeClassInstrumenter} * @param duplicatedLinesMap - map of found duplicates in the class. You should use {@link DetectDuplicatedCodeClassVisitor} to find the duplicated lines. */ public InjectCodeClassInstrumenter(ClassVisitor cv, Collection ignoreRegexes, boolean threadsafeRigorous, ClassMap classMap, Map> duplicatedLinesMap, Set ignoredMethods) { super(cv, ignoreRegexes, duplicatedLinesMap); this.classMap = classMap; this.ignoredMethods = ignoredMethods; codeProvider = threadsafeRigorous ? new AtomicArrayCodeProvider() : new FastArrayCodeProvider(); touchPointListener = new InjectCodeTouchPointListener(classMap, codeProvider); } /** *

Marks the class 'already instrumented' and injects code connected to the fields that are keeping counters.

*/ @Override public void visit(int version, int access, String name, String signature, String supertype, String[] interfaces) { super.visit(version, access, name, signature, supertype, interfaces); codeProvider.generateCountersField(cv); } /** *

Instrumenting a code in a single method. Special conditions for processing 'static initialization block'.

*

*

This method also uses {@link ShiftVariableMethodAdapter} that is used firstly to calculate the index of internal * variable injected to store information about last 'processed' jump or switch in runtime ( {@link ShiftVariableMethodAdapter#calculateFirstStackVariable(int, String)} ), * and then is used to inject code responsible for keeping the variable and shifting (+1) all previously seen variables. */ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (ignoredMethods.contains(name + desc)) { return mv; } if ((access & Opcodes.ACC_STATIC) != 0) { mv = new GenerateCallCoberturaInitMethodVisitor(mv, classMap .getClassName()); if ("".equals(name)) { wasStaticInitMethodVisited = true; } } FindTouchPointsMethodAdapter instrumenter = new FindTouchPointsMethodAdapter( mv, classMap.getClassName(), name, desc, eventIdGenerator, duplicatedLinesMap, lineIdGenerator); instrumenter.setTouchPointListener(touchPointListener); instrumenter.setIgnoreRegexp(getIgnoreRegexp()); LocalVariablesSorter sorter = new LocalVariablesSorter(access, desc, instrumenter); int variable = sorter.newLocal(Type.INT_TYPE); touchPointListener.setLastJumpIdVariableIndex(variable); return sorter; //return new ShiftVariableMethodAdapter(instrumenter, access, desc, 1); } /** * Method instrumenter that injects {@link CodeProvider#generateCINITmethod(MethodVisitor, String, int)} code, and * then forwards the whole previous content of the method. * * @author [email protected] */ private class GenerateCallCoberturaInitMethodVisitor extends MethodVisitor { private String className; public GenerateCallCoberturaInitMethodVisitor(MethodVisitor arg0, String className) { super(Opcodes.ASM4, arg0); this.className = className; } @Override public void visitCode() { codeProvider.generateCallCoberturaInitMethod(mv, className); super.visitCode(); } } /** *

If there was no 'static initialization block' in the class, the method is responsible for generating the method.
* It is also responsible for generating method that keeps mapping of counterIds into source places connected to them

*/ @Override public void visitEnd() { if (!wasStaticInitMethodVisited) { //We need to generate new method MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null); mv.visitCode(); codeProvider.generateCallCoberturaInitMethod(mv, classMap .getClassName()); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(/*stack*/3,/*local*/0); mv.visitEnd(); wasStaticInitMethodVisited = true; } codeProvider.generateCoberturaInitMethod(cv, classMap.getClassName(), classMap.getMaxCounterId() + 1); codeProvider.generateCoberturaClassMapMethod(cv, classMap); codeProvider.generateCoberturaGetAndResetCountersMethod(cv, classMap .getClassName()); super.visitEnd(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy