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     * Constructs a LocalVariable.
078     *
079     * @param startPc Range in which the variable is valid.
080     * @param length length of validity.
081     * @param nameIndex Index in constant pool of variable name.
082     * @param signatureIndex Index of variable's signature.
083     * @param index Variable is 'index'th local variable on the method's frame.
084     * @param constantPool Array of constants.
085     */
086    public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
087        this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
088    }
089
090    /**
091     * Constructs a LocalVariable.
092     *
093     * @param startPc Range in which the variable is valid.
094     * @param length length of validity.
095     * @param nameIndex Index in constant pool of variable name.
096     * @param signatureIndex Index of variable's signature.
097     * @param index Variable is 'index'th local variable on the method's frame.
098     * @param constantPool Array of constants.
099     * @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