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