blob: 556fc0971346fb18aa025ca7f6396bf79875f02f [file] [log] [blame]
/*
* 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.asm.AnnotationVisitor;
import com.google.gwt.dev.asm.FieldVisitor;
import com.google.gwt.dev.asm.MethodVisitor;
import com.google.gwt.dev.asm.Type;
import com.google.gwt.dev.asm.commons.EmptyVisitor;
import com.google.gwt.dev.asm.signature.SignatureReader;
import com.google.gwt.dev.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 implements SignatureVisitor {
public SignatureVisitor visitArrayType() {
return this;
}
public void visitBaseType(char descriptor) {
}
public SignatureVisitor visitClassBound() {
return this;
}
public void visitClassType(String name) {
referencedTypes.add(name);
}
public void visitEnd() {
}
public SignatureVisitor visitExceptionType() {
return this;
}
public void visitFormalTypeParameter(String name) {
}
public void visitInnerClassType(String name) {
}
public SignatureVisitor visitInterface() {
return this;
}
public SignatureVisitor visitInterfaceBound() {
return this;
}
public SignatureVisitor visitParameterType() {
return this;
}
public SignatureVisitor visitReturnType() {
return this;
}
public SignatureVisitor visitSuperclass() {
return this;
}
public void visitTypeArgument() {
}
public SignatureVisitor visitTypeArgument(char wildcard) {
return this;
}
public void visitTypeVariable(String name) {
}
}
// 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 void visit(String name, Object value) {
if (value instanceof Type) {
addTypeIfClass((Type) value);
}
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
// 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
return null;
}
@Override
public void visitEnum(String name, String desc, String value) {
addTypeIfClass(desc);
}
@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 this;
}
/**
* @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 this;
}
/**
* @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());
}
}