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