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         // type cast
  95         case CAST:
  96         // instanceof
  97         case INSTANCEOF:
  98         // new expression
  99         case NEW:
 100             if (showOffsets) {
 101                 print(", offset=");
 102                 print(pos.offset);
 103             }
 104             break;
 105         // local variable
 106         case LOCAL_VARIABLE:
 107         // resource variable
 108         case RESOURCE_VARIABLE:
 109             if (pos.lvarOffset == null) {
 110                 print(", lvarOffset is Null!");
 111                 break;
 112             }
 113             print(", {");
 114             for (int i = 0; i < pos.lvarOffset.length; ++i) {
 115                 if (i != 0) print("; ");
 116                 if (showOffsets) {
 117                     print("start_pc=");
 118                     print(pos.lvarOffset[i]);
 119                 }
 120                 print(", length=");
 121                 print(pos.lvarLength[i]);
 122                 print(", index=");
 123                 print(pos.lvarIndex[i]);
 124             }
 125             print("}");
 126             break;
 127         // exception parameter
 128         case EXCEPTION_PARAMETER:
 129             print(", exception_index=");
 130             print(pos.exception_index);
 131             break;
 132         // method receiver
 133         case METHOD_RECEIVER:
 134             // Do nothing
 135             break;
 136         // type parameter
 137         case CLASS_TYPE_PARAMETER:
 138         case METHOD_TYPE_PARAMETER:
 139             print(", param_index=");
 140             print(pos.parameter_index);
 141             break;
 142         // type parameter bound
 143         case CLASS_TYPE_PARAMETER_BOUND:
 144         case METHOD_TYPE_PARAMETER_BOUND:
 145             print(", param_index=");
 146             print(pos.parameter_index);
 147             print(", bound_index=");
 148             print(pos.bound_index);
 149             break;
 150         // class extends or implements clause
 151         case CLASS_EXTENDS:
 152             print(", type_index=");
 153             print(pos.type_index);
 154             break;
 155         // throws
 156         case THROWS:
 157             print(", type_index=");
 158             print(pos.type_index);
 159             break;
 160         // method parameter
 161         case METHOD_FORMAL_PARAMETER:
 162             print(", param_index=");
 163             print(pos.parameter_index);
 164             break;
 165         // method/constructor/reference type argument
 166         case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
 167         case METHOD_INVOCATION_TYPE_ARGUMENT:
 168         case METHOD_REFERENCE_TYPE_ARGUMENT:
 169             if (showOffsets) {
 170                 print(", offset=");
 171                 print(pos.offset);
 172             }
 173             print(", type_index=");
 174             print(pos.type_index);
 175             break;
 176         // We don't need to worry about these
 177         case METHOD_RETURN:
 178         case FIELD:
 179             break;
 180         // lambda formal parameter
 181         case LAMBDA_FORMAL_PARAMETER:
 182             print(", param_index=");
 183             print(pos.parameter_index);
 184             break;
 185         case UNKNOWN:
 186             throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!");
 187         default:
 188             throw new AssertionError("AnnotationWriter: Unknown target type for position: " + pos);
 189         }
 190 
 191         // Append location data for generics/arrays.
 192         if (!pos.location.isEmpty()) {
 193             print(", location=");
 194             print(pos.location);
 195         }
 196     }
 197 
 198     public void write(Annotation.element_value_pair pair) {
 199         write(pair, false);
 200     }
 201 
 202     public void write(Annotation.element_value_pair pair, boolean resolveIndices) {
 203         writeIndex(pair.element_name_index, resolveIndices);
 204         print("=");
 205         write(pair.value, resolveIndices);
 206     }
 207 
 208     public void write(Annotation.element_value value) {
 209         write(value, false);
 210     }
 211 
 212     public void write(Annotation.element_value value, boolean resolveIndices) {
 213         ev_writer.write(value, resolveIndices);
 214     }
 215 
 216     private void writeDescriptor(int index, boolean resolveIndices) {
 217         if (resolveIndices) {
 218             try {
 219                 ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
 220                 Descriptor d = new Descriptor(index);
 221                 print(d.getFieldType(constant_pool));
 222                 return;
 223             } catch (ConstantPoolException ignore) {
 224             } catch (InvalidDescriptor ignore) {
 225             }
 226         }
 227 
 228         print("#" + index);
 229     }
 230 
 231     private void writeIndex(int index, boolean resolveIndices) {
 232         if (resolveIndices) {
 233             print(constantWriter.stringValue(index));
 234         } else
 235             print("#" + index);
 236     }
 237 
 238     element_value_Writer ev_writer = new element_value_Writer();
 239 
 240     class element_value_Writer implements Annotation.element_value.Visitor<Void,Boolean> {
 241         public void write(Annotation.element_value value, boolean resolveIndices) {
 242             value.accept(this, resolveIndices);
 243         }
 244 
 245         public Void visitPrimitive(Primitive_element_value ev, Boolean resolveIndices) {
 246             if (resolveIndices)
 247                 writeIndex(ev.const_value_index, resolveIndices);
 248             else
 249                 print(((char) ev.tag) + "#" + ev.const_value_index);
 250             return null;
 251         }
 252 
 253         public Void visitEnum(Enum_element_value ev, Boolean resolveIndices) {
 254             if (resolveIndices) {
 255                 writeIndex(ev.type_name_index, resolveIndices);
 256                 print(".");
 257                 writeIndex(ev.const_name_index, resolveIndices);
 258             } else
 259                 print(((char) ev.tag) + "#" + ev.type_name_index + ".#" + ev.const_name_index);
 260             return null;
 261         }
 262 
 263         public Void visitClass(Class_element_value ev, Boolean resolveIndices) {
 264             if (resolveIndices) {
 265                 writeIndex(ev.class_info_index, resolveIndices);
 266                 print(".class");
 267             } else
 268                 print(((char) ev.tag) + "#" + ev.class_info_index);
 269             return null;
 270         }
 271 
 272         public Void visitAnnotation(Annotation_element_value ev, Boolean resolveIndices) {
 273             print((char) ev.tag);
 274             AnnotationWriter.this.write(ev.annotation_value, resolveIndices);
 275             return null;
 276         }
 277 
 278         public Void visitArray(Array_element_value ev, Boolean resolveIndices) {
 279             print("[");
 280             for (int i = 0; i < ev.num_values; i++) {
 281                 if (i > 0)
 282                     print(",");
 283                 write(ev.values[i], resolveIndices);
 284             }
 285             print("]");
 286             return null;
 287         }
 288 
 289     }
 290 
 291     private ClassWriter classWriter;
 292     private ConstantWriter constantWriter;
 293 }