add utility to extract LineNumbers from bytecode
git-svn-id: https://google-guice.googlecode.com/svn/trunk@129 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/build.xml b/build.xml
index d295206..47a7df2 100644
--- a/build.xml
+++ b/build.xml
@@ -30,7 +30,9 @@
<jarjar jarfile="${build.dir}/dist/guice-${version}.jar">
<fileset dir="${build.dir}/classes"/>
<zipfileset src="lib/build/cglib-nodep-2.2_beta1.jar"/>
+ <zipfileset src="lib/build/asm-3.0.jar"/>
<rule pattern="net.sf.cglib.**" result="com.google.inject.cglib.@1"/>
+ <rule pattern="org.objectweb.asm.**" result="com.google.inject.asm.@1"/>
</jarjar>
</target>
diff --git a/lib/build/asm-3.0.jar b/lib/build/asm-3.0.jar
new file mode 100644
index 0000000..112f5bd
--- /dev/null
+++ b/lib/build/asm-3.0.jar
Binary files differ
diff --git a/src/com/google/inject/util/LineNumbers.java b/src/com/google/inject/util/LineNumbers.java
new file mode 100644
index 0000000..3188586
--- /dev/null
+++ b/src/com/google/inject/util/LineNumbers.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2006 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.*;
+import java.util.HashMap;
+import java.util.Map;
+import org.objectweb.asm.*;
+import org.objectweb.asm.Type;
+
+public class LineNumbers
+{
+ private final Class cls;
+ private Map<String,Integer> lines = new HashMap<String,Integer>();
+ private String source;
+
+ /**
+ * Reads line number information from the given class, if available.
+ */
+ public LineNumbers(Class cls) throws IOException {
+ this.cls = cls;
+ InputStream in = cls.getResourceAsStream("/" + cls.getName().replace('.', '/') + ".class");
+ new ClassReader(in).accept(new LineNumberReader(), 0);
+ }
+
+ /**
+ * Get the source file name as read from the bytecode.
+ * @return the source file name if available, or null
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * Get the line number associated with the given member.
+ * @param member a field, constructor, or method belonging to the class used during construction
+ * @return the wrapped line number, or null if not available
+ * @throws IllegalArgumentException if the member does not belong to the class used during construction
+ */
+ public Integer getLineNumber(Member member) {
+ if (!cls.equals(member.getDeclaringClass()))
+ throw new IllegalArgumentException("Member " + member + " belongs to " + member.getDeclaringClass() + ", not " + cls);
+ return lines.get(getKey(member));
+ }
+
+ private static String getKey(Member member) {
+ if (member instanceof Field) {
+ return member.getName();
+ } else if (member instanceof Method) {
+ return member.getName() + Type.getMethodDescriptor((Method)member);
+ } else {
+ return "<init>" + Type.getConstructorDescriptor((Constructor)member);
+ }
+ }
+
+ private class LineNumberReader implements ClassVisitor, MethodVisitor
+ {
+ private int line = -1;
+ private String pendingMethod;
+ private String name;
+ private boolean inStatic;
+
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ this.name = name;
+ }
+
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ if ((access & Opcodes.ACC_PRIVATE) != 0)
+ return null;
+ inStatic = (access & Opcodes.ACC_STATIC) != 0;
+ pendingMethod = name + desc;
+ line = -1;
+ return this;
+ }
+
+ public void visitSource(String source, String debug) {
+ LineNumbers.this.source = source;
+ }
+
+ public void visitLineNumber(int line, Label start) {
+ this.line = line;
+ if (pendingMethod != null) {
+ lines.put(pendingMethod, line);
+ pendingMethod = null;
+ }
+ }
+
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ if (opcode == Opcodes.PUTFIELD && this.name.equals(owner) && !lines.containsKey(name) && line != -1)
+ lines.put(name, line);
+ }
+
+ public void visitEnd() { }
+ public void visitInnerClass(String name, String outerName, String innerName, int access) { }
+ public void visitOuterClass(String owner, String name, String desc) { }
+ public void visitAttribute(Attribute attr) { }
+
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { return null; }
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return null; }
+ public AnnotationVisitor visitAnnotationDefault() { return null; }
+ public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { return null; }
+
+ public void visitCode() { }
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { }
+ public void visitIincInsn(int var, int increment) { }
+ public void visitInsn(int opcode) { }
+ public void visitIntInsn(int opcode, int operand) { }
+ public void visitJumpInsn(int opcode, Label label) { }
+ public void visitLabel(Label label) { }
+ public void visitLdcInsn(Object cst) { }
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { }
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { }
+ public void visitMaxs(int maxStack, int maxLocals) { }
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) { }
+ public void visitMultiANewArrayInsn(String desc, int dims) { }
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { }
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { }
+ public void visitTypeInsn(int opcode, String desc) { }
+ public void visitVarInsn(int opcode, int var) { }
+ }
+}