/*
 * 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 "int, float, etc or that of a type argument, such as T, K, V, etc. See: JVMS 4.3.2 BaseType: B, C, D, F, I, J, S, Z; VoidDescriptor: V; JVMS 4.3.4 TypeVariableSignature: T Identifier ;
/** * 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<>(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: [ TypeSignature ]
/** * 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 ( TypeSignature* ReturnType ThrowsSignature*
/** * 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*
/** * 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: L PackageSpecifier_opt SimpleClassTypeSignature ClassTypeSignatureSuffix* ; PackageSpecifier: Identifier / PackageSpecifier* SimpleClassTypeSignature: Identifier TypeArguments_opt } ClassTypeSignatureSuffix: . SimpleClassTypeSignature
/** * 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: < FormalTypeParameter+ > FormalTypeParameter: Identifier ClassBound InterfaceBound* ClassBound: : FieldTypeSignature_opt InterfaceBound: : FieldTypeSignature
/** * 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 * WildcardIndicator: + -
/** * 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; } }