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