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 * Constructs a LocalVariable.
78 *
79 * @param startPc Range in which the variable is valid.
80 * @param length length of validity.
81 * @param nameIndex Index in constant pool of variable name.
82 * @param signatureIndex Index of variable's signature.
83 * @param index Variable is 'index'th local variable on the method's frame.
84 * @param constantPool Array of constants.
85 */
86 public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
87 this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
88 }
89
90 /**
91 * Constructs a LocalVariable.
92 *
93 * @param startPc Range in which the variable is valid.
94 * @param length length of validity.
95 * @param nameIndex Index in constant pool of variable name.
96 * @param signatureIndex Index of variable's signature.
97 * @param index Variable is 'index'th local variable on the method's frame.
98 * @param constantPool Array of constants.
99 * @param origIndex Variable is 'index'th local variable on the method's frame prior to any changes.
100 */
101 public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool,
102 final int origIndex) {
103 this.startPc = Args.requireU2(startPc, "startPc");
104 this.length = Args.requireU2(length, "length");
105 this.nameIndex = Args.requireU2(nameIndex, "nameIndex");
106 this.signatureIndex = Args.requireU2(signatureIndex, "signatureIndex");
107 this.index = Args.requireU2(index, "index");
108 this.origIndex = Args.requireU2(origIndex, "origIndex");
109 this.constantPool = constantPool;
110 }
111
112 /**
113 * Initializes from another LocalVariable. Note that both objects use the same references (shallow copy). Use copy() for
114 * a physical copy.
115 *
116 * @param localVariable Another LocalVariable.
117 */
118 public LocalVariable(final LocalVariable localVariable) {
119 this(localVariable.getStartPC(), localVariable.getLength(), localVariable.getNameIndex(), localVariable.getSignatureIndex(), localVariable.getIndex(),
120 localVariable.getConstantPool());
121 }
122
123 /**
124 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
125 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
126 *
127 * @param v Visitor object.
128 */
129 @Override
130 public void accept(final Visitor v) {
131 v.visitLocalVariable(this);
132 }
133
134 /**
135 * Creates a deep copy of this object.
136 *
137 * @return deep copy of this object.
138 */
139 public LocalVariable copy() {
140 try {
141 return (LocalVariable) clone();
142 } catch (final CloneNotSupportedException e) {
143 // TODO should this throw?
144 }
145 return null;
146 }
147
148 /**
149 * Dumps local variable to file stream in binary format.
150 *
151 * @param dataOutputStream Output file stream.
152 * @throws IOException if an I/O error occurs.
153 * @see java.io.FilterOutputStream#out
154 */
155 public void dump(final DataOutputStream dataOutputStream) throws IOException {
156 dataOutputStream.writeShort(startPc);
157 dataOutputStream.writeShort(length);
158 dataOutputStream.writeShort(nameIndex);
159 dataOutputStream.writeShort(signatureIndex);
160 dataOutputStream.writeShort(index);
161 }
162
163 /**
164 * Gets the constant pool used by this object.
165 *
166 * @return Constant pool used by this object.
167 */
168 public ConstantPool getConstantPool() {
169 return constantPool;
170 }
171
172 /**
173 * Gets the index of register where variable is stored.
174 *
175 * @return index of register where variable is stored.
176 */
177 public int getIndex() {
178 return index;
179 }
180
181 /**
182 * Gets the length of validity.
183 *
184 * @return Variable is valid within getStartPC() .. getStartPC()+getLength().
185 */
186 public int getLength() {
187 return length;
188 }
189
190 /**
191 * Gets the variable name.
192 *
193 * @return Variable name.
194 */
195 public String getName() {
196 return constantPool.getConstantUtf8(nameIndex).getBytes();
197 }
198
199 /**
200 * Gets the index in constant pool of variable name.
201 *
202 * @return Index in constant pool of variable name.
203 */
204 public int getNameIndex() {
205 return nameIndex;
206 }
207
208 /**
209 * Gets the index of register where variable was originally stored.
210 *
211 * @return index of register where variable was originally stored.
212 */
213 public int getOrigIndex() {
214 return origIndex;
215 }
216
217 /**
218 * Gets the signature.
219 *
220 * @return Signature.
221 */
222 public String getSignature() {
223 return constantPool.getConstantUtf8(signatureIndex).getBytes();
224 }
225
226 /**
227 * Gets the index in constant pool of variable signature.
228 *
229 * @return Index in constant pool of variable signature.
230 */
231 public int getSignatureIndex() {
232 return signatureIndex;
233 }
234
235 /**
236 * Gets the start of range where the variable is valid.
237 *
238 * @return Start of range where the variable is valid.
239 */
240 public int getStartPC() {
241 return startPc;
242 }
243
244 /**
245 * Sets the constant pool to be used for this object.
246 *
247 * @param constantPool Constant pool to be used for this object.
248 */
249 public void setConstantPool(final ConstantPool constantPool) {
250 this.constantPool = constantPool;
251 }
252
253 /**
254 * Sets the index in the local variable table of this variable.
255 *
256 * @param index the index in the local variable table of this variable.
257 */
258 public void setIndex(final int index) { // TODO unused
259 this.index = index;
260 }
261
262 /**
263 * Sets the length of this local variable.
264 *
265 * @param length the length of this local variable.
266 */
267 public void setLength(final int length) {
268 this.length = length;
269 }
270
271 /**
272 * Sets the index into the constant pool for the name of this variable.
273 *
274 * @param nameIndex the index into the constant pool for the name of this variable.
275 */
276 public void setNameIndex(final int nameIndex) { // TODO unused
277 this.nameIndex = nameIndex;
278 }
279
280 /**
281 * Sets the index into the constant pool for the signature of this variable.
282 *
283 * @param signatureIndex the index into the constant pool for the signature of this variable.
284 */
285 public void setSignatureIndex(final int signatureIndex) { // TODO unused
286 this.signatureIndex = signatureIndex;
287 }
288
289 /**
290 * Sets the range where the local variable is valid.
291 *
292 * @param startPc Specify range where the local variable is valid.
293 */
294 public void setStartPC(final int startPc) { // TODO unused
295 this.startPc = startPc;
296 }
297
298 /**
299 * Gets the string representation.
300 *
301 * @return string representation.
302 */
303 @Override
304 public String toString() {
305 return toStringShared(false);
306 }
307
308 /*
309 * Helper method shared with LocalVariableTypeTable
310 */
311 String toStringShared(final boolean typeTable) {
312 final String name = getName();
313 final String signature = Utility.signatureToString(getSignature(), false);
314 final String label = "LocalVariable" + (typeTable ? "Types" : "");
315 return label + "(startPc = " + startPc + ", length = " + length + ", index = " + index + ":" + signature + " " + name + ")";
316 }
317 }
318