001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.generic;
020
021import org.apache.bcel.Const;
022
023/**
024 * Denotes array type, such as int[][]
025 */
026public final class ArrayType extends ReferenceType {
027
028    private final int dimensions;
029    private final Type basicType;
030
031    /**
032     * Convenience constructor for array type, for example int[]
033     *
034     * @param type array type, for example T_INT.
035     * @param dimensions array dimensions.
036     */
037    public ArrayType(final byte type, final int dimensions) {
038        this(BasicType.getType(type), dimensions);
039    }
040
041    /**
042     * Convenience constructor for reference array type, for example Object[]
043     *
044     * @param className complete name of class ({@link String}, for example).
045     * @param dimensions array dimensions.
046     */
047    public ArrayType(final String className, final int dimensions) {
048        this(ObjectType.getInstance(className), dimensions);
049    }
050
051    /**
052     * Constructor for array of given type
053     *
054     * @param type type of array (may be an array itself).
055     * @param dimensions array dimensions.
056     */
057    public ArrayType(final Type type, final int dimensions) {
058        super(Const.T_ARRAY, "<dummy>");
059        if (dimensions < 1 || dimensions > Const.MAX_BYTE) {
060            throw new ClassGenException("Invalid number of dimensions: " + dimensions);
061        }
062        switch (type.getType()) {
063        case Const.T_ARRAY:
064            final ArrayType array = (ArrayType) type;
065            this.dimensions = dimensions + array.dimensions;
066            basicType = array.basicType;
067            break;
068        case Const.T_VOID:
069            throw new ClassGenException("Invalid type: void[]");
070        default: // Basic type or reference
071            this.dimensions = dimensions;
072            basicType = type;
073            break;
074        }
075        final StringBuilder buf = new StringBuilder();
076        for (int i = 0; i < this.dimensions; i++) {
077            buf.append('[');
078        }
079        buf.append(basicType.getSignature());
080        this.signature = buf.toString();
081    }
082
083    /**
084     * @return true if both type objects refer to the same array type.
085     */
086    @Override
087    public boolean equals(final Object type) {
088        if (type instanceof ArrayType) {
089            final ArrayType array = (ArrayType) type;
090            return array.dimensions == dimensions && array.basicType.equals(basicType);
091        }
092        return false;
093    }
094
095    /**
096     * Gets the basic type of array, that is, for int[][][] the basic type is int.
097     *
098     * @return basic type of array, that is, for int[][][] the basic type is int.
099     */
100    public Type getBasicType() {
101        return basicType;
102    }
103
104    /**
105     * Gets the name of referenced class.
106     *
107     * @return name of referenced class.
108     * @since 6.7.0
109     */
110    @Override
111    public String getClassName() {
112        return signature;
113    }
114
115    /**
116     * Gets the number of dimensions of array.
117     *
118     * @return number of dimensions of array.
119     */
120    public int getDimensions() {
121        return dimensions;
122    }
123
124    /**
125     * Gets the element type of array, that is, for int[][][] the element type is int[][].
126     *
127     * @return element type of array, that is, for int[][][] the element type is int[][].
128     */
129    public Type getElementType() {
130        if (dimensions == 1) {
131            return basicType;
132        }
133        return new ArrayType(basicType, dimensions - 1);
134    }
135
136    /**
137     * @return a hash code value for the object.
138     */
139    @Override
140    public int hashCode() {
141        return basicType.hashCode() ^ dimensions;
142    }
143}