blob: 05d1c29af16a39196f8be7e9d375512e97129df1 [file] [log] [blame]
chris.nokleberg5db87c62007-02-13 21:16:24 +00001/**
2 * Copyright (C) 2006 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
kevinb9ncad2c2b2007-05-15 17:28:03 +000017package com.google.inject.internal;
chris.nokleberg5db87c62007-02-13 21:16:24 +000018
limpbizkit53664a72009-02-21 00:25:27 +000019import static com.google.inject.internal.Preconditions.checkArgument;
chris.nokleberg5db87c62007-02-13 21:16:24 +000020import java.io.IOException;
21import java.io.InputStream;
kevinb9n2394ca62007-04-20 14:33:40 +000022import java.lang.reflect.Member;
chris.nokleberg5db87c62007-02-13 21:16:24 +000023import java.util.Map;
kevinb9n2394ca62007-04-20 14:33:40 +000024import org.objectweb.asm.AnnotationVisitor;
25import org.objectweb.asm.Attribute;
26import org.objectweb.asm.ClassReader;
27import org.objectweb.asm.ClassVisitor;
28import org.objectweb.asm.FieldVisitor;
29import org.objectweb.asm.Label;
30import org.objectweb.asm.MethodVisitor;
31import org.objectweb.asm.Opcodes;
chris.nokleberg5db87c62007-02-13 21:16:24 +000032
crazyboblee71733532007-02-14 02:35:21 +000033/**
34 * Looks up line numbers for classes and their members.
35 *
36 * @author Chris Nokleberg
37 */
limpbizkit5ae41eb2009-06-06 17:51:27 +000038final class LineNumbers {
chris.nokleberg5db87c62007-02-13 21:16:24 +000039
limpbizkit564053f2008-06-15 11:21:18 +000040 private final Class type;
41 private final Map<String, Integer> lines = Maps.newHashMap();
crazyboblee71733532007-02-14 02:35:21 +000042 private String source;
crazyboblee0f09fe32007-02-23 23:43:57 +000043 private int firstLine = Integer.MAX_VALUE;
crazyboblee71733532007-02-14 02:35:21 +000044
45 /**
46 * Reads line number information from the given class, if available.
47 *
limpbizkit564053f2008-06-15 11:21:18 +000048 * @param type the class to read line number information from
49 * @throws IllegalArgumentException if the bytecode for the class cannot be found
50 * @throws java.io.IOException if an error occurs while reading bytecode
crazyboblee71733532007-02-14 02:35:21 +000051 */
limpbizkit564053f2008-06-15 11:21:18 +000052 public LineNumbers(Class type) throws IOException {
53 this.type = type;
limpbizkit2c2c6102008-06-20 13:34:36 +000054
55 if (!type.isArray()) {
56 InputStream in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class");
57 checkArgument(in != null, "Cannot find bytecode for %s", type);
58 new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
59 }
crazyboblee71733532007-02-14 02:35:21 +000060 }
61
62 /**
63 * Get the source file name as read from the bytecode.
64 *
65 * @return the source file name if available, or null
66 */
67 public String getSource() {
68 return source;
69 }
70
71 /**
72 * Get the line number associated with the given member.
73 *
limpbizkit564053f2008-06-15 11:21:18 +000074 * @param member a field, constructor, or method belonging to the class used during construction
crazyboblee71733532007-02-14 02:35:21 +000075 * @return the wrapped line number, or null if not available
limpbizkit564053f2008-06-15 11:21:18 +000076 * @throws IllegalArgumentException if the member does not belong to the class used during
77 * construction
crazyboblee71733532007-02-14 02:35:21 +000078 */
79 public Integer getLineNumber(Member member) {
limpbizkit564053f2008-06-15 11:21:18 +000080 checkArgument(type == member.getDeclaringClass(),
81 "Member %s belongs to %s, not %s", member, member.getDeclaringClass(), type);
82 return lines.get(MoreTypes.memberKey(member));
crazyboblee71733532007-02-14 02:35:21 +000083 }
84
limpbizkit564053f2008-06-15 11:21:18 +000085 /** Gets the first line number. */
crazybobleededcabd2007-02-20 03:59:14 +000086 public int getFirstLine() {
crazyboblee0f09fe32007-02-23 23:43:57 +000087 return firstLine == Integer.MAX_VALUE ? 1 : firstLine;
crazybobleededcabd2007-02-20 03:59:14 +000088 }
89
chris.nokleberg409df522007-03-20 04:39:42 +000090 private class LineNumberReader implements ClassVisitor, MethodVisitor, AnnotationVisitor {
crazyboblee71733532007-02-14 02:35:21 +000091
92 private int line = -1;
93 private String pendingMethod;
94 private String name;
95
96 public void visit(int version, int access, String name, String signature,
97 String superName, String[] interfaces) {
98 this.name = name;
chris.nokleberg5db87c62007-02-13 21:16:24 +000099 }
100
crazyboblee71733532007-02-14 02:35:21 +0000101 public MethodVisitor visitMethod(int access, String name, String desc,
102 String signature, String[] exceptions) {
103 if ((access & Opcodes.ACC_PRIVATE) != 0) {
104 return null;
105 }
106 pendingMethod = name + desc;
107 line = -1;
108 return this;
chris.nokleberg5db87c62007-02-13 21:16:24 +0000109 }
110
crazyboblee71733532007-02-14 02:35:21 +0000111 public void visitSource(String source, String debug) {
112 LineNumbers.this.source = source;
chris.nokleberg5db87c62007-02-13 21:16:24 +0000113 }
114
crazyboblee71733532007-02-14 02:35:21 +0000115 public void visitLineNumber(int line, Label start) {
crazyboblee0f09fe32007-02-23 23:43:57 +0000116 if (line < firstLine) {
crazybobleededcabd2007-02-20 03:59:14 +0000117 firstLine = line;
118 }
119
crazyboblee71733532007-02-14 02:35:21 +0000120 this.line = line;
121 if (pendingMethod != null) {
122 lines.put(pendingMethod, line);
123 pendingMethod = null;
124 }
chris.nokleberg5db87c62007-02-13 21:16:24 +0000125 }
126
crazyboblee71733532007-02-14 02:35:21 +0000127 public void visitFieldInsn(int opcode, String owner, String name,
128 String desc) {
129 if (opcode == Opcodes.PUTFIELD && this.name.equals(owner)
130 && !lines.containsKey(name) && line != -1) {
131 lines.put(name, line);
132 }
chris.nokleberg5db87c62007-02-13 21:16:24 +0000133 }
crazyboblee71733532007-02-14 02:35:21 +0000134
135 public void visitEnd() {
136 }
137
138 public void visitInnerClass(String name, String outerName, String innerName,
139 int access) {
140 }
141
142 public void visitOuterClass(String owner, String name, String desc) {
143 }
144
145 public void visitAttribute(Attribute attr) {
146 }
147
148 public FieldVisitor visitField(int access, String name, String desc,
149 String signature, Object value) {
150 return null;
151 }
152
153 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
chris.nokleberg409df522007-03-20 04:39:42 +0000154 return this;
155 }
156
157 public AnnotationVisitor visitAnnotation(String name, String desc) {
158 return this;
crazyboblee71733532007-02-14 02:35:21 +0000159 }
160
161 public AnnotationVisitor visitAnnotationDefault() {
chris.nokleberg409df522007-03-20 04:39:42 +0000162 return this;
crazyboblee71733532007-02-14 02:35:21 +0000163 }
164
165 public AnnotationVisitor visitParameterAnnotation(int parameter,
166 String desc, boolean visible) {
chris.nokleberg409df522007-03-20 04:39:42 +0000167 return this;
168 }
169
170 public AnnotationVisitor visitArray(String name) {
171 return this;
172 }
173
174 public void visitEnum(String name, String desc, String value) {
175 }
176
177 public void visit(String name, Object value) {
crazyboblee71733532007-02-14 02:35:21 +0000178 }
179
180 public void visitCode() {
181 }
182
183 public void visitFrame(int type, int nLocal, Object[] local, int nStack,
184 Object[] stack) {
185 }
186
187 public void visitIincInsn(int var, int increment) {
188 }
189
190 public void visitInsn(int opcode) {
191 }
192
193 public void visitIntInsn(int opcode, int operand) {
194 }
195
196 public void visitJumpInsn(int opcode, Label label) {
197 }
198
199 public void visitLabel(Label label) {
200 }
201
202 public void visitLdcInsn(Object cst) {
203 }
204
205 public void visitLocalVariable(String name, String desc, String signature,
206 Label start, Label end, int index) {
207 }
208
209 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
210 }
211
212 public void visitMaxs(int maxStack, int maxLocals) {
213 }
214
215 public void visitMethodInsn(int opcode, String owner, String name,
216 String desc) {
217 }
218
219 public void visitMultiANewArrayInsn(String desc, int dims) {
220 }
221
222 public void visitTableSwitchInsn(int min, int max, Label dflt,
223 Label[] labels) {
224 }
225
226 public void visitTryCatchBlock(Label start, Label end, Label handler,
227 String type) {
228 }
229
230 public void visitTypeInsn(int opcode, String desc) {
231 }
232
233 public void visitVarInsn(int opcode, int var) {
234 }
235 }
chris.nokleberg5db87c62007-02-13 21:16:24 +0000236}