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