1 /* 2 * Copyright (c) 2007, 2017, 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 { instance(Context context)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 AnnotationWriter(Context context)56 protected AnnotationWriter(Context context) { 57 super(context); 58 classWriter = ClassWriter.instance(context); 59 constantWriter = ConstantWriter.instance(context); 60 } 61 write(Annotation annot)62 public void write(Annotation annot) { 63 write(annot, false); 64 println(); 65 indent(+1); 66 write(annot, true); 67 indent(-1); 68 } 69 write(Annotation annot, boolean resolveIndices)70 public void write(Annotation annot, boolean resolveIndices) { 71 writeDescriptor(annot.type_index, resolveIndices); 72 if (resolveIndices) { 73 boolean showParens = annot.num_element_value_pairs > 0; 74 if (showParens) { 75 println("("); 76 indent(+1); 77 } 78 for (int i = 0; i < annot.num_element_value_pairs; i++) { 79 write(annot.element_value_pairs[i], true); 80 println(); 81 } 82 if (showParens) { 83 indent(-1); 84 print(")"); 85 } 86 } else { 87 print("("); 88 for (int i = 0; i < annot.num_element_value_pairs; i++) { 89 if (i > 0) 90 print(","); 91 write(annot.element_value_pairs[i], false); 92 } 93 print(")"); 94 } 95 } 96 write(TypeAnnotation annot)97 public void write(TypeAnnotation annot) { 98 write(annot, true, false); 99 println(); 100 indent(+1); 101 write(annot.annotation, true); 102 indent(-1); 103 } 104 write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices)105 public void write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices) { 106 write(annot.annotation, resolveIndices); 107 print(": "); 108 write(annot.position, showOffsets); 109 } 110 write(TypeAnnotation.Position pos, boolean showOffsets)111 public void write(TypeAnnotation.Position pos, boolean showOffsets) { 112 print(pos.type); 113 114 switch (pos.type) { 115 // instanceof 116 case INSTANCEOF: 117 // new expression 118 case NEW: 119 // constructor/method reference receiver 120 case CONSTRUCTOR_REFERENCE: 121 case METHOD_REFERENCE: 122 if (showOffsets) { 123 print(", offset="); 124 print(pos.offset); 125 } 126 break; 127 // local variable 128 case LOCAL_VARIABLE: 129 // resource variable 130 case RESOURCE_VARIABLE: 131 if (pos.lvarOffset == null) { 132 print(", lvarOffset is Null!"); 133 break; 134 } 135 print(", {"); 136 for (int i = 0; i < pos.lvarOffset.length; ++i) { 137 if (i != 0) print("; "); 138 if (showOffsets) { 139 print("start_pc="); 140 print(pos.lvarOffset[i]); 141 } 142 print(", length="); 143 print(pos.lvarLength[i]); 144 print(", index="); 145 print(pos.lvarIndex[i]); 146 } 147 print("}"); 148 break; 149 // exception parameter 150 case EXCEPTION_PARAMETER: 151 print(", exception_index="); 152 print(pos.exception_index); 153 break; 154 // method receiver 155 case METHOD_RECEIVER: 156 // Do nothing 157 break; 158 // type parameter 159 case CLASS_TYPE_PARAMETER: 160 case METHOD_TYPE_PARAMETER: 161 print(", param_index="); 162 print(pos.parameter_index); 163 break; 164 // type parameter bound 165 case CLASS_TYPE_PARAMETER_BOUND: 166 case METHOD_TYPE_PARAMETER_BOUND: 167 print(", param_index="); 168 print(pos.parameter_index); 169 print(", bound_index="); 170 print(pos.bound_index); 171 break; 172 // class extends or implements clause 173 case CLASS_EXTENDS: 174 print(", type_index="); 175 print(pos.type_index); 176 break; 177 // throws 178 case THROWS: 179 print(", type_index="); 180 print(pos.type_index); 181 break; 182 // method parameter 183 case METHOD_FORMAL_PARAMETER: 184 print(", param_index="); 185 print(pos.parameter_index); 186 break; 187 // type cast 188 case CAST: 189 // method/constructor/reference type argument 190 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 191 case METHOD_INVOCATION_TYPE_ARGUMENT: 192 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 193 case METHOD_REFERENCE_TYPE_ARGUMENT: 194 if (showOffsets) { 195 print(", offset="); 196 print(pos.offset); 197 } 198 print(", type_index="); 199 print(pos.type_index); 200 break; 201 // We don't need to worry about these 202 case METHOD_RETURN: 203 case FIELD: 204 break; 205 case UNKNOWN: 206 throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!"); 207 default: 208 throw new AssertionError("AnnotationWriter: Unknown target type for position: " + pos); 209 } 210 211 // Append location data for generics/arrays. 212 if (!pos.location.isEmpty()) { 213 print(", location="); 214 print(pos.location); 215 } 216 } 217 write(Annotation.element_value_pair pair, boolean resolveIndices)218 public void write(Annotation.element_value_pair pair, boolean resolveIndices) { 219 writeIndex(pair.element_name_index, resolveIndices); 220 print("="); 221 write(pair.value, resolveIndices); 222 } 223 write(Annotation.element_value value)224 public void write(Annotation.element_value value) { 225 write(value, false); 226 println(); 227 indent(+1); 228 write(value, true); 229 indent(-1); 230 } 231 write(Annotation.element_value value, boolean resolveIndices)232 public void write(Annotation.element_value value, boolean resolveIndices) { 233 ev_writer.write(value, resolveIndices); 234 } 235 writeDescriptor(int index, boolean resolveIndices)236 private void writeDescriptor(int index, boolean resolveIndices) { 237 if (resolveIndices) { 238 try { 239 ConstantPool constant_pool = classWriter.getClassFile().constant_pool; 240 Descriptor d = new Descriptor(index); 241 print(d.getFieldType(constant_pool)); 242 return; 243 } catch (ConstantPoolException | InvalidDescriptor ignore) { 244 } 245 } 246 247 print("#" + index); 248 } 249 writeIndex(int index, boolean resolveIndices)250 private void writeIndex(int index, boolean resolveIndices) { 251 if (resolveIndices) { 252 print(constantWriter.stringValue(index)); 253 } else 254 print("#" + index); 255 } 256 257 element_value_Writer ev_writer = new element_value_Writer(); 258 259 class element_value_Writer implements Annotation.element_value.Visitor<Void,Boolean> { write(Annotation.element_value value, boolean resolveIndices)260 public void write(Annotation.element_value value, boolean resolveIndices) { 261 value.accept(this, resolveIndices); 262 } 263 264 @Override visitPrimitive(Primitive_element_value ev, Boolean resolveIndices)265 public Void visitPrimitive(Primitive_element_value ev, Boolean resolveIndices) { 266 if (resolveIndices) { 267 int index = ev.const_value_index; 268 switch (ev.tag) { 269 case 'B': 270 print("(byte) "); 271 print(constantWriter.stringValue(index)); 272 break; 273 case 'C': 274 print("'"); 275 print(constantWriter.charValue(index)); 276 print("'"); 277 break; 278 case 'D': 279 case 'F': 280 case 'I': 281 case 'J': 282 print(constantWriter.stringValue(index)); 283 break; 284 case 'S': 285 print("(short) "); 286 print(constantWriter.stringValue(index)); 287 break; 288 case 'Z': 289 print(constantWriter.booleanValue(index)); 290 break; 291 case 's': 292 print("\""); 293 print(constantWriter.stringValue(index)); 294 print("\""); 295 break; 296 default: 297 print(((char) ev.tag) + "#" + ev.const_value_index); 298 break; 299 } 300 } else { 301 print(((char) ev.tag) + "#" + ev.const_value_index); 302 } 303 return null; 304 } 305 306 @Override visitEnum(Enum_element_value ev, Boolean resolveIndices)307 public Void visitEnum(Enum_element_value ev, Boolean resolveIndices) { 308 if (resolveIndices) { 309 writeIndex(ev.type_name_index, resolveIndices); 310 print("."); 311 writeIndex(ev.const_name_index, resolveIndices); 312 } else { 313 print(((char) ev.tag) + "#" + ev.type_name_index + ".#" + ev.const_name_index); 314 } 315 return null; 316 } 317 318 @Override visitClass(Class_element_value ev, Boolean resolveIndices)319 public Void visitClass(Class_element_value ev, Boolean resolveIndices) { 320 if (resolveIndices) { 321 print("class "); 322 writeIndex(ev.class_info_index, resolveIndices); 323 } else { 324 print(((char) ev.tag) + "#" + ev.class_info_index); 325 } 326 return null; 327 } 328 329 @Override visitAnnotation(Annotation_element_value ev, Boolean resolveIndices)330 public Void visitAnnotation(Annotation_element_value ev, Boolean resolveIndices) { 331 print((char) ev.tag); 332 AnnotationWriter.this.write(ev.annotation_value, resolveIndices); 333 return null; 334 } 335 336 @Override visitArray(Array_element_value ev, Boolean resolveIndices)337 public Void visitArray(Array_element_value ev, Boolean resolveIndices) { 338 print("["); 339 for (int i = 0; i < ev.num_values; i++) { 340 if (i > 0) 341 print(","); 342 write(ev.values[i], resolveIndices); 343 } 344 print("]"); 345 return null; 346 } 347 348 } 349 350 private final ClassWriter classWriter; 351 private final ConstantWriter constantWriter; 352 } 353