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.classfile; 018 019import java.io.DataInput; 020import java.io.DataOutputStream; 021import java.io.IOException; 022 023import org.apache.bcel.Constants; 024 025/** 026 * This class represents a local variable within a method. It contains its scope, name, signature and index on the 027 * method's frame. It is used both to represent an element of the LocalVariableTable as well as an element of the 028 * LocalVariableTypeTable. The nomenclature used here may be a bit confusing; while the two items have the same layout 029 * in a class file, a LocalVariableTable attribute contains a descriptor_index, not a signatureIndex. The 030 * LocalVariableTypeTable attribute does have a signatureIndex. 031 * 032 * @see org.apache.bcel.classfile.Utility for more details on the difference. 033 * 034 * @see LocalVariableTable 035 * @see LocalVariableTypeTable 036 */ 037public final class LocalVariable implements Cloneable, Node, Constants { 038 039 private int startPc; // Range in which the variable is valid 040 private int length; 041 private int nameIndex; // Index in constant pool of variable name 042 // Technically, a decscriptor_index for a local variable table entry 043 // and a signatureIndex for a local variable type table entry. 044 private int signatureIndex; // Index of variable signature 045 private int index; /* 046 * Variable is index'th local variable on this method's frame. 047 */ 048 private ConstantPool constantPool; 049 private int origIndex; // never changes; used to match up with LocalVariableTypeTable entries 050 051 /** 052 * Constructs object from file stream. 053 * 054 * @param file Input stream 055 * @throws IOException if an I/O error occurs. 056 */ 057 LocalVariable(final DataInput file, final ConstantPool constantPool) throws IOException { 058 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), constantPool); 059 } 060 061 /** 062 * @param startPc Range in which the variable 063 * @param length ... is valid 064 * @param nameIndex Index in constant pool of variable name 065 * @param signatureIndex Index of variable's signature 066 * @param index Variable is `index'th local variable on the method's frame 067 * @param constantPool Array of constants 068 */ 069 public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) { 070 this.startPc = startPc; 071 this.length = length; 072 this.nameIndex = nameIndex; 073 this.signatureIndex = signatureIndex; 074 this.index = index; 075 this.constantPool = constantPool; 076 this.origIndex = index; 077 } 078 079 /** 080 * @param startPc Range in which the variable 081 * @param length ... is valid 082 * @param nameIndex Index in constant pool of variable name 083 * @param signatureIndex Index of variable's signature 084 * @param index Variable is `index'th local variable on the method's frame 085 * @param constantPool Array of constants 086 * @param origIndex Variable is `index'th local variable on the method's frame prior to any changes 087 */ 088 public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool, 089 final int origIndex) { 090 this.startPc = startPc; 091 this.length = length; 092 this.nameIndex = nameIndex; 093 this.signatureIndex = signatureIndex; 094 this.index = index; 095 this.constantPool = constantPool; 096 this.origIndex = origIndex; 097 } 098 099 /** 100 * Initializes from another LocalVariable. Note that both objects use the same references (shallow copy). Use copy() for 101 * a physical copy. 102 * 103 * @param localVariable Another LocalVariable. 104 */ 105 public LocalVariable(final LocalVariable localVariable) { 106 this(localVariable.getStartPC(), localVariable.getLength(), localVariable.getNameIndex(), localVariable.getSignatureIndex(), localVariable.getIndex(), 107 localVariable.getConstantPool()); 108 this.origIndex = localVariable.getOrigIndex(); 109 } 110 111 /** 112 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 113 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 114 * 115 * @param v Visitor object 116 */ 117 @Override 118 public void accept(final Visitor v) { 119 v.visitLocalVariable(this); 120 } 121 122 /** 123 * @return deep copy of this object 124 */ 125 public LocalVariable copy() { 126 try { 127 return (LocalVariable) clone(); 128 } catch (final CloneNotSupportedException e) { 129 // TODO should this throw? 130 } 131 return null; 132 } 133 134 /** 135 * Dumps local variable to file stream in binary format. 136 * 137 * @param dataOutputStream Output file stream 138 * @throws IOException if an I/O error occurs. 139 * @see java.io.FilterOutputStream#out 140 */ 141 public void dump(final DataOutputStream dataOutputStream) throws IOException { 142 dataOutputStream.writeShort(startPc); 143 dataOutputStream.writeShort(length); 144 dataOutputStream.writeShort(nameIndex); 145 dataOutputStream.writeShort(signatureIndex); 146 dataOutputStream.writeShort(index); 147 } 148 149 /** 150 * @return Constant pool used by this object. 151 */ 152 public ConstantPool getConstantPool() { 153 return constantPool; 154 } 155 156 /** 157 * @return index of register where variable is stored 158 */ 159 public int getIndex() { 160 return index; 161 } 162 163 /** 164 * @return Variable is valid within getStartPC() .. getStartPC()+getLength() 165 */ 166 public int getLength() { 167 return length; 168 } 169 170 /** 171 * @return Variable name. 172 */ 173 public String getName() { 174 return constantPool.getConstantUtf8(nameIndex).getBytes(); 175 } 176 177 /** 178 * @return Index in constant pool of variable name. 179 */ 180 public int getNameIndex() { 181 return nameIndex; 182 } 183 184 /** 185 * @return index of register where variable was originally stored 186 */ 187 public int getOrigIndex() { 188 return origIndex; 189 } 190 191 /** 192 * @return Signature. 193 */ 194 public String getSignature() { 195 return constantPool.getConstantUtf8(signatureIndex).getBytes(); 196 } 197 198 /** 199 * @return Index in constant pool of variable signature. 200 */ 201 public int getSignatureIndex() { 202 return signatureIndex; 203 } 204 205 /** 206 * @return Start of range where the variable is valid 207 */ 208 public int getStartPC() { 209 return startPc; 210 } 211 212 /** 213 * @param constantPool Constant pool to be used for this object. 214 */ 215 public void setConstantPool(final ConstantPool constantPool) { 216 this.constantPool = constantPool; 217 } 218 219 /** 220 * @param index the index in the local variable table of this variable 221 */ 222 public void setIndex(final int index) { // TODO unused 223 this.index = index; 224 } 225 226 /** 227 * @param length the length of this local variable 228 */ 229 public void setLength(final int length) { 230 this.length = length; 231 } 232 233 /** 234 * @param nameIndex the index into the constant pool for the name of this variable 235 */ 236 public void setNameIndex(final int nameIndex) { // TODO unused 237 this.nameIndex = nameIndex; 238 } 239 240 /** 241 * @param signatureIndex the index into the constant pool for the signature of this variable 242 */ 243 public void setSignatureIndex(final int signatureIndex) { // TODO unused 244 this.signatureIndex = signatureIndex; 245 } 246 247 /** 248 * @param startPc Specify range where the local variable is valid. 249 */ 250 public void setStartPC(final int startPc) { // TODO unused 251 this.startPc = startPc; 252 } 253 254 /** 255 * @return string representation. 256 */ 257 @Override 258 public String toString() { 259 return toStringShared(false); 260 } 261 262 /* 263 * Helper method shared with LocalVariableTypeTable 264 */ 265 String toStringShared(final boolean typeTable) { 266 final String name = getName(); 267 final String signature = Utility.signatureToString(getSignature(), false); 268 final String label = "LocalVariable" + (typeTable ? "Types" : ""); 269 return label + "(startPc = " + startPc + ", length = " + length + ", index = " + index + ":" + signature + " " + name + ")"; 270 } 271}