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 */
017package org.apache.bcel.verifier.statics;
018
019import org.apache.bcel.classfile.AnnotationDefault;
020import org.apache.bcel.classfile.AnnotationEntry;
021import org.apache.bcel.classfile.Annotations;
022import org.apache.bcel.classfile.BootstrapMethods;
023import org.apache.bcel.classfile.Code;
024import org.apache.bcel.classfile.CodeException;
025import org.apache.bcel.classfile.ConstantClass;
026import org.apache.bcel.classfile.ConstantDouble;
027import org.apache.bcel.classfile.ConstantDynamic;
028import org.apache.bcel.classfile.ConstantFieldref;
029import org.apache.bcel.classfile.ConstantFloat;
030import org.apache.bcel.classfile.ConstantInteger;
031import org.apache.bcel.classfile.ConstantInterfaceMethodref;
032import org.apache.bcel.classfile.ConstantInvokeDynamic;
033import org.apache.bcel.classfile.ConstantLong;
034import org.apache.bcel.classfile.ConstantMethodHandle;
035import org.apache.bcel.classfile.ConstantMethodType;
036import org.apache.bcel.classfile.ConstantMethodref;
037import org.apache.bcel.classfile.ConstantModule;
038import org.apache.bcel.classfile.ConstantNameAndType;
039import org.apache.bcel.classfile.ConstantPackage;
040import org.apache.bcel.classfile.ConstantPool;
041import org.apache.bcel.classfile.ConstantString;
042import org.apache.bcel.classfile.ConstantUtf8;
043import org.apache.bcel.classfile.ConstantValue;
044import org.apache.bcel.classfile.Deprecated;
045import org.apache.bcel.classfile.EnclosingMethod;
046import org.apache.bcel.classfile.ExceptionTable;
047import org.apache.bcel.classfile.Field;
048import org.apache.bcel.classfile.InnerClass;
049import org.apache.bcel.classfile.InnerClasses;
050import org.apache.bcel.classfile.JavaClass;
051import org.apache.bcel.classfile.LineNumber;
052import org.apache.bcel.classfile.LineNumberTable;
053import org.apache.bcel.classfile.LocalVariable;
054import org.apache.bcel.classfile.LocalVariableTable;
055import org.apache.bcel.classfile.LocalVariableTypeTable;
056import org.apache.bcel.classfile.Method;
057import org.apache.bcel.classfile.MethodParameters;
058import org.apache.bcel.classfile.NestMembers;
059import org.apache.bcel.classfile.Node;
060import org.apache.bcel.classfile.ParameterAnnotationEntry;
061import org.apache.bcel.classfile.ParameterAnnotations;
062import org.apache.bcel.classfile.Record;
063import org.apache.bcel.classfile.RecordComponentInfo;
064import org.apache.bcel.classfile.Signature;
065import org.apache.bcel.classfile.SourceFile;
066import org.apache.bcel.classfile.StackMap;
067import org.apache.bcel.classfile.StackMapEntry;
068import org.apache.bcel.classfile.Synthetic;
069import org.apache.bcel.classfile.Unknown;
070import org.apache.bcel.verifier.exc.AssertionViolatedException;
071
072/**
073 * BCEL's Node classes (those from the classfile API that <B>accept()</B> Visitor instances) have <B>toString()</B>
074 * methods that were not designed to be robust, this gap is closed by this class. When performing class file
075 * verification, it may be useful to output which entity (e.g. a <B>Code</B> instance) is not satisfying the verifier's
076 * constraints, but in this case it could be possible for the <B>toString()</B> method to throw a RuntimeException. A
077 * (new StringRepresentation(Node n)).toString() never throws any exception. Note that this class also serves as a
078 * placeholder for more sophisticated message handling in future versions of JustIce.
079 */
080public class StringRepresentation extends org.apache.bcel.classfile.EmptyVisitor {
081    /** The string representation, created by a visitXXX() method, output by toString(). */
082    private String tostring;
083    /** The node we ask for its string representation. Not really needed; only for debug output. */
084    private final Node n;
085
086    /**
087     * Creates a new StringRepresentation object which is the representation of n.
088     *
089     * @param n The node to represent.
090     * @see #toString()
091     */
092    public StringRepresentation(final Node n) {
093        this.n = n;
094        n.accept(this); // assign a string representation to field 'tostring' if we know n's class.
095    }
096
097    /**
098     * Returns the String representation.
099     */
100    @Override
101    public String toString() {
102// The run-time check below is needed because we don't want to omit inheritance
103// of "EmptyVisitor" and provide a thousand empty methods.
104// However, in terms of performance this would be a better idea.
105// If some new "Node" is defined in BCEL (such as some concrete "Attribute"), we
106// want to know that this class has also to be adapted.
107        if (tostring == null) {
108            throw new AssertionViolatedException("Please adapt '" + getClass() + "' to deal with objects of class '" + n.getClass() + "'.");
109        }
110        return tostring;
111    }
112
113    /**
114     * Returns the String representation of the Node object obj; this is obj.toString() if it does not throw any
115     * RuntimeException, or else it is a string derived only from obj's class name.
116     */
117    private String toString(final Node obj) {
118        String ret;
119        try {
120            ret = obj.toString();
121        }
122
123        catch (final RuntimeException e) {
124            // including ClassFormatException, trying to convert the "signature" of a ReturnaddressType LocalVariable
125            // (shouldn't occur, but people do crazy things)
126            String s = obj.getClass().getName();
127            s = s.substring(s.lastIndexOf(".") + 1);
128            ret = "<<" + s + ">>";
129        }
130        return ret;
131    }
132
133    /**
134     * @since 6.0
135     */
136    @Override
137    public void visitAnnotation(final Annotations obj) {
138        // this is invoked whenever an annotation is found
139        // when verifier is passed over a class
140        tostring = toString(obj);
141    }
142
143    /**
144     * @since 6.0
145     */
146    @Override
147    public void visitAnnotationDefault(final AnnotationDefault obj) {
148        tostring = toString(obj);
149    }
150
151    /**
152     * @since 6.0
153     */
154    @Override
155    public void visitAnnotationEntry(final AnnotationEntry obj) {
156        tostring = toString(obj);
157    }
158
159    /**
160     * @since 6.0
161     */
162    @Override
163    public void visitBootstrapMethods(final BootstrapMethods obj) {
164        tostring = toString(obj);
165    }
166
167    ////////////////////////////////
168    // Visitor methods start here //
169    ////////////////////////////////
170    // We don't of course need to call some default implementation:
171    // e.g. we could also simply output "Code" instead of a possibly
172    // lengthy Code attribute's toString().
173    @Override
174    public void visitCode(final Code obj) {
175        // tostring = toString(obj);
176        tostring = "<CODE>"; // We don't need real code outputs.
177    }
178
179    @Override
180    public void visitCodeException(final CodeException obj) {
181        tostring = toString(obj);
182    }
183
184    @Override
185    public void visitConstantClass(final ConstantClass obj) {
186        tostring = toString(obj);
187    }
188
189    @Override
190    public void visitConstantDouble(final ConstantDouble obj) {
191        tostring = toString(obj);
192    }
193
194    /**
195     * @since 6.6.0
196     */
197    @Override
198    public void visitConstantDynamic(final ConstantDynamic obj) {
199        tostring = toString(obj);
200    }
201
202    @Override
203    public void visitConstantFieldref(final ConstantFieldref obj) {
204        tostring = toString(obj);
205    }
206
207    @Override
208    public void visitConstantFloat(final ConstantFloat obj) {
209        tostring = toString(obj);
210    }
211
212    @Override
213    public void visitConstantInteger(final ConstantInteger obj) {
214        tostring = toString(obj);
215    }
216
217    @Override
218    public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref obj) {
219        tostring = toString(obj);
220    }
221
222    /**
223     * @since 6.0
224     */
225    @Override
226    public void visitConstantInvokeDynamic(final ConstantInvokeDynamic obj) {
227        tostring = toString(obj);
228    }
229
230    @Override
231    public void visitConstantLong(final ConstantLong obj) {
232        tostring = toString(obj);
233    }
234
235    /**
236     * @since 6.0
237     */
238    @Override
239    public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
240        tostring = toString(obj);
241    }
242
243    @Override
244    public void visitConstantMethodref(final ConstantMethodref obj) {
245        tostring = toString(obj);
246    }
247
248    /**
249     * @since 6.0
250     */
251    @Override
252    public void visitConstantMethodType(final ConstantMethodType obj) {
253        tostring = toString(obj);
254    }
255
256    /**
257     * @since 6.6.0
258     */
259    @Override
260    public void visitConstantModule(final ConstantModule obj) {
261        tostring = toString(obj);
262    }
263
264    @Override
265    public void visitConstantNameAndType(final ConstantNameAndType obj) {
266        tostring = toString(obj);
267    }
268
269    /**
270     * @since 6.6.0
271     */
272    @Override
273    public void visitConstantPackage(final ConstantPackage obj) {
274        tostring = toString(obj);
275    }
276
277    @Override
278    public void visitConstantPool(final ConstantPool obj) {
279        tostring = toString(obj);
280    }
281
282    @Override
283    public void visitConstantString(final ConstantString obj) {
284        tostring = toString(obj);
285    }
286
287    @Override
288    public void visitConstantUtf8(final ConstantUtf8 obj) {
289        tostring = toString(obj);
290    }
291
292    @Override
293    public void visitConstantValue(final ConstantValue obj) {
294        tostring = toString(obj);
295    }
296
297    @Override
298    public void visitDeprecated(final Deprecated obj) {
299        tostring = toString(obj);
300    }
301
302    /**
303     * @since 6.0
304     */
305    @Override
306    public void visitEnclosingMethod(final EnclosingMethod obj) {
307        tostring = toString(obj);
308    }
309
310    @Override
311    public void visitExceptionTable(final ExceptionTable obj) {
312        tostring = toString(obj);
313    }
314
315    @Override
316    public void visitField(final Field obj) {
317        tostring = toString(obj);
318    }
319
320    @Override
321    public void visitInnerClass(final InnerClass obj) {
322        tostring = toString(obj);
323    }
324
325    @Override
326    public void visitInnerClasses(final InnerClasses obj) {
327        tostring = toString(obj);
328    }
329
330    @Override
331    public void visitJavaClass(final JavaClass obj) {
332        tostring = toString(obj);
333    }
334
335    @Override
336    public void visitLineNumber(final LineNumber obj) {
337        tostring = toString(obj);
338    }
339
340    @Override
341    public void visitLineNumberTable(final LineNumberTable obj) {
342        tostring = "<LineNumberTable: " + toString(obj) + ">";
343    }
344
345    @Override
346    public void visitLocalVariable(final LocalVariable obj) {
347        tostring = toString(obj);
348    }
349
350    @Override
351    public void visitLocalVariableTable(final LocalVariableTable obj) {
352        tostring = "<LocalVariableTable: " + toString(obj) + ">";
353    }
354
355    /**
356     * @since 6.0
357     */
358    @Override
359    public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
360        // this is invoked whenever a local variable type is found
361        // when verifier is passed over a class
362        tostring = toString(obj);
363    }
364
365    @Override
366    public void visitMethod(final Method obj) {
367        tostring = toString(obj);
368    }
369
370    /**
371     * @since 6.0
372     */
373    @Override
374    public void visitMethodParameters(final MethodParameters obj) {
375        tostring = toString(obj);
376    }
377
378    /**
379     * @since 6.4.0
380     */
381    @Override
382    public void visitNestMembers(final NestMembers obj) {
383        tostring = toString(obj);
384    }
385
386    /**
387     * @since 6.0
388     */
389    @Override
390    public void visitParameterAnnotation(final ParameterAnnotations obj) {
391        tostring = toString(obj);
392    }
393
394    /**
395     * @since 6.0
396     */
397    @Override
398    public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
399        tostring = toString(obj);
400    }
401
402    @Override
403    public void visitRecord(final Record obj) {
404        tostring = toString(obj);
405    }
406
407    @Override
408    public void visitRecordComponent(final RecordComponentInfo obj) {
409        tostring = toString(obj);
410    }
411
412    @Override
413    public void visitSignature(final Signature obj) {
414        tostring = toString(obj);
415    }
416
417    @Override
418    public void visitSourceFile(final SourceFile obj) {
419        tostring = toString(obj);
420    }
421
422    @Override
423    public void visitStackMap(final StackMap obj) {
424        tostring = toString(obj);
425    }
426
427    /**
428     * @since 6.0
429     */
430    @Override
431    public void visitStackMapEntry(final StackMapEntry obj) {
432        tostring = toString(obj);
433    }
434
435    @Override
436    public void visitSynthetic(final Synthetic obj) {
437        tostring = toString(obj);
438    }
439
440    @Override
441    public void visitUnknown(final Unknown obj) {
442        tostring = toString(obj);
443    }
444
445}