1/*
2 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javap;
27
28import com.sun.tools.classfile.Annotation;
29import com.sun.tools.classfile.TypeAnnotation;
30import com.sun.tools.classfile.Annotation.Annotation_element_value;
31import com.sun.tools.classfile.Annotation.Array_element_value;
32import com.sun.tools.classfile.Annotation.Class_element_value;
33import com.sun.tools.classfile.Annotation.Enum_element_value;
34import com.sun.tools.classfile.Annotation.Primitive_element_value;
35import com.sun.tools.classfile.ConstantPool;
36import com.sun.tools.classfile.ConstantPoolException;
37import com.sun.tools.classfile.Descriptor;
38import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
39
40/**
41 *  A writer for writing annotations as text.
42 *
43 *  <p><b>This is NOT part of any supported API.
44 *  If you write code that depends on this, you do so at your own risk.
45 *  This code and its internal interfaces are subject to change or
46 *  deletion without notice.</b>
47 */
48public class AnnotationWriter extends BasicWriter {
49    static AnnotationWriter instance(Context context) {
50        AnnotationWriter instance = context.get(AnnotationWriter.class);
51        if (instance == null)
52            instance = new AnnotationWriter(context);
53        return instance;
54    }
55
56    protected AnnotationWriter(Context context) {
57        super(context);
58        classWriter = ClassWriter.instance(context);
59        constantWriter = ConstantWriter.instance(context);
60    }
61
62    public void write(Annotation annot) {
63        write(annot, false);
64    }
65
66    public void write(Annotation annot, boolean resolveIndices) {
67        writeDescriptor(annot.type_index, resolveIndices);
68        boolean showParens = annot.num_element_value_pairs > 0 || !resolveIndices;
69        if (showParens)
70            print("(");
71        for (int i = 0; i < annot.num_element_value_pairs; i++) {
72            if (i > 0)
73                print(",");
74            write(annot.element_value_pairs[i], resolveIndices);
75        }
76        if (showParens)
77            print(")");
78    }
79
80    public void write(TypeAnnotation annot) {
81        write(annot, true, false);
82    }
83
84    public void write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices) {
85        write(annot.annotation, resolveIndices);
86        print(": ");
87        write(annot.position, showOffsets);
88    }
89
90    public void write(TypeAnnotation.Position pos, boolean showOffsets) {
91        print(pos.type);
92
93        switch (pos.type) {
94        // instanceof
95        case INSTANCEOF:
96        // new expression
97        case NEW:
98        // constructor/method reference receiver
99        case CONSTRUCTOR_REFERENCE:
100        case METHOD_REFERENCE:
101            if (showOffsets) {
102                print(", offset=");
103                print(pos.offset);
104            }
105            break;
106        // local variable
107        case LOCAL_VARIABLE:
108        // resource variable
109        case RESOURCE_VARIABLE:
110            if (pos.lvarOffset == null) {
111                print(", lvarOffset is Null!");
112                break;
113            }
114            print(", {");
115            for (int i = 0; i < pos.lvarOffset.length; ++i) {
116                if (i != 0) print("; ");
117                if (showOffsets) {
118                    print("start_pc=");
119                    print(pos.lvarOffset[i]);
120                }
121                print(", length=");
122                print(pos.lvarLength[i]);
123                print(", index=");
124                print(pos.lvarIndex[i]);
125            }
126            print("}");
127            break;
128        // exception parameter
129        case EXCEPTION_PARAMETER:
130            print(", exception_index=");
131            print(pos.exception_index);
132            break;
133        // method receiver
134        case METHOD_RECEIVER:
135            // Do nothing
136            break;
137        // type parameter
138        case CLASS_TYPE_PARAMETER:
139        case METHOD_TYPE_PARAMETER:
140            print(", param_index=");
141            print(pos.parameter_index);
142            break;
143        // type parameter bound
144        case CLASS_TYPE_PARAMETER_BOUND:
145        case METHOD_TYPE_PARAMETER_BOUND:
146            print(", param_index=");
147            print(pos.parameter_index);
148            print(", bound_index=");
149            print(pos.bound_index);
150            break;
151        // class extends or implements clause
152        case CLASS_EXTENDS:
153            print(", type_index=");
154            print(pos.type_index);
155            break;
156        // throws
157        case THROWS:
158            print(", type_index=");
159            print(pos.type_index);
160            break;
161        // method parameter
162        case METHOD_FORMAL_PARAMETER:
163            print(", param_index=");
164            print(pos.parameter_index);
165            break;
166        // type cast
167        case CAST:
168        // method/constructor/reference type argument
169        case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
170        case METHOD_INVOCATION_TYPE_ARGUMENT:
171        case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
172        case METHOD_REFERENCE_TYPE_ARGUMENT:
173            if (showOffsets) {
174                print(", offset=");
175                print(pos.offset);
176            }
177            print(", type_index=");
178            print(pos.type_index);
179            break;
180        // We don't need to worry about these
181        case METHOD_RETURN:
182        case FIELD:
183            break;
184        case UNKNOWN:
185            throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!");
186        default:
187            throw new AssertionError("AnnotationWriter: Unknown target type for position: " + pos);
188        }
189
190        // Append location data for generics/arrays.
191        if (!pos.location.isEmpty()) {
192            print(", location=");
193            print(pos.location);
194        }
195    }
196
197    public void write(Annotation.element_value_pair pair) {
198        write(pair, false);
199    }
200
201    public void write(Annotation.element_value_pair pair, boolean resolveIndices) {
202        writeIndex(pair.element_name_index, resolveIndices);
203        print("=");
204        write(pair.value, resolveIndices);
205    }
206
207    public void write(Annotation.element_value value) {
208        write(value, false);
209    }
210
211    public void write(Annotation.element_value value, boolean resolveIndices) {
212        ev_writer.write(value, resolveIndices);
213    }
214
215    private void writeDescriptor(int index, boolean resolveIndices) {
216        if (resolveIndices) {
217            try {
218                ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
219                Descriptor d = new Descriptor(index);
220                print(d.getFieldType(constant_pool));
221                return;
222            } catch (ConstantPoolException | InvalidDescriptor ignore) {
223            }
224        }
225
226        print("#" + index);
227    }
228
229    private void writeIndex(int index, boolean resolveIndices) {
230        if (resolveIndices) {
231            print(constantWriter.stringValue(index));
232        } else
233            print("#" + index);
234    }
235
236    element_value_Writer ev_writer = new element_value_Writer();
237
238    class element_value_Writer implements Annotation.element_value.Visitor<Void,Boolean> {
239        public void write(Annotation.element_value value, boolean resolveIndices) {
240            value.accept(this, resolveIndices);
241        }
242
243        public Void visitPrimitive(Primitive_element_value ev, Boolean resolveIndices) {
244            if (resolveIndices)
245                writeIndex(ev.const_value_index, resolveIndices);
246            else
247                print(((char) ev.tag) + "#" + ev.const_value_index);
248            return null;
249        }
250
251        public Void visitEnum(Enum_element_value ev, Boolean resolveIndices) {
252            if (resolveIndices) {
253                writeIndex(ev.type_name_index, resolveIndices);
254                print(".");
255                writeIndex(ev.const_name_index, resolveIndices);
256            } else
257                print(((char) ev.tag) + "#" + ev.type_name_index + ".#" + ev.const_name_index);
258            return null;
259        }
260
261        public Void visitClass(Class_element_value ev, Boolean resolveIndices) {
262            if (resolveIndices) {
263                writeIndex(ev.class_info_index, resolveIndices);
264                print(".class");
265            } else
266                print(((char) ev.tag) + "#" + ev.class_info_index);
267            return null;
268        }
269
270        public Void visitAnnotation(Annotation_element_value ev, Boolean resolveIndices) {
271            print((char) ev.tag);
272            AnnotationWriter.this.write(ev.annotation_value, resolveIndices);
273            return null;
274        }
275
276        public Void visitArray(Array_element_value ev, Boolean resolveIndices) {
277            print("[");
278            for (int i = 0; i < ev.num_values; i++) {
279                if (i > 0)
280                    print(",");
281                write(ev.values[i], resolveIndices);
282            }
283            print("]");
284            return null;
285        }
286
287    }
288
289    private ClassWriter classWriter;
290    private ConstantWriter constantWriter;
291}
292