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