1 26 27 package net.sourceforge.groboutils.codecoverage.v2.module; 28 29 30 import java.util.Arrays ; 31 import java.util.Comparator ; 32 33 import net.sourceforge.groboutils.codecoverage.v2.IAnalysisMetaData; 34 import net.sourceforge.groboutils.codecoverage.v2.IMethodCode; 35 36 import org.apache.bcel.classfile.LineNumber; 37 import org.apache.bcel.classfile.LineNumberTable; 38 import org.apache.bcel.classfile.Method; 39 import org.apache.bcel.generic.InstructionHandle; 40 import org.apache.bcel.generic.InstructionList; 41 42 43 52 public class BytecodeLineUtil 53 { 54 private int[] instructionPos; private int[] instructionLine; private InstructionHandle[] handles; 57 58 private static final LineNumberComparator LINENUMBER_COMPARATOR = 59 new LineNumberComparator(); 60 61 66 private static class LineNumberComparator implements Comparator 67 { 68 76 public int compare(Object o1, Object o2) 77 { 78 return ((LineNumber) o1).getStartPC() - 79 ((LineNumber) o2).getStartPC(); 80 } 81 82 83 90 public boolean equals(Object o) 91 { 92 return (o != null) ? (this.getClass() == o.getClass()) : false; 93 } 94 } 95 96 97 100 public BytecodeLineUtil( Method m ) 101 { 102 if (m == null) 103 { 104 throw new IllegalArgumentException ("no null args."); 105 } 106 initialize( m ); 107 } 108 109 110 public BytecodeLineUtil( IMethodCode m ) 111 { 112 if (m == null) 113 { 114 throw new IllegalArgumentException ("no null args."); 115 } 116 initialize( m.getOriginalMethod() ); 117 } 118 119 120 public InstructionHandle[] getHandles() 121 { 122 return this.handles; 123 } 124 125 126 public int getLineNumber( InstructionHandle ih ) 127 { 128 if (ih == null) 129 { 130 throw new IllegalArgumentException ("no null args."); 131 } 132 return getLineNumberForBytecodePos( ih.getPosition() ); 133 } 134 135 136 public int getLineNumberForBytecodePos( int bytecodePos ) 137 { 138 int instrPos = getInstructionPosForBytecodePos( bytecodePos ); 139 return getLineNumberForInstructionPos( instrPos ); 140 } 141 142 143 public int getLineNumberForInstructionPos( int instrPos ) 144 { 145 if (instrPos >= 0 && instrPos < this.instructionLine.length) 146 { 147 return this.instructionLine[ instrPos ]; 148 } 149 return -1; 151 } 152 153 154 public int getInstructionPosForBytecodePos( int bytecodePos ) 155 { 156 159 int len = this.instructionPos.length; 160 if (len == 0) 161 { 162 return 0; 163 } 164 for (int i = 0; i < len; ++i) 165 { 166 if (this.instructionPos[i] == bytecodePos) 167 { 168 return i; 169 } 170 } 171 if (len >= 1 && this.instructionPos[ len - 1 ] < bytecodePos ) 172 { 173 return len; 174 } 175 176 throw new IllegalStateException ( "Unknown bytecode position "+ 177 bytecodePos ); 178 } 179 180 181 182 183 185 186 protected void initialize( Method m ) 187 { 188 if (m == null) 189 { 190 throw new IllegalArgumentException ("no null args."); 191 } 192 LineNumberTable lnt = m.getLineNumberTable(); 193 LineNumber[] lines = sort( lnt ); 194 this.instructionPos = getInstructionPositions( m ); 195 this.instructionLine = getInstructionLines( lines, 196 this.instructionPos ); 197 } 198 199 200 private LineNumber[] sort( LineNumberTable lnt ) 201 { 202 if (lnt == null) 203 { 204 return new LineNumber[0]; 205 } 206 LineNumber[] lines = lnt.getLineNumberTable(); 207 if (lines == null) 208 { 209 return new LineNumber[0]; 210 } 211 212 Arrays.sort( lines, LINENUMBER_COMPARATOR ); 213 return lines; 214 } 215 216 217 private int[] getInstructionPositions( Method m ) 218 { 219 InstructionList il = new InstructionList( m.getCode().getCode() ); 220 il.setPositions(); 221 this.handles = il.getInstructionHandles(); 222 223 int instructionCount = handles.length; 224 int instructionPos[] = new int[ instructionCount ]; 225 226 for (int i = 0; i < instructionCount; ++i) 228 { 229 instructionPos[i] = this.handles[i].getPosition(); 230 } 231 return instructionPos; 232 } 233 234 235 private int[] getInstructionLines( LineNumber lines[], int bytePos[] ) 236 { 237 int out[] = new int[ bytePos.length ]; 238 for (int bIndex = 0; bIndex < bytePos.length; ++bIndex) 239 { 240 out[bIndex] = getLinenoForBytePos( lines, bytePos[ bIndex ] ); 241 } 242 return out; 243 } 244 245 246 private int getLinenoForBytePos( LineNumber lines[], int bytePos ) 247 { 248 if (lines.length <= 0) 249 { 250 return -1; 251 } 252 253 for (int i = 1; i < lines.length; ++i) 254 { 255 if (bytePos < lines[ i ].getStartPC()) 256 { 257 return lines[i - 1].getLineNumber(); 258 } 259 } 260 return lines[ lines.length - 1 ].getLineNumber(); 261 } 262 } 263 264 | Popular Tags |