KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > LineNumberMap


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba;
21
22 import java.util.IdentityHashMap JavaDoc;
23
24 import org.apache.bcel.classfile.LineNumber;
25 import org.apache.bcel.classfile.LineNumberTable;
26 import org.apache.bcel.generic.InstructionHandle;
27 import org.apache.bcel.generic.MethodGen;
28
29 import edu.umd.cs.findbugs.SystemProperties;
30
31 /**
32  * Summarize line numbers (and other source information)
33  * for a method.
34  */

35 public class LineNumberMap {
36     /**
37      * Set this property to true to get debug print statements.
38      */

39     private static final boolean DEBUG = SystemProperties.getBoolean("lnm.debug");
40
41     /**
42      * When this is true, the workaround for the bug in BCEL 5.0's
43      * LineNumberTable class is disabled.
44      */

45     private static final boolean LINE_NUMBER_BUG = SystemProperties.getBoolean("lineNumberBug");
46
47     private MethodGen methodGen;
48     private IdentityHashMap JavaDoc<InstructionHandle, LineNumber> lineNumberMap;
49     private boolean hasLineNumbers;
50
51     /**
52      * Constructor.
53      *
54      * @param methodGen the method to summarize line numbers for
55      */

56     public LineNumberMap(MethodGen methodGen) {
57         this.methodGen = methodGen;
58         lineNumberMap = new IdentityHashMap JavaDoc<InstructionHandle, LineNumber>();
59         hasLineNumbers = false;
60     }
61
62     /**
63      * Build the line number information.
64      * Should be called before any other methods.
65      */

66     public void build() {
67         int numGood = 0, numBytecodes = 0;
68
69         if (DEBUG) {
70             System.out.println("Method: " + methodGen.getName() + " - " + methodGen.getSignature() +
71                     "in class " + methodGen.getClassName());
72         }
73
74         // Associate line number information with each InstructionHandle
75
LineNumberTable table = methodGen.getLineNumberTable(methodGen.getConstantPool());
76
77         if (table != null && table.getTableLength() > 0) {
78             checkTable(table);
79             InstructionHandle handle = methodGen.getInstructionList().getStart();
80             while (handle != null) {
81                 int bytecodeOffset = handle.getPosition();
82                 if (bytecodeOffset < 0)
83                     throw new IllegalStateException JavaDoc("Bad bytecode offset: " + bytecodeOffset);
84                 if (DEBUG) System.out.println("Looking for source line for bytecode offset " + bytecodeOffset);
85                 int sourceLine;
86                 try {
87                     sourceLine = table.getSourceLine(bytecodeOffset);
88                 } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
89                     if (LINE_NUMBER_BUG)
90                         throw e;
91                     else
92                         sourceLine = -1;
93                 }
94                 if (sourceLine >= 0)
95                     ++numGood;
96                 lineNumberMap.put(handle,
97                         new LineNumber(bytecodeOffset, sourceLine));
98                 handle = handle.getNext();
99                 ++numBytecodes;
100             }
101             hasLineNumbers = true;
102
103             if (DEBUG) System.out.println("\t" + numGood + "/" + numBytecodes + " had valid line numbers");
104         }
105     }
106
107     private void checkTable(LineNumberTable table) {
108         if (DEBUG) System.out.println("line number table has length " + table.getTableLength());
109         LineNumber[] entries = table.getLineNumberTable();
110         int lastBytecode = -1;
111         for (int i = 0; i < entries.length; ++i) {
112             LineNumber ln = entries[i];
113             if (DEBUG) System.out.println("Entry " + i + ": pc=" + ln.getStartPC() + ", line=" + ln.getLineNumber());
114             int pc = ln.getStartPC();
115             if (pc <= lastBytecode) throw new IllegalStateException JavaDoc("LineNumberTable is not sorted");
116         }
117     }
118
119     /**
120      * Does this method have line number information?
121      */

122     public boolean hasLineNumbers() {
123         return hasLineNumbers;
124     }
125
126     /**
127      * Find the line number information for instruction whose
128      * handle is given.
129      *
130      * @param handle the InstructionHandle
131      * @return the LineNumber object containing bytecode offset and source line number
132      */

133     public LineNumber lookupLineNumber(InstructionHandle handle) {
134         return lineNumberMap.get(handle);
135     }
136 }
137
Popular Tags