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.classfile;
019    
020    import java.util.Stack;
021    
022    /**
023     * Traverses a JavaClass with another Visitor object 'piggy-backed' that is
024     * applied to all components of a JavaClass object. I.e. this class supplies the
025     * traversal strategy, other classes can make use of it.
026     * 
027     * @version $Id: DescendingVisitor.java 1149459 2011-07-22 04:34:27Z dbrosius $
028     * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
029     */
030    public class DescendingVisitor implements Visitor
031    {
032            private JavaClass clazz;
033    
034            private Visitor visitor;
035    
036            private Stack<Object> stack = new Stack<Object>();
037    
038            /**
039             * @return container of current entitity, i.e., predecessor during traversal
040             */
041            public Object predecessor()
042            {
043                    return predecessor(0);
044            }
045    
046            /**
047             * @param level
048             *            nesting level, i.e., 0 returns the direct predecessor
049             * @return container of current entitity, i.e., predecessor during traversal
050             */
051            public Object predecessor(int level)
052            {
053                    int size = stack.size();
054                    if ((size < 2) || (level < 0))
055                    {
056                            return null;
057                    }
058                    else
059                    {
060                            return stack.elementAt(size - (level + 2)); // size - 1 == current
061                    }
062            }
063    
064            /**
065             * @return current object
066             */
067            public Object current()
068            {
069                    return stack.peek();
070            }
071    
072            /**
073             * @param clazz
074             *            Class to traverse
075             * @param visitor
076             *            visitor object to apply to all components
077             */
078            public DescendingVisitor(JavaClass clazz, Visitor visitor)
079            {
080                    this.clazz = clazz;
081                    this.visitor = visitor;
082            }
083    
084            /**
085             * Start traversal.
086             */
087            public void visit()
088            {
089                    clazz.accept(this);
090            }
091    
092            public void visitJavaClass(JavaClass _clazz)
093            {
094                    stack.push(_clazz);
095                    _clazz.accept(visitor);
096                    Field[] fields = _clazz.getFields();
097                    for (int i = 0; i < fields.length; i++)
098                    {
099                            fields[i].accept(this);
100                    }
101                    Method[] methods = _clazz.getMethods();
102                    for (int i = 0; i < methods.length; i++)
103                    {
104                            methods[i].accept(this);
105                    }
106                    Attribute[] attributes = _clazz.getAttributes();
107                    for (int i = 0; i < attributes.length; i++)
108                    {
109                            attributes[i].accept(this);
110                    }
111                    _clazz.getConstantPool().accept(this);
112                    stack.pop();
113            }
114    
115            public void visitAnnotation(Annotations annotation)
116            {
117                    stack.push(annotation);
118                    annotation.accept(visitor);
119                    AnnotationEntry[] entries = annotation.getAnnotationEntries();
120                    for (int i = 0; i < entries.length; i++)
121                    {
122                            entries[i].accept(this);
123                    }
124                    stack.pop();
125            }
126    
127            public void visitAnnotationEntry(AnnotationEntry annotationEntry)
128            {
129                    stack.push(annotationEntry);
130                    annotationEntry.accept(visitor);
131                    stack.pop();
132            }
133    
134            public void visitField(Field field)
135            {
136                    stack.push(field);
137                    field.accept(visitor);
138                    Attribute[] attributes = field.getAttributes();
139                    for (int i = 0; i < attributes.length; i++)
140                    {
141                            attributes[i].accept(this);
142                    }
143                    stack.pop();
144            }
145    
146            public void visitConstantValue(ConstantValue cv)
147            {
148                    stack.push(cv);
149                    cv.accept(visitor);
150                    stack.pop();
151            }
152    
153            public void visitMethod(Method method)
154            {
155                    stack.push(method);
156                    method.accept(visitor);
157                    Attribute[] attributes = method.getAttributes();
158                    for (int i = 0; i < attributes.length; i++)
159                    {
160                            attributes[i].accept(this);
161                    }
162                    stack.pop();
163            }
164    
165            public void visitExceptionTable(ExceptionTable table)
166            {
167                    stack.push(table);
168                    table.accept(visitor);
169                    stack.pop();
170            }
171    
172            public void visitCode(Code code)
173            {
174                    stack.push(code);
175                    code.accept(visitor);
176                    CodeException[] table = code.getExceptionTable();
177                    for (int i = 0; i < table.length; i++)
178                    {
179                            table[i].accept(this);
180                    }
181                    Attribute[] attributes = code.getAttributes();
182                    for (int i = 0; i < attributes.length; i++)
183                    {
184                            attributes[i].accept(this);
185                    }
186                    stack.pop();
187            }
188    
189            public void visitCodeException(CodeException ce)
190            {
191                    stack.push(ce);
192                    ce.accept(visitor);
193                    stack.pop();
194            }
195    
196            public void visitLineNumberTable(LineNumberTable table)
197            {
198                    stack.push(table);
199                    table.accept(visitor);
200                    LineNumber[] numbers = table.getLineNumberTable();
201                    for (int i = 0; i < numbers.length; i++)
202                    {
203                            numbers[i].accept(this);
204                    }
205                    stack.pop();
206            }
207    
208            public void visitLineNumber(LineNumber number)
209            {
210                    stack.push(number);
211                    number.accept(visitor);
212                    stack.pop();
213            }
214    
215            public void visitLocalVariableTable(LocalVariableTable table)
216            {
217                    stack.push(table);
218                    table.accept(visitor);
219                    LocalVariable[] vars = table.getLocalVariableTable();
220                    for (int i = 0; i < vars.length; i++)
221                    {
222                            vars[i].accept(this);
223                    }
224                    stack.pop();
225            }
226    
227            public void visitStackMap(StackMap table)
228            {
229                    stack.push(table);
230                    table.accept(visitor);
231                    StackMapEntry[] vars = table.getStackMap();
232                    for (int i = 0; i < vars.length; i++)
233                    {
234                            vars[i].accept(this);
235                    }
236                    stack.pop();
237            }
238    
239            public void visitStackMapEntry(StackMapEntry var)
240            {
241                    stack.push(var);
242                    var.accept(visitor);
243                    stack.pop();
244            }
245    
246            public void visitStackMapTable(StackMapTable table)
247            {
248                    stack.push(table);
249                    table.accept(visitor);
250                    StackMapTableEntry[] vars = table.getStackMapTable();
251                    for (int i = 0; i < vars.length; i++)
252                    {
253                            vars[i].accept(this);
254                    }
255                    stack.pop();
256            }
257    
258            public void visitStackMapTableEntry(StackMapTableEntry var)
259            {
260                    stack.push(var);
261                    var.accept(visitor);
262                    stack.pop();
263            }
264    
265            public void visitLocalVariable(LocalVariable var)
266            {
267                    stack.push(var);
268                    var.accept(visitor);
269                    stack.pop();
270            }
271    
272            public void visitConstantPool(ConstantPool cp)
273            {
274                    stack.push(cp);
275                    cp.accept(visitor);
276                    Constant[] constants = cp.getConstantPool();
277                    for (int i = 1; i < constants.length; i++)
278                    {
279                            if (constants[i] != null)
280                            {
281                                    constants[i].accept(this);
282                            }
283                    }
284                    stack.pop();
285            }
286    
287            public void visitConstantClass(ConstantClass constant)
288            {
289                    stack.push(constant);
290                    constant.accept(visitor);
291                    stack.pop();
292            }
293    
294            public void visitConstantDouble(ConstantDouble constant)
295            {
296                    stack.push(constant);
297                    constant.accept(visitor);
298                    stack.pop();
299            }
300    
301            public void visitConstantFieldref(ConstantFieldref constant)
302            {
303                    stack.push(constant);
304                    constant.accept(visitor);
305                    stack.pop();
306            }
307    
308            public void visitConstantFloat(ConstantFloat constant)
309            {
310                    stack.push(constant);
311                    constant.accept(visitor);
312                    stack.pop();
313            }
314    
315            public void visitConstantInteger(ConstantInteger constant)
316            {
317                    stack.push(constant);
318                    constant.accept(visitor);
319                    stack.pop();
320            }
321    
322            public void visitConstantInterfaceMethodref(
323                            ConstantInterfaceMethodref constant)
324            {
325                    stack.push(constant);
326                    constant.accept(visitor);
327                    stack.pop();
328            }
329    
330            public void visitConstantLong(ConstantLong constant)
331            {
332                    stack.push(constant);
333                    constant.accept(visitor);
334                    stack.pop();
335            }
336    
337            public void visitConstantMethodref(ConstantMethodref constant)
338            {
339                    stack.push(constant);
340                    constant.accept(visitor);
341                    stack.pop();
342            }
343    
344            public void visitConstantNameAndType(ConstantNameAndType constant)
345            {
346                    stack.push(constant);
347                    constant.accept(visitor);
348                    stack.pop();
349            }
350    
351            public void visitConstantString(ConstantString constant)
352            {
353                    stack.push(constant);
354                    constant.accept(visitor);
355                    stack.pop();
356            }
357    
358            public void visitConstantUtf8(ConstantUtf8 constant)
359            {
360                    stack.push(constant);
361                    constant.accept(visitor);
362                    stack.pop();
363            }
364    
365            public void visitInnerClasses(InnerClasses ic)
366            {
367                    stack.push(ic);
368                    ic.accept(visitor);
369                    InnerClass[] ics = ic.getInnerClasses();
370                    for (int i = 0; i < ics.length; i++)
371                    {
372                            ics[i].accept(this);
373                    }
374                    stack.pop();
375            }
376    
377            public void visitInnerClass(InnerClass inner)
378            {
379                    stack.push(inner);
380                    inner.accept(visitor);
381                    stack.pop();
382            }
383    
384            public void visitDeprecated(Deprecated attribute)
385            {
386                    stack.push(attribute);
387                    attribute.accept(visitor);
388                    stack.pop();
389            }
390    
391            public void visitSignature(Signature attribute)
392            {
393                    stack.push(attribute);
394                    attribute.accept(visitor);
395                    stack.pop();
396            }
397    
398            public void visitSourceFile(SourceFile attribute)
399            {
400                    stack.push(attribute);
401                    attribute.accept(visitor);
402                    stack.pop();
403            }
404    
405            public void visitSynthetic(Synthetic attribute)
406            {
407                    stack.push(attribute);
408                    attribute.accept(visitor);
409                    stack.pop();
410            }
411    
412            public void visitUnknown(Unknown attribute)
413            {
414                    stack.push(attribute);
415                    attribute.accept(visitor);
416                    stack.pop();
417            }
418    
419            public void visitAnnotationDefault(AnnotationDefault obj)
420            {
421                    stack.push(obj);
422                    obj.accept(visitor);
423                    stack.pop();
424            }
425    
426            public void visitEnclosingMethod(EnclosingMethod obj)
427            {
428                    stack.push(obj);
429                    obj.accept(visitor);
430                    stack.pop();
431            }
432    
433            public void visitLocalVariableTypeTable(LocalVariableTypeTable obj)
434            {
435                    stack.push(obj);
436                    obj.accept(visitor);
437                    stack.pop();
438            }
439    
440            public void visitParameterAnnotation(ParameterAnnotations obj)
441            {
442                    stack.push(obj);
443                    obj.accept(visitor);
444                    stack.pop();
445            }
446    }