blob: b0f23625706e18e11966a0443744de8217c64d7e [file] [log] [blame]
/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.classfile;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/*
* Family of classes used to represent the parsed form of a {@link Descriptor}
* or {@link Signature}.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public abstract class Type {
protected Type() { }
public boolean isObject() {
return false;
}
public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
protected static void append(StringBuilder sb, String prefix, List<? extends Type> types, String suffix) {
sb.append(prefix);
String sep = "";
for (Type t: types) {
sb.append(sep);
sb.append(t);
sep = ", ";
}
sb.append(suffix);
}
protected static void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> types, String suffix) {
if (types != null && types.size() > 0)
append(sb, prefix, types, suffix);
}
public interface Visitor<R,P> {
R visitSimpleType(SimpleType type, P p);
R visitArrayType(ArrayType type, P p);
R visitMethodType(MethodType type, P p);
R visitClassSigType(ClassSigType type, P p);
R visitClassType(ClassType type, P p);
R visitTypeParamType(TypeParamType type, P p);
R visitWildcardType(WildcardType type, P p);
}
/**
* Represents a type signature with a simple name. The name may be that of a
* primitive type, such "{@code int}, {@code float}, etc
* or that of a type argument, such as {@code T}, {@code K}, {@code V}, etc.
*
* See:
* JVMS 4.3.2
* BaseType:
* {@code B}, {@code C}, {@code D}, {@code F}, {@code I},
* {@code J}, {@code S}, {@code Z};
* VoidDescriptor:
* {@code V};
* JVMS 4.3.4
* TypeVariableSignature:
* {@code T} Identifier {@code ;}
*/
public static class SimpleType extends Type {
public SimpleType(String name) {
this.name = name;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitSimpleType(this, data);
}
public boolean isPrimitiveType() {
return primitiveTypes.contains(name);
}
// where
private static final Set<String> primitiveTypes = new HashSet<String>(Arrays.asList(
"boolean", "byte", "char", "double", "float", "int", "long", "short", "void"));
@Override
public String toString() {
return name;
}
public final String name;
}
/**
* Represents an array type signature.
*
* See:
* JVMS 4.3.4
* ArrayTypeSignature:
* {@code [} TypeSignature {@code ]}
*/
public static class ArrayType extends Type {
public ArrayType(Type elemType) {
this.elemType = elemType;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitArrayType(this, data);
}
@Override
public String toString() {
return elemType + "[]";
}
public final Type elemType;
}
/**
* Represents a method type signature.
*
* See;
* JVMS 4.3.4
* MethodTypeSignature:
* FormalTypeParameters_opt {@code (} TypeSignature* {@code)} ReturnType
* ThrowsSignature*
*/
public static class MethodType extends Type {
public MethodType(List<? extends Type> paramTypes, Type resultType) {
this(null, paramTypes, resultType, null);
}
public MethodType(List<? extends TypeParamType> typeParamTypes,
List<? extends Type> paramTypes,
Type returnType,
List<? extends Type> throwsTypes) {
this.typeParamTypes = typeParamTypes;
this.paramTypes = paramTypes;
this.returnType = returnType;
this.throwsTypes = throwsTypes;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitMethodType(this, data);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
appendIfNotEmpty(sb, "<", typeParamTypes, "> ");
sb.append(returnType);
append(sb, " (", paramTypes, ")");
appendIfNotEmpty(sb, " throws ", throwsTypes, "");
return sb.toString();
}
public final List<? extends TypeParamType> typeParamTypes;
public final List<? extends Type> paramTypes;
public final Type returnType;
public final List<? extends Type> throwsTypes;
}
/**
* Represents a class signature. These describe the signature of
* a class that has type arguments.
*
* See:
* JVMS 4.3.4
* ClassSignature:
* FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature*
*/
public static class ClassSigType extends Type {
public ClassSigType(List<TypeParamType> typeParamTypes, Type superclassType,
List<Type> superinterfaceTypes) {
this.typeParamTypes = typeParamTypes;
this.superclassType = superclassType;
this.superinterfaceTypes = superinterfaceTypes;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitClassSigType(this, data);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
appendIfNotEmpty(sb, "<", typeParamTypes, ">");
if (superclassType != null) {
sb.append(" extends ");
sb.append(superclassType);
}
appendIfNotEmpty(sb, " implements ", superinterfaceTypes, "");
return sb.toString();
}
public final List<TypeParamType> typeParamTypes;
public final Type superclassType;
public final List<Type> superinterfaceTypes;
}
/**
* Represents a class type signature. This is used to represent a
* reference to a class, such as in a field, parameter, return type, etc.
*
* See:
* JVMS 4.3.4
* ClassTypeSignature:
* {@code L} PackageSpecifier_opt SimpleClassTypeSignature
* ClassTypeSignatureSuffix* {@code ;}
* PackageSpecifier:
* Identifier {@code /} PackageSpecifier*
* SimpleClassTypeSignature:
* Identifier TypeArguments_opt }
* ClassTypeSignatureSuffix:
* {@code .} SimpleClassTypeSignature
*/
public static class ClassType extends Type {
public ClassType(ClassType outerType, String name, List<Type> typeArgs) {
this.outerType = outerType;
this.name = name;
this.typeArgs = typeArgs;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitClassType(this, data);
}
public String getBinaryName() {
if (outerType == null)
return name;
else
return (outerType.getBinaryName() + "$" + name);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (outerType != null) {
sb.append(outerType);
sb.append(".");
}
sb.append(name);
appendIfNotEmpty(sb, "<", typeArgs, ">");
return sb.toString();
}
@Override
public boolean isObject() {
return (outerType == null)
&& name.equals("java/lang/Object")
&& (typeArgs == null || typeArgs.isEmpty());
}
public final ClassType outerType;
public final String name;
public final List<Type> typeArgs;
}
/**
* Represents a FormalTypeParameter. These are used to declare the type
* parameters for generic classes and methods.
*
* See:
* JVMS 4.3.4
* FormalTypeParameters:
* {@code <} FormalTypeParameter+ {@code >}
* FormalTypeParameter:
* Identifier ClassBound InterfaceBound*
* ClassBound:
* {@code :} FieldTypeSignature_opt
* InterfaceBound:
* {@code :} FieldTypeSignature
*/
public static class TypeParamType extends Type {
public TypeParamType(String name, Type classBound, List<Type> interfaceBounds) {
this.name = name;
this.classBound = classBound;
this.interfaceBounds = interfaceBounds;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitTypeParamType(this, data);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name);
String sep = " extends ";
if (classBound != null) {
sb.append(sep);
sb.append(classBound);
sep = " & ";
}
if (interfaceBounds != null) {
for (Type bound: interfaceBounds) {
sb.append(sep);
sb.append(bound);
sep = " & ";
}
}
return sb.toString();
}
public final String name;
public final Type classBound;
public final List<Type> interfaceBounds;
}
/**
* Represents a wildcard type argument. A type argument that is not a
* wildcard type argument will be represented by a ClassType, ArrayType, etc.
*
* See:
* JVMS 4.3.4
* TypeArgument:
* WildcardIndicator_opt FieldTypeSignature
* {@code *}
* WildcardIndicator:
* {@code +}
* {@code -}
*/
public static class WildcardType extends Type {
public enum Kind { UNBOUNDED, EXTENDS, SUPER };
public WildcardType() {
this(Kind.UNBOUNDED, null);
}
public WildcardType(Kind kind, Type boundType) {
this.kind = kind;
this.boundType = boundType;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitWildcardType(this, data);
}
@Override
public String toString() {
switch (kind) {
case UNBOUNDED:
return "?";
case EXTENDS:
return "? extends " + boundType;
case SUPER:
return "? super " + boundType;
default:
throw new AssertionError();
}
}
public final Kind kind;
public final Type boundType;
}
}