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     * @return basic type of array, i.e., for int[][][] the basic type is int
097     */
098    public Type getBasicType() {
099        return basicType;
100    }
101
102    /**
103     * Gets the name of referenced class.
104     *
105     * @return name of referenced class.
106     * @since 6.7.0
107     */
108    @Override
109    public String getClassName() {
110        return signature;
111    }
112
113    /**
114     * @return number of dimensions of array
115     */
116    public int getDimensions() {
117        return dimensions;
118    }
119
120    /**
121     * @return element type of array, i.e., for int[][][] the element type is int[][]
122     */
123    public Type getElementType() {
124        if (dimensions == 1) {
125            return basicType;
126        }
127        return new ArrayType(basicType, dimensions - 1);
128    }
129
130    /**
131     * @return a hash code value for the object.
132     */
133    @Override
134    public int hashCode() {
135        return basicType.hashCode() ^ dimensions;
136    }
137}