001 /*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2005 Mark Doliner <thekingant@users.sourceforge.net>
005 *
006 * Cobertura is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published
008 * by the Free Software Foundation; either version 2 of the License,
009 * or (at your option) any later version.
010 *
011 * Cobertura is distributed in the hope that it will be useful, but
012 * WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with Cobertura; if not, write to the Free Software
018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019 * USA
020 */
021
022 package net.sourceforge.cobertura.coverage;
023
024 import java.util.regex.Pattern;
025
026 import org.objectweb.asm.Label;
027 import org.objectweb.asm.MethodAdapter;
028 import org.objectweb.asm.MethodVisitor;
029 import org.objectweb.asm.Opcodes;
030
031 /*
032 * TODO: If class is abstract then do not count the "public abstract class bleh" line as a SLOC.
033 * TODO: For branches, only count the branch as covered if both paths are accessed?
034 */
035 public class MethodInstrumenter extends MethodAdapter implements Opcodes
036 {
037 private final String ownerClass;
038 private String myName;
039 private String myDescriptor;
040 private Pattern ignoreRegexp;
041 private CoverageData coverageData;
042
043 private int currentLine = 0;
044
045 public MethodInstrumenter(final MethodVisitor mv,
046 CoverageData coverageData, final String owner,
047 final String myName, final String myDescriptor,
048 final Pattern ignoreRegexp)
049 {
050 super(mv);
051 this.coverageData = coverageData;
052 this.ownerClass = owner;
053 this.myName = myName;
054 this.myDescriptor = myDescriptor;
055 this.ignoreRegexp = ignoreRegexp;
056 }
057
058 public void visitJumpInsn(int opcode, Label label)
059 {
060 super.visitJumpInsn(opcode, label);
061
062 // Ignore any jump instructions in the "class init" method.
063 // When initializing static variables, the JVM first checks
064 // that the variable is null before attempting to set it.
065 // This check contains an IFNONNULL jump instruction which
066 // would confuse people if it showed up in the reports.
067 if ((opcode != GOTO) && (currentLine != 0)
068 && (!this.myName.equals("<clinit>")))
069 coverageData.markLineAsConditional(currentLine);
070 }
071
072 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels)
073 {
074 super.visitLookupSwitchInsn(dflt, keys, labels);
075 if (currentLine != 0)
076 coverageData.markLineAsConditional(currentLine);
077 }
078
079 public void visitLineNumber(int line, Label start)
080 {
081 // Record initial information about this line of code
082 currentLine = line;
083 coverageData.addLine(currentLine, myName, myDescriptor);
084
085 // Get an instance of CoverageDataFactory
086 mv.visitMethodInsn(INVOKESTATIC,
087 "net/sourceforge/cobertura/coverage/CoverageDataFactory",
088 "getInstance",
089 "()Lnet/sourceforge/cobertura/coverage/CoverageDataFactory;");
090
091 // Get the CoverageData object for this class
092 mv.visitLdcInsn(ownerClass);
093 mv
094 .visitMethodInsn(
095 INVOKEVIRTUAL,
096 "net/sourceforge/cobertura/coverage/CoverageDataFactory",
097 "newInstrumentation",
098 "(Ljava/lang/String;)Lnet/sourceforge/cobertura/coverage/CoverageData;");
099
100 // Call "coverageData.touch(line);"
101 mv.visitIntInsn(SIPUSH, line);
102 mv.visitMethodInsn(INVOKEVIRTUAL,
103 "net/sourceforge/cobertura/coverage/CoverageData", "touch",
104 "(I)V");
105
106 super.visitLineNumber(line, start);
107 }
108
109 public void visitMethodInsn(int opcode, String owner, String name,
110 String desc)
111 {
112 super.visitMethodInsn(opcode, owner, name, desc);
113
114 if ((ignoreRegexp != null) && (ignoreRegexp.matcher(owner).matches()))
115 coverageData.removeLine(currentLine);
116 }
117
118 }