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 
  26 package com.sun.tools.javap;
  27 
  28 import com.sun.tools.classfile.Annotation;
  29 import com.sun.tools.classfile.TypeAnnotation;
  30 import com.sun.tools.classfile.Annotation.Annotation_element_value;
  31 import com.sun.tools.classfile.Annotation.Array_element_value;
  32 import com.sun.tools.classfile.Annotation.Class_element_value;
  33 import com.sun.tools.classfile.Annotation.Enum_element_value;
  34 import com.sun.tools.classfile.Annotation.Primitive_element_value;
  35 import com.sun.tools.classfile.ConstantPool;
  36 import com.sun.tools.classfile.ConstantPoolException;
  37 import com.sun.tools.classfile.Descriptor;
  38 import 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  */
  48 public 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 }