    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