View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel.classfile;
20  
21  import java.io.DataInput;
22  import java.io.DataOutputStream;
23  import java.io.IOException;
24  
25  import org.apache.bcel.Constants;
26  import org.apache.bcel.util.Args;
27  
28  /**
29   * This class represents a local variable within a method. It contains its scope, name, signature and index on the
30   * method's frame. It is used both to represent an element of the LocalVariableTable as well as an element of the
31   * LocalVariableTypeTable. The nomenclature used here may be a bit confusing; while the two items have the same layout
32   * in a class file, a LocalVariableTable attribute contains a descriptor_index, not a signatureIndex. The
33   * LocalVariableTypeTable attribute does have a signatureIndex.
34   *
35   * @see org.apache.bcel.classfile.Utility for more details on the difference.
36   * @see LocalVariableTable
37   * @see LocalVariableTypeTable
38   */
39  public final class LocalVariable implements Cloneable, Node, Constants {
40  
41      static final LocalVariable[] EMPTY_ARRAY = {};
42  
43      /** Range in which the variable is valid. */
44      private int startPc;
45  
46      private int length;
47  
48      /** Index in constant pool of variable name. */
49      private int nameIndex;
50  
51      /**
52       * Technically, a decscriptor_index for a local variable table entry and a signatureIndex for a local variable type table entry. Index of variable signature
53       */
54      private int signatureIndex;
55  
56      /*
57       * Variable is index'th local variable on this method's frame.
58       */
59      private int index;
60  
61      private ConstantPool constantPool;
62  
63      /** Never changes; used to match up with LocalVariableTypeTable entries. */
64      private final int origIndex;
65  
66      /**
67       * Constructs object from file stream.
68       *
69       * @param file Input stream
70       * @throws IOException if an I/O error occurs.
71       */
72      LocalVariable(final DataInput file, final ConstantPool constantPool) throws IOException {
73          this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), constantPool);
74      }
75  
76      /**
77       * @param startPc Range in which the variable
78       * @param length ... is valid
79       * @param nameIndex Index in constant pool of variable name
80       * @param signatureIndex Index of variable's signature
81       * @param index Variable is 'index'th local variable on the method's frame
82       * @param constantPool Array of constants
83       */
84      public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
85          this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
86      }
87  
88      /**
89       * @param startPc Range in which the variable
90       * @param length ... is valid
91       * @param nameIndex Index in constant pool of variable name
92       * @param signatureIndex Index of variable's signature
93       * @param index Variable is 'index'th local variable on the method's frame
94       * @param constantPool Array of constants
95       * @param origIndex Variable is 'index'th local variable on the method's frame prior to any changes
96       */
97      public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool,
98          final int origIndex) {
99          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 }