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     */
018    package org.apache.bcel.generic;
019    
020    import org.apache.bcel.Constants;
021    import org.apache.bcel.classfile.LocalVariable;
022    
023    /** 
024     * This class represents a local variable within a method. It contains its
025     * scope, name and type. The generated LocalVariable object can be obtained
026     * with getLocalVariable which needs the instruction list and the constant
027     * pool as parameters.
028     *
029     * @version $Id: LocalVariableGen.java 1152072 2011-07-29 01:54:05Z dbrosius $
030     * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
031     * @see     LocalVariable
032     * @see     MethodGen
033     */
034    public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable,
035            java.io.Serializable {
036    
037        private static final long serialVersionUID = -3810966319065955534L;
038        private int index;
039        private String name;
040        private Type type;
041        private InstructionHandle start, end;
042    
043    
044        /**
045         * Generate a local variable that with index `index'. Note that double and long
046         * variables need two indexs. Index indices have to be provided by the user.
047         *
048         * @param index index of local variable
049         * @param name its name
050         * @param type its type
051         * @param start from where the instruction is valid (null means from the start)
052         * @param end until where the instruction is valid (null means to the end)
053         */
054        public LocalVariableGen(int index, String name, Type type, InstructionHandle start,
055                InstructionHandle end) {
056            if ((index < 0) || (index > Constants.MAX_SHORT)) {
057                throw new ClassGenException("Invalid index index: " + index);
058            }
059            this.name = name;
060            this.type = type;
061            this.index = index;
062            setStart(start);
063            setEnd(end);
064        }
065    
066    
067        /**
068         * Get LocalVariable object.
069         *
070         * This relies on that the instruction list has already been dumped to byte code or
071         * or that the `setPositions' methods has been called for the instruction list.
072         *
073         * Note that for local variables whose scope end at the last
074         * instruction of the method's code, the JVM specification is ambiguous:
075         * both a start_pc+length ending at the last instruction and
076         * start_pc+length ending at first index beyond the end of the code are
077         * valid.
078         *
079         * @param cp constant pool
080         */
081        public LocalVariable getLocalVariable( ConstantPoolGen cp ) {
082            int start_pc = start.getPosition();
083            int length = end.getPosition() - start_pc;
084            if (length > 0) {
085                length += end.getInstruction().getLength();
086            }
087            int name_index = cp.addUtf8(name);
088            int signature_index = cp.addUtf8(type.getSignature());
089            return new LocalVariable(start_pc, length, name_index, signature_index, index, cp
090                    .getConstantPool());
091        }
092    
093    
094        public void setIndex( int index ) {
095            this.index = index;
096        }
097    
098    
099        public int getIndex() {
100            return index;
101        }
102    
103    
104        public void setName( String name ) {
105            this.name = name;
106        }
107    
108    
109        public String getName() {
110            return name;
111        }
112    
113    
114        public void setType( Type type ) {
115            this.type = type;
116        }
117    
118    
119        public Type getType() {
120            return type;
121        }
122    
123    
124        public InstructionHandle getStart() {
125            return start;
126        }
127    
128    
129        public InstructionHandle getEnd() {
130            return end;
131        }
132    
133    
134        public void setStart( InstructionHandle start ) {
135            BranchInstruction.notifyTarget(this.start, start, this);
136            this.start = start;
137        }
138    
139    
140        public void setEnd( InstructionHandle end ) {
141            BranchInstruction.notifyTarget(this.end, end, this);
142            this.end = end;
143        }
144    
145    
146        /**
147         * @param old_ih old target, either start or end
148         * @param new_ih new target
149         */
150        public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) {
151            boolean targeted = false;
152            if (start == old_ih) {
153                targeted = true;
154                setStart(new_ih);
155            }
156            if (end == old_ih) {
157                targeted = true;
158                setEnd(new_ih);
159            }
160            if (!targeted) {
161                throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end
162                        + "}");
163            }
164        }
165    
166    
167        /**
168         * @return true, if ih is target of this variable
169         */
170        public boolean containsTarget( InstructionHandle ih ) {
171            return (start == ih) || (end == ih);
172        }
173    
174    
175        /** @return a hash code value for the object.
176         */
177        @Override
178        public int hashCode() {
179            //If the user changes the name or type, problems with the targeter hashmap will occur
180            int hc = index ^ name.hashCode() ^ type.hashCode();
181            return hc;
182        }
183    
184    
185        /**
186         * We consider to local variables to be equal, if the use the same index and
187         * are valid in the same range.
188         */
189        @Override
190        public boolean equals( Object o ) {
191            if (!(o instanceof LocalVariableGen)) {
192                return false;
193            }
194            LocalVariableGen l = (LocalVariableGen) o;
195            return (l.index == index) && (l.start == start) && (l.end == end);
196        }
197    
198    
199        @Override
200        public String toString() {
201            return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")";
202        }
203    
204    
205        @Override
206        public Object clone() {
207            try {
208                return super.clone();
209            } catch (CloneNotSupportedException e) {
210                System.err.println(e);
211                return null;
212            }
213        }
214    }