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