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 LocalVariable[] localVariableTypeTable; // variables
064
065    LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
066        this(nameIdx, len, (LocalVariable[]) null, cpool);
067
068        final int localVariableTypeTableLength = input.readUnsignedShort();
069        localVariableTypeTable = new LocalVariable[localVariableTypeTableLength];
070
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
098        c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length];
099        Arrays.setAll(c.localVariableTypeTable, i -> localVariableTypeTable[i].copy());
100        c.setConstantPool(constantPool);
101        return c;
102    }
103
104    @Override
105    public final void dump(final DataOutputStream file) throws IOException {
106        super.dump(file);
107        file.writeShort(localVariableTypeTable.length);
108        for (final LocalVariable variable : localVariableTypeTable) {
109            variable.dump(file);
110        }
111    }
112
113    public final LocalVariable getLocalVariable(final int index) {
114        for (final LocalVariable variable : localVariableTypeTable) {
115            if (variable.getIndex() == index) {
116                return variable;
117            }
118        }
119
120        return null;
121    }
122
123    public final LocalVariable[] getLocalVariableTypeTable() {
124        return localVariableTypeTable;
125    }
126
127    public final int getTableLength() {
128        return localVariableTypeTable == null ? 0 : localVariableTypeTable.length;
129    }
130
131    @Override
132    public Iterator<LocalVariable> iterator() {
133        return Stream.of(localVariableTypeTable).iterator();
134    }
135
136    public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
137        this.localVariableTypeTable = localVariableTable;
138    }
139
140    /**
141     * @return String representation.
142     */
143    @Override
144    public final String toString() {
145        final StringBuilder buf = new StringBuilder();
146
147        for (int i = 0; i < localVariableTypeTable.length; i++) {
148            buf.append(localVariableTypeTable[i].toStringShared(true));
149
150            if (i < localVariableTypeTable.length - 1) {
151                buf.append('\n');
152            }
153        }
154
155        return buf.toString();
156    }
157}