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