| /* |
| * Copyright 2009 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.gwt.dev.javac.asm; |
| |
| import com.google.gwt.dev.javac.asmbridge.EmptyVisitor; |
| |
| import org.objectweb.asm.AnnotationVisitor; |
| import org.objectweb.asm.FieldVisitor; |
| import org.objectweb.asm.MethodVisitor; |
| import org.objectweb.asm.Opcodes; |
| import org.objectweb.asm.Type; |
| import org.objectweb.asm.signature.SignatureReader; |
| import org.objectweb.asm.signature.SignatureVisitor; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * Collect all the types which are referenced by a particular class. |
| */ |
| public class CollectReferencesVisitor extends EmptyVisitor { |
| |
| /** |
| * Collect type names from generic signatures. |
| * |
| * All we care about is picking up type names, so we just return ourselves for |
| * nested visitors. |
| */ |
| private class CollectGenericTypes extends SignatureVisitor { |
| |
| public CollectGenericTypes() { |
| super(Opcodes.ASM7); |
| } |
| |
| @Override |
| public SignatureVisitor visitArrayType() { |
| return this; |
| } |
| |
| @Override |
| public void visitBaseType(char descriptor) { |
| } |
| |
| @Override |
| public SignatureVisitor visitClassBound() { |
| return this; |
| } |
| |
| @Override |
| public void visitClassType(String name) { |
| referencedTypes.add(name); |
| } |
| |
| @Override |
| public void visitEnd() { |
| } |
| |
| @Override |
| public SignatureVisitor visitExceptionType() { |
| return this; |
| } |
| |
| @Override |
| public void visitFormalTypeParameter(String name) { |
| } |
| |
| @Override |
| public void visitInnerClassType(String name) { |
| } |
| |
| @Override |
| public SignatureVisitor visitInterface() { |
| return this; |
| } |
| |
| @Override |
| public SignatureVisitor visitInterfaceBound() { |
| return this; |
| } |
| |
| @Override |
| public SignatureVisitor visitParameterType() { |
| return this; |
| } |
| |
| @Override |
| public SignatureVisitor visitReturnType() { |
| return this; |
| } |
| |
| @Override |
| public SignatureVisitor visitSuperclass() { |
| return this; |
| } |
| |
| @Override |
| public void visitTypeArgument() { |
| } |
| |
| @Override |
| public SignatureVisitor visitTypeArgument(char wildcard) { |
| return this; |
| } |
| |
| @Override |
| public void visitTypeVariable(String name) { |
| } |
| } |
| |
| CollectReferencesVisitor() { |
| this.av = new AnnotationVisitor(Opcodes.ASM7, this.av) { |
| @Override |
| public void visitEnum(String name, String desc, String value) { |
| addTypeIfClass(desc); |
| } |
| @Override |
| public void visit(String name, Object value) { |
| // don't mark this annotation as a reference or its arguments, so we can |
| // handle binary-only annotations. |
| // TODO(jat): consider implications of updating the annotation class |
| } |
| |
| }; |
| } |
| |
| // internal names |
| protected Set<String> referencedTypes = new HashSet<String>(); |
| |
| public Set<String> getReferencedTypes() { |
| return referencedTypes; |
| } |
| |
| @Override |
| public void visit(int version, int access, String name, String signature, |
| String superName, String[] interfaces) { |
| if (superName != null) { |
| referencedTypes.add(superName); |
| } |
| if (interfaces != null) { |
| for (String intf : interfaces) { |
| referencedTypes.add(intf); |
| } |
| } |
| collectTypesFromClassSignature(signature); |
| } |
| |
| @Override |
| public FieldVisitor visitField(int access, String name, String desc, |
| String signature, Object value) { |
| addTypeIfClass(desc); |
| collectTypesFromFieldSignature(signature); |
| // we don't use visitEnd, so we can just use ourselves for nested visitors |
| return super.visitField(access, name, desc, signature, value); |
| } |
| |
| /** |
| * @param name internal name of the inner class |
| * @param outerName internal name of the enclosing class |
| */ |
| @Override |
| public void visitInnerClass(String name, String outerName, String innerName, |
| int access) { |
| referencedTypes.add(name); |
| if (outerName != null) { |
| referencedTypes.add(outerName); |
| } |
| } |
| |
| @Override |
| public MethodVisitor visitMethod(int access, String name, String desc, |
| String signature, String[] exceptions) { |
| for (Type type : Type.getArgumentTypes(desc)) { |
| addTypeIfClass(type); |
| } |
| addTypeIfClass(Type.getReturnType(desc)); |
| collectTypesFromClassSignature(signature); |
| // we don't use visitEnd, so we can just use ourselves for nested visitors |
| return super.visitMethod(access, name, desc, signature, exceptions); |
| } |
| |
| /** |
| * @param owner internal name of owning class |
| */ |
| @Override |
| public void visitOuterClass(String owner, String name, String desc) { |
| referencedTypes.add(owner); |
| } |
| |
| protected void addTypeIfClass(String desc) { |
| addTypeIfClass(Type.getType(desc)); |
| } |
| |
| protected void addTypeIfClass(Type type) { |
| if (type.getSort() == Type.OBJECT) { |
| referencedTypes.add(type.getInternalName()); |
| } |
| } |
| |
| private void collectTypesFromClassSignature(String signature) { |
| if (signature == null) { |
| return; |
| } |
| SignatureReader reader = new SignatureReader(signature); |
| reader.accept(new CollectGenericTypes()); |
| } |
| |
| private void collectTypesFromFieldSignature(String signature) { |
| if (signature == null) { |
| return; |
| } |
| SignatureReader reader = new SignatureReader(signature); |
| reader.acceptType(new CollectGenericTypes()); |
| } |
| } |