Coverage Report - net.sourceforge.cobertura.instrument.FirstPassMethodInstrumenter
 
Classes in this File Line Coverage Branch Coverage Complexity
FirstPassMethodInstrumenter
100%
58/58
75%
15/20
1.353
 
 1  
 /*
 2  
  * Cobertura - http://cobertura.sourceforge.net/
 3  
  *
 4  
  * Copyright (C) 2005 Mark Doliner
 5  
  * Copyright (C) 2006 Jiri Mares
 6  
  *
 7  
  * Cobertura is free software; you can redistribute it and/or modify
 8  
  * it under the terms of the GNU General Public License as published
 9  
  * by the Free Software Foundation; either version 2 of the License,
 10  
  * or (at your option) any later version.
 11  
  *
 12  
  * Cobertura is distributed in the hope that it will be useful, but
 13  
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15  
  * General Public License for more details.
 16  
  *
 17  
  * You should have received a copy of the GNU General Public License
 18  
  * along with Cobertura; if not, write to the Free Software
 19  
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 20  
  * USA
 21  
  */
 22  
 
 23  
 package net.sourceforge.cobertura.instrument;
 24  
 
 25  
 import java.util.Collection;
 26  
 import java.util.HashMap;
 27  
 import java.util.Map;
 28  
 
 29  
 import net.sourceforge.cobertura.coveragedata.ClassData;
 30  
 import net.sourceforge.cobertura.util.RegexUtil;
 31  
 
 32  
 import org.objectweb.asm.Label;
 33  
 import org.objectweb.asm.MethodAdapter;
 34  
 import org.objectweb.asm.MethodVisitor;
 35  
 import org.objectweb.asm.Opcodes;
 36  
 import org.objectweb.asm.tree.MethodNode;
 37  
 
 38  
 public class FirstPassMethodInstrumenter extends MethodAdapter implements Opcodes
 39  
 {
 40  
 
 41  
         private final String ownerClass;
 42  
 
 43  
         private String myName;
 44  
 
 45  
         private String myDescriptor;
 46  
 
 47  
         private int myAccess;
 48  
    
 49  
         private Collection ignoreRegexs;
 50  
    
 51  
         private Collection ignoreBranchesRegexs;
 52  
 
 53  
         private ClassData classData;
 54  
 
 55  
         private int currentLine;
 56  
    
 57  
         private int currentJump;
 58  
    
 59  
         private int currentSwitch;
 60  
         
 61  
         private Map jumpTargetLabels;
 62  
 
 63  
         private Map switchTargetLabels;
 64  
    
 65  
         private Map lineLabels;
 66  
    
 67  
         private MethodVisitor writerMethodVisitor;
 68  
    
 69  
         private MethodNode methodNode;
 70  
 
 71  
         public FirstPassMethodInstrumenter(ClassData classData, final MethodVisitor mv,
 72  
                         final String owner, final int access, final String name, final String desc, 
 73  
                         final String signature, final String[] exceptions, final Collection ignoreRegexs,
 74  
                         final Collection ignoreBranchesRegexs)
 75  
         {
 76  38
                 super(new MethodNode(access, name, desc, signature, exceptions));
 77  38
                 writerMethodVisitor = mv;
 78  38
                 this.ownerClass = owner;
 79  38
                 this.methodNode = (MethodNode) this.mv;
 80  38
                 this.classData = classData;
 81  38
                 this.myAccess = access;
 82  38
                 this.myName = name;
 83  38
                 this.myDescriptor = desc;
 84  38
                 this.ignoreRegexs = ignoreRegexs;
 85  38
                 this.ignoreBranchesRegexs = ignoreBranchesRegexs;
 86  38
                 this.jumpTargetLabels = new HashMap();
 87  38
                 this.switchTargetLabels = new HashMap();
 88  38
                 this.lineLabels = new HashMap();
 89  38
                 this.currentLine = 0;
 90  38
         }
 91  
 
 92  
         public void visitEnd() {
 93  38
                 super.visitEnd();
 94  
 
 95  38
                 methodNode.accept(lineLabels.isEmpty() ? writerMethodVisitor : new SecondPassMethodInstrumenter(this)); //when there is no line number info -> no instrumentation
 96  38
         }
 97  
 
 98  
         public void visitJumpInsn(int opcode, Label label)
 99  
         {
 100  
                 // Ignore any jump instructions in the "class init" method.
 101  
                 // When initializing static variables, the JVM first checks
 102  
                 // that the variable is null before attempting to set it.
 103  
                 // This check contains an IFNONNULL jump instruction which
 104  
                 // would confuse people if it showed up in the reports.
 105  11
                 if ((opcode != GOTO) && (opcode != JSR) && (currentLine != 0)
 106  
                                 && (!this.myName.equals("<clinit>")))
 107  
                 {
 108  7
                         classData.addLineJump(currentLine, currentJump);
 109  7
                         jumpTargetLabels.put(label, new JumpHolder(currentLine, currentJump++));
 110  
                 }
 111  
                 
 112  11
                 super.visitJumpInsn(opcode, label);
 113  11
         }
 114  
 
 115  
         public void visitLineNumber(int line, Label start)
 116  
         {
 117  
                 // Record initial information about this line of code
 118  108
                 currentLine = line;
 119  108
                 classData.addLine(currentLine, myName, myDescriptor);
 120  108
                 currentJump = 0;
 121  108
                 currentSwitch = 0;
 122  
       
 123  108
                 lineLabels.put(start, new Integer(line));
 124  
 
 125  
                 //removed because the MethodNode doesn't reproduce visitLineNumber where they are but at the end of the file :-(( 
 126  
                 //therefore we don't need them
 127  
                 //We can directly instrument the visit line number here, but it is better to leave all instrumentation in the second pass
 128  
                 //therefore we just collects what label is the line ...
 129  
                 //super.visitLineNumber(line, start);
 130  108
         }
 131  
 
 132  
         public void visitMethodInsn(int opcode, String owner, String name,
 133  
                         String desc)
 134  
         {
 135  41
                 super.visitMethodInsn(opcode, owner, name, desc);
 136  
 
 137  
                 // If any of the ignore patterns match this line
 138  
                 // then remove it from our data
 139  41
                 if (RegexUtil.matches(ignoreRegexs, owner)) 
 140  
                 {
 141  2
                         classData.removeLine(currentLine);
 142  
                 }
 143  41
         }
 144  
 
 145  
         public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels)
 146  
         {
 147  1
                 super.visitLookupSwitchInsn(dflt, keys, labels);
 148  
       
 149  1
                 if (currentLine != 0)
 150  
                 {
 151  1
                         switchTargetLabels.put(dflt, new SwitchHolder(currentLine, currentSwitch, -1)); 
 152  3
                         for (int i = labels.length -1; i >=0; i--)
 153  2
                                 switchTargetLabels.put(labels[i], new SwitchHolder(currentLine, currentSwitch, i));
 154  1
                         classData.addLineSwitch(currentLine, currentSwitch++, keys);
 155  
                 }
 156  1
         }
 157  
 
 158  
         public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels)
 159  
         {
 160  1
                 super.visitTableSwitchInsn(min, max, dflt, labels);
 161  
       
 162  1
                 if (currentLine != 0)
 163  
                 {
 164  1
                         switchTargetLabels.put(dflt, new SwitchHolder(currentLine, currentSwitch, -1)); 
 165  10
                         for (int i = labels.length -1; i >=0; i--)
 166  9
                                 switchTargetLabels.put(labels[i], new SwitchHolder(currentLine, currentSwitch, i));
 167  1
                         classData.addLineSwitch(currentLine, currentSwitch++, min, max);
 168  
                 }
 169  1
         }
 170  
 
 171  
         protected void removeLine(int lineNumber) 
 172  
         {
 173  2
                 classData.removeLine(lineNumber);
 174  2
         }
 175  
    
 176  
         protected MethodVisitor getWriterMethodVisitor() 
 177  
         {
 178  35
                 return writerMethodVisitor;
 179  
         }
 180  
 
 181  
         protected Collection getIgnoreRegexs() 
 182  
         {
 183  38
                 return ignoreRegexs;
 184  
         }
 185  
 
 186  
         protected Map getJumpTargetLabels() 
 187  
         {
 188  146
                 return jumpTargetLabels;
 189  
         }
 190  
 
 191  
         protected Map getSwitchTargetLabels() 
 192  
         {
 193  146
                 return switchTargetLabels;
 194  
         }
 195  
 
 196  
         protected int getMyAccess() 
 197  
         {
 198  35
                 return myAccess;
 199  
         }
 200  
 
 201  
         protected String getMyDescriptor() 
 202  
         {
 203  35
                 return myDescriptor;
 204  
         }
 205  
 
 206  
         protected String getMyName() 
 207  
         {
 208  7
                 return myName;
 209  
         }
 210  
 
 211  
         protected String getOwnerClass() 
 212  
         {
 213  135
                 return ownerClass;
 214  
         }
 215  
 
 216  
         protected Map getLineLabels() 
 217  
         {
 218  146
                 return lineLabels;
 219  
         }
 220  
 
 221  
 }