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 */
017
018package org.apache.bcel.classfile;
019
020import java.io.DataInput;
021import java.io.DataOutputStream;
022import java.io.IOException;
023import java.util.Arrays;
024import java.util.Iterator;
025import java.util.stream.Stream;
026
027import org.apache.bcel.Const;
028import org.apache.bcel.util.Args;
029
030// The new table is used when generic types are about...
031
032//LocalVariableTable_attribute {
033//       u2 attribute_name_index;
034//       u4 attribute_length;
035//       u2 local_variable_table_length;
036//       {  u2 start_pc;
037//          u2 length;
038//          u2 name_index;
039//          u2 descriptor_index;
040//          u2 index;
041//       } local_variable_table[local_variable_table_length];
042//     }
043
044//LocalVariableTypeTable_attribute {
045//    u2 attribute_name_index;
046//    u4 attribute_length;
047//    u2 local_variable_type_table_length;
048//    {
049//      u2 start_pc;
050//      u2 length;
051//      u2 name_index;
052//      u2 signature_index;
053//      u2 index;
054//    } localVariableTypeTable[local_variable_type_table_length];
055//  }
056// J5TODO: Needs some testing !
057
058/**
059 * @since 6.0
060 */
061public class LocalVariableTypeTable extends Attribute implements Iterable<LocalVariable> {
062
063    private static final LocalVariable[] EMPTY_ARRAY = {};
064
065    private LocalVariable[] localVariableTypeTable; // variables
066
067    LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
068        this(nameIdx, len, (LocalVariable[]) null, cpool);
069        final int localVariableTypeTableLength = input.readUnsignedShort();
070        localVariableTypeTable = new LocalVariable[localVariableTypeTableLength];
071        for (int i = 0; i < localVariableTypeTableLength; i++) {
072            localVariableTypeTable[i] = new LocalVariable(input, cpool);
073        }
074    }
075
076    public LocalVariableTypeTable(final int nameIndex, final int length, final LocalVariable[] localVariableTypeTable, final ConstantPool constantPool) {
077        super(Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE, nameIndex, length, constantPool);
078        this.localVariableTypeTable = localVariableTypeTable != null ? localVariableTypeTable : LocalVariable.EMPTY_ARRAY;
079        Args.requireU2(this.localVariableTypeTable.length, "localVariableTypeTable.length");
080    }
081
082    public LocalVariableTypeTable(final LocalVariableTypeTable c) {
083        this(c.getNameIndex(), c.getLength(), c.getLocalVariableTypeTable(), c.getConstantPool());
084    }
085
086    @Override
087    public void accept(final Visitor v) {
088        v.visitLocalVariableTypeTable(this);
089    }
090
091    /**
092     * @return deep copy of this attribute
093     */
094    @Override
095    public Attribute copy(final ConstantPool constantPool) {
096        final LocalVariableTypeTable c = (LocalVariableTypeTable) clone();
097        c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length];
098        Arrays.setAll(c.localVariableTypeTable, i -> localVariableTypeTable[i].copy());
099        c.setConstantPool(constantPool);
100        return c;
101    }
102
103    @Override
104    public final void dump(final DataOutputStream file) throws IOException {
105        super.dump(file);
106        file.writeShort(localVariableTypeTable.length);
107        for (final LocalVariable variable : localVariableTypeTable) {
108            variable.dump(file);
109        }
110    }
111
112    public final LocalVariable getLocalVariable(final int index) {
113        for (final LocalVariable variable : localVariableTypeTable) {
114            if (variable.getIndex() == index) {
115                return variable;
116            }
117        }
118        return null;
119    }
120
121    public final LocalVariable[] getLocalVariableTypeTable() {
122        return localVariableTypeTable;
123    }
124
125    public final int getTableLength() {
126        return localVariableTypeTable == null ? 0 : localVariableTypeTable.length;
127    }
128
129    @Override
130    public Iterator<LocalVariable> iterator() {
131        return Stream.of(localVariableTypeTable).iterator();
132    }
133
134    public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
135        this.localVariableTypeTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
136    }
137
138    /**
139     * @return String representation.
140     */
141    @Override
142    public final String toString() {
143        final StringBuilder buf = new StringBuilder();
144        for (int i = 0; i < localVariableTypeTable.length; i++) {
145            buf.append(localVariableTypeTable[i].toStringShared(true));
146            if (i < localVariableTypeTable.length - 1) {
147                buf.append('\n');
148            }
149        }
150        return buf.toString();
151    }
152}