View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.bcel.classfile;
18  
19  import java.io.DataInput;
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  
23  import org.apache.bcel.Constants;
24  import org.apache.bcel.util.Args;
25  
26  /**
27   * This class represents a local variable within a method. It contains its scope, name, signature and index on the
28   * method's frame. It is used both to represent an element of the LocalVariableTable as well as an element of the
29   * LocalVariableTypeTable. The nomenclature used here may be a bit confusing; while the two items have the same layout
30   * in a class file, a LocalVariableTable attribute contains a descriptor_index, not a signatureIndex. The
31   * LocalVariableTypeTable attribute does have a signatureIndex.
32   *
33   * @see org.apache.bcel.classfile.Utility for more details on the difference.
34   *
35   * @see LocalVariableTable
36   * @see LocalVariableTypeTable
37   */
38  public final class LocalVariable implements Cloneable, Node, Constants {
39  
40      static final LocalVariable[] EMPTY_ARRAY = {};
41  
42      /** Range in which the variable is valid. */
43      private int startPc;
44  
45      private int length;
46  
47      /** Index in constant pool of variable name. */
48      private int nameIndex;
49  
50      /**
51       * Technically, a decscriptor_index for a local variable table entry and a signatureIndex for a local variable type table entry. Index of variable signature
52       */
53      private int signatureIndex;
54  
55      /*
56       * Variable is index'th local variable on this method's frame.
57       */
58      private int index;
59  
60      private ConstantPool constantPool;
61  
62      /** Never changes; used to match up with LocalVariableTypeTable entries. */
63      private final int origIndex;
64  
65      /**
66       * Constructs object from file stream.
67       *
68       * @param file Input stream
69       * @throws IOException if an I/O error occurs.
70       */
71      LocalVariable(final DataInput file, final ConstantPool constantPool) throws IOException {
72          this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), constantPool);
73      }
74  
75      /**
76       * @param startPc Range in which the variable
77       * @param length ... is valid
78       * @param nameIndex Index in constant pool of variable name
79       * @param signatureIndex Index of variable's signature
80       * @param index Variable is 'index'th local variable on the method's frame
81       * @param constantPool Array of constants
82       */
83      public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
84          this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
85      }
86  
87      /**
88       * @param startPc Range in which the variable
89       * @param length ... is valid
90       * @param nameIndex Index in constant pool of variable name
91       * @param signatureIndex Index of variable's signature
92       * @param index Variable is 'index'th local variable on the method's frame
93       * @param constantPool Array of constants
94       * @param origIndex Variable is 'index'th local variable on the method's frame prior to any changes
95       */
96      public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool,
97          final int origIndex) {
98          this.startPc = Args.requireU2(startPc, "startPc");
99          this.length = Args.requireU2(length, "length");
100         this.nameIndex = Args.requireU2(nameIndex, "nameIndex");
101         this.signatureIndex = Args.requireU2(signatureIndex, "signatureIndex");
102         this.index = Args.requireU2(index, "index");
103         this.origIndex = Args.requireU2(origIndex, "origIndex");
104         this.constantPool = constantPool;
105     }
106 
107     /**
108      * Initializes from another LocalVariable. Note that both objects use the same references (shallow copy). Use copy() for
109      * a physical copy.
110      *
111      * @param localVariable Another LocalVariable.
112      */
113     public LocalVariable(final LocalVariable localVariable) {
114         this(localVariable.getStartPC(), localVariable.getLength(), localVariable.getNameIndex(), localVariable.getSignatureIndex(), localVariable.getIndex(),
115             localVariable.getConstantPool());
116     }
117 
118     /**
119      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
120      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
121      *
122      * @param v Visitor object
123      */
124     @Override
125     public void accept(final Visitor v) {
126         v.visitLocalVariable(this);
127     }
128 
129     /**
130      * @return deep copy of this object
131      */
132     public LocalVariable copy() {
133         try {
134             return (LocalVariable) clone();
135         } catch (final CloneNotSupportedException e) {
136             // TODO should this throw?
137         }
138         return null;
139     }
140 
141     /**
142      * Dumps local variable to file stream in binary format.
143      *
144      * @param dataOutputStream Output file stream
145      * @throws IOException if an I/O error occurs.
146      * @see java.io.FilterOutputStream#out
147      */
148     public void dump(final DataOutputStream dataOutputStream) throws IOException {
149         dataOutputStream.writeShort(startPc);
150         dataOutputStream.writeShort(length);
151         dataOutputStream.writeShort(nameIndex);
152         dataOutputStream.writeShort(signatureIndex);
153         dataOutputStream.writeShort(index);
154     }
155 
156     /**
157      * @return Constant pool used by this object.
158      */
159     public ConstantPool getConstantPool() {
160         return constantPool;
161     }
162 
163     /**
164      * @return index of register where variable is stored
165      */
166     public int getIndex() {
167         return index;
168     }
169 
170     /**
171      * @return Variable is valid within getStartPC() .. getStartPC()+getLength()
172      */
173     public int getLength() {
174         return length;
175     }
176 
177     /**
178      * @return Variable name.
179      */
180     public String getName() {
181         return constantPool.getConstantUtf8(nameIndex).getBytes();
182     }
183 
184     /**
185      * @return Index in constant pool of variable name.
186      */
187     public int getNameIndex() {
188         return nameIndex;
189     }
190 
191     /**
192      * @return index of register where variable was originally stored
193      */
194     public int getOrigIndex() {
195         return origIndex;
196     }
197 
198     /**
199      * @return Signature.
200      */
201     public String getSignature() {
202         return constantPool.getConstantUtf8(signatureIndex).getBytes();
203     }
204 
205     /**
206      * @return Index in constant pool of variable signature.
207      */
208     public int getSignatureIndex() {
209         return signatureIndex;
210     }
211 
212     /**
213      * @return Start of range where the variable is valid
214      */
215     public int getStartPC() {
216         return startPc;
217     }
218 
219     /**
220      * @param constantPool Constant pool to be used for this object.
221      */
222     public void setConstantPool(final ConstantPool constantPool) {
223         this.constantPool = constantPool;
224     }
225 
226     /**
227      * @param index the index in the local variable table of this variable
228      */
229     public void setIndex(final int index) { // TODO unused
230         this.index = index;
231     }
232 
233     /**
234      * @param length the length of this local variable
235      */
236     public void setLength(final int length) {
237         this.length = length;
238     }
239 
240     /**
241      * @param nameIndex the index into the constant pool for the name of this variable
242      */
243     public void setNameIndex(final int nameIndex) { // TODO unused
244         this.nameIndex = nameIndex;
245     }
246 
247     /**
248      * @param signatureIndex the index into the constant pool for the signature of this variable
249      */
250     public void setSignatureIndex(final int signatureIndex) { // TODO unused
251         this.signatureIndex = signatureIndex;
252     }
253 
254     /**
255      * @param startPc Specify range where the local variable is valid.
256      */
257     public void setStartPC(final int startPc) { // TODO unused
258         this.startPc = startPc;
259     }
260 
261     /**
262      * @return string representation.
263      */
264     @Override
265     public String toString() {
266         return toStringShared(false);
267     }
268 
269     /*
270      * Helper method shared with LocalVariableTypeTable
271      */
272     String toStringShared(final boolean typeTable) {
273         final String name = getName();
274         final String signature = Utility.signatureToString(getSignature(), false);
275         final String label = "LocalVariable" + (typeTable ? "Types" : "");
276         return label + "(startPc = " + startPc + ", length = " + length + ", index = " + index + ":" + signature + " " + name + ")";
277     }
278 }