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