1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.bcel.classfile;
20
21 import java.io.DataInput;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24
25 import org.apache.bcel.Constants;
26 import org.apache.bcel.util.Args;
27
28 /**
29 * This class represents a local variable within a method. It contains its scope, name, signature and index on the
30 * method's frame. It is used both to represent an element of the LocalVariableTable as well as an element of the
31 * LocalVariableTypeTable. The nomenclature used here may be a bit confusing; while the two items have the same layout
32 * in a class file, a LocalVariableTable attribute contains a descriptor_index, not a signatureIndex. The
33 * LocalVariableTypeTable attribute does have a signatureIndex.
34 *
35 * @see org.apache.bcel.classfile.Utility for more details on the difference.
36 * @see LocalVariableTable
37 * @see LocalVariableTypeTable
38 */
39 public final class LocalVariable implements Cloneable, Node, Constants {
40
41 static final LocalVariable[] EMPTY_ARRAY = {};
42
43 /** Range in which the variable is valid. */
44 private int startPc;
45
46 private int length;
47
48 /** Index in constant pool of variable name. */
49 private int nameIndex;
50
51 /**
52 * Technically, a decscriptor_index for a local variable table entry and a signatureIndex for a local variable type table entry. Index of variable signature
53 */
54 private int signatureIndex;
55
56 /*
57 * Variable is index'th local variable on this method's frame.
58 */
59 private int index;
60
61 private ConstantPool constantPool;
62
63 /** Never changes; used to match up with LocalVariableTypeTable entries. */
64 private final int origIndex;
65
66 /**
67 * Constructs object from file stream.
68 *
69 * @param file Input stream
70 * @throws IOException if an I/O error occurs.
71 */
72 LocalVariable(final DataInput file, final ConstantPool constantPool) throws IOException {
73 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), constantPool);
74 }
75
76 /**
77 * @param startPc Range in which the variable
78 * @param length ... is valid
79 * @param nameIndex Index in constant pool of variable name
80 * @param signatureIndex Index of variable's signature
81 * @param index Variable is 'index'th local variable on the method's frame
82 * @param constantPool Array of constants
83 */
84 public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
85 this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
86 }
87
88 /**
89 * @param startPc Range in which the variable
90 * @param length ... is valid
91 * @param nameIndex Index in constant pool of variable name
92 * @param signatureIndex Index of variable's signature
93 * @param index Variable is 'index'th local variable on the method's frame
94 * @param constantPool Array of constants
95 * @param origIndex Variable is 'index'th local variable on the method's frame prior to any changes
96 */
97 public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool,
98 final int origIndex) {
99 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 }