/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.dcd.asm;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureVisitor;
import net.sourceforge.pmd.dcd.ClassLoaderUtil;
public class TypeSignatureVisitor extends SignatureVisitor {
private static final boolean TRACE = false;
private static final int NO_TYPE = 0;
private static final int FIELD_TYPE = 1;
private static final int RETURN_TYPE = 2;
private static final int PARAMETER_TYPE = 3;
// The type of the current Type
private int typeType;
// The current Type identified.
private Class<?> type;
// The number of dimensions on an array for the current Type.
private int arrayDimensions = 0;
// Completed Field Type is stored here
private Class<?> fieldType;
// Completed Return Type is stored here
private Class<?> returnType;
// Completed Parameter Types are stored here
private List<Class<?>> parameterTypes = new ArrayList<>(0);
private final PrintVisitor p;
public TypeSignatureVisitor() {
super(Opcodes.ASM5);
p = new PrintVisitor();
init();
}
public TypeSignatureVisitor(PrintVisitor parent) {
super(Opcodes.ASM5);
p = new PrintVisitor(parent);
init();
}
protected void println(String s) {
p.println(s);
}
protected void printlnIndent(String s) {
p.printlnIndent(s);
}
public void init() {
typeType = FIELD_TYPE;
type = null;
arrayDimensions = 0;
parameterTypes.clear();
}
public Class<?> getFieldType() {
popType();
if (fieldType == null) {
throw new RuntimeException();
}
return fieldType;
}
public Class<?> getMethodReturnType() {
popType();
if (returnType == null) {
throw new RuntimeException();
}
return returnType;
}
public Class<?>[] getMethodParameterTypes() {
popType();
if (parameterTypes == null) {
throw new RuntimeException();
}
if (parameterTypes != null) {
return parameterTypes.toArray(new Class<?>[parameterTypes.size()]);
} else {
return null;
}
}
private void pushType(int type) {
this.typeType = type;
}
private void popType() {
switch (typeType) {
case NO_TYPE:
break;
case FIELD_TYPE:
fieldType = getType();
break;
case RETURN_TYPE:
returnType = getType();
break;
case PARAMETER_TYPE:
parameterTypes.add(getType());
break;
default:
throw new RuntimeException("Unknown type type: " + typeType);
}
typeType = NO_TYPE;
type = null;
arrayDimensions = 0;
}
private Class<?> getType() {
Class<?> type = null;
if (this.type != null) {
type = this.type;
for (int i = 0; i < arrayDimensions; i++) {
// Is there another way to get Array Classes?
Object array = Array.newInstance(type, 0);
type = array.getClass();
}
}
return type;
}
@Override
public SignatureVisitor visitArrayType() {
if (TRACE) {
println("visitArrayType:");
}
arrayDimensions++;
return this;
}
@Override
public void visitBaseType(char descriptor) {
if (TRACE) {
println("visitBaseType:");
printlnIndent("descriptor: " + descriptor);
}
switch (descriptor) {
case 'B':
type = Byte.TYPE;
break;
case 'C':
type = Character.TYPE;
break;
case 'D':
type = Double.TYPE;
break;
case 'F':
type = Float.TYPE;
break;
case 'I':
type = Integer.TYPE;
break;
case 'J':
type = Long.TYPE;
break;
case 'S':
type = Short.TYPE;
break;
case 'Z':
type = Boolean.TYPE;
break;
case 'V':
type = Void.TYPE;
break;
default:
throw new RuntimeException("Unknown baseType descriptor: " + descriptor);
}
}
@Override
public SignatureVisitor visitClassBound() {
if (TRACE) {
println("visitClassBound:");
}
return this;
}
@Override
public void visitClassType(String name) {
if (TRACE) {
println("visitClassType:");
printlnIndent("name: " + name);
}
name = ClassLoaderUtil.fromInternalForm(name);
this.type = ClassLoaderUtil.getClass(name);
}
@Override
public void visitEnd() {
if (TRACE) {
println("visitEnd:");
}
popType();
}
@Override
public SignatureVisitor visitExceptionType() {
if (TRACE) {
println("visitExceptionType:");
}
return this;
}
@Override
public void visitFormalTypeParameter(String name) {
if (TRACE) {
println("visitFormalTypeParameter:");
printlnIndent("name: " + name);
}
}
@Override
public void visitInnerClassType(String name) {
if (TRACE) {
println("visitInnerClassType:");
printlnIndent("name: " + name);
}
}
@Override
public SignatureVisitor visitInterface() {
if (TRACE) {
println("visitInterface:");
}
return this;
}
@Override
public SignatureVisitor visitInterfaceBound() {
if (TRACE) {
println("visitInterfaceBound:");
}
return this;
}
@Override
public SignatureVisitor visitParameterType() {
if (TRACE) {
println("visitParameterType:");
}
popType();
pushType(PARAMETER_TYPE);
return this;
}
@Override
public SignatureVisitor visitReturnType() {
if (TRACE) {
println("visitReturnType:");
}
popType();
pushType(RETURN_TYPE);
return this;
}
@Override
public SignatureVisitor visitSuperclass() {
if (TRACE) {
println("visitSuperclass:");
}
return this;
}
@Override
public void visitTypeArgument() {
if (TRACE) {
println("visitTypeArgument:");
}
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
if (TRACE) {
println("visitTypeArgument:");
printlnIndent("wildcard: " + wildcard);
}
return this;
}
@Override
public void visitTypeVariable(String name) {
if (TRACE) {
println("visitTypeVariable:");
printlnIndent("name: " + name);
}
}
}