001/*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2011 Piotr Tabor
005 *
006 * Note: This file is dual licensed under the GPL and the Apache
007 * Source License (so that it can be used from both the main
008 * Cobertura classes and the ant tasks).
009 *
010 * Cobertura is free software; you can redistribute it and/or modify
011 * it under the terms of the GNU General Public License as published
012 * by the Free Software Foundation; either version 2 of the License,
013 * or (at your option) any later version.
014 *
015 * Cobertura is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of
017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018 * General Public License for more details.
019 *
020 * You should have received a copy of the GNU General Public License
021 * along with Cobertura; if not, write to the Free Software
022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
023 * USA
024 */
025
026package net.sourceforge.cobertura.instrument.pass3;
027
028import net.sourceforge.cobertura.instrument.tp.ClassMap;
029
030import org.objectweb.asm.ClassVisitor;
031import org.objectweb.asm.MethodVisitor;
032
033/**
034 * Universal API for all methods that are responsible for generating any JASM code that have
035 * to be injected into real classes. 
036 * 
037 *  The general idea is that injected code is responsible for incrementing counters. The realization of counters
038 *  is implementation dependent. 
039 * 
040 * @author piotr.tabor@gmail.com
041 *
042 */
043public interface CodeProvider { 
044        /**
045         * Name of a field that have to be injected into instrumented class that is responsible for storing counters  
046         */
047        public static final String COBERTURA_COUNTERS_FIELD_NAME  = "__cobertura_counters";
048        
049        /**
050         * Name of a method that will to be injected into instrumented class that is responsible for storing
051         * class-map (information on mapping of counter identifiers into lines, jumps and switch-touches). 
052         */
053        public static final String COBERTURA_CLASSMAP_METHOD_NAME = "__cobertura_classmap";
054        
055        /**
056         * Name of method that will initialize internal counters variable.
057         */
058        public static final String COBERTURA_INIT_METHOD_NAME = "__cobertura_init";
059        
060        /**
061         * Name of a method that have to be injected into instrumented class that is responsible for reading
062         * value of given counter.
063         * 
064         * Signature of this method is: int[] __cobertura_counter(int counterId);
065         */
066        public static final String COBERTURA_GET_AND_RESET_COUNTERS_METHOD_NAME  = "__cobertura_get_and_reset_counters";
067
068        
069        /**
070         * Generates fields injected into  instrumented class  by cobertura. 
071         * 
072         * @param cv - ClassVisitor that is listener of code-generation events
073         */
074        public abstract void generateCountersField(ClassVisitor cv);
075        
076        /**
077         * Injects code that increments counter given by parameter.     
078         * 
079         * @param nextMethodVisitor - {@link MethodVisitor} that is listener of code-generation events
080         * @param counterId -  counterId of counter that have to be incremented 
081         * @param className  - internal name (asm) of class being instrumented
082         */     
083        public abstract void generateCodeThatIncrementsCoberturaCounter(
084                        MethodVisitor nextMethodVisitor, Integer counterId, String className);
085        
086        /**
087         * Injects code that increments counter given by internal variable. 
088         * The id of the variable is identified by lastJumpIdVariableIndex. The variable is in most cases set (by {@link #generateCodeThatSetsJumpCounterIdVariable(MethodVisitor, int, int)} 
089         * to some counterId and in the target label, the counter identified by the variable is incremented.    
090         * long
091         * @param nextMethodVisitor          - {@link MethodVisitor} that is listener of code-generation events
092         * @param lastJumpIdVariableIndex    - id of the variable used to store counterId that have to be incremented 
093         * @param className                  - internal name (asm) of class being instrumented
094         */     
095        public abstract void generateCodeThatIncrementsCoberturaCounterFromInternalVariable(
096                        MethodVisitor nextMethodVisitor, int lastJumpIdVariableIndex,
097                        String className);
098
099        /**
100         * Injects code that sets internal variable (identified by lastJumpIdVariableIndex) to given value.
101         * 
102         * @param nextMethodVisitor       - {@link MethodVisitor} that is listener of code-generation events
103         * @param new_value               - value to set the variable to 
104         * @param lastJumpIdVariableIndex - index of variable that have to be set
105         */
106        public abstract void generateCodeThatSetsJumpCounterIdVariable(
107                        MethodVisitor nextMethodVisitor, int new_value,
108                        int lastJumpIdVariableIndex);
109
110        /**
111         * Injects code that sets internal variable (identified by lastJumpIdVariableIndex) to zero.
112         * 
113         * @param nextMethodVisitor       - {@link MethodVisitor} that is listener of code-generation events 
114         * @param lastJumpIdVariableIndex - index of variable that have to be set
115         */
116        public abstract void generateCodeThatZeroJumpCounterIdVariable(
117                        MethodVisitor nextMethodVisitor, int lastJumpIdVariableIndex);
118
119        /**
120         * Injects code that behaves the same as such a code snippet:  
121         * <pre>
122         * if (value('lastJumpIdVariableIndex')==neededJumpCounterIdVariableValue){
123         *       cobertura_counters.increment(counterIdToIncrement);
124         * }
125         * </pre>
126         * 
127         * This snippet is used in switch case of switch statement. We have a label and we want to ensure that
128         * we are executing the label in effect of switch statement-jump, and not other JUMP or fall-throught.  
129         */
130        public abstract void generateCodeThatIncrementsCoberturaCounterIfVariableEqualsAndCleanVariable(
131                        MethodVisitor nextMethodVisitor,
132                        Integer neededJumpCounterIdVariableValue,
133                        Integer counterIdToIncrement, int lastJumpIdVariableIndex,
134                        String className);
135
136        /**
137         * The version of cobertura prior to 1.10 used *.ser file to store information of lines, jumps, switches and other
138         * constructions used in the class. It was difficult to user to transfer the files after instrumentation into 
139         * 'production' directory. To avoid that we are now creating the class-map as a special injected method that is responsible
140         * for keeping such a informations.     
141         * 
142         * @param cv - listener used to inject the code
143         * @param classMap - structure that is keeping all collected information about the class. The information from the structure will be stored as
144         *                                       method body. 
145         */
146        public void generateCoberturaClassMapMethod(ClassVisitor cv, ClassMap classMap);
147
148        /**
149         * Generate method {@value #COBERTURA_GET_AND_RESET_COUNTERS_METHOD_NAME} that is accessor to couters. 
150         * Signature of this method is: static int __cobertura_counter(int counterId); 
151         * 
152         * @param cv - listener used to inject the code
153         */
154        public abstract void generateCoberturaGetAndResetCountersMethod(ClassVisitor cv, String className);
155                 
156        public void generateCoberturaInitMethod(ClassVisitor cv,  String className, int countersCnt);
157
158        public abstract void generateCallCoberturaInitMethod(MethodVisitor mv,
159                        String className);
160}