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