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