1 /* 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.turbine.bytecode; 18 19 import com.google.common.collect.ImmutableList; 20 import com.google.common.io.ByteArrayDataOutput; 21 import com.google.turbine.bytecode.ClassFile.AnnotationInfo; 22 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue; 23 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.AnnotationValue; 24 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ArrayValue; 25 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue; 26 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstValue; 27 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue; 28 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo; 29 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.FormalParameterTarget; 30 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.SuperTypeTarget; 31 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.Target; 32 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.ThrowsTarget; 33 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypeParameterBoundTarget; 34 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypeParameterTarget; 35 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypePath; 36 import com.google.turbine.model.Const.Value; 37 import java.util.Map.Entry; 38 39 /** Writes an {@link AnnotationInfo} to a class file. */ 40 public class AnnotationWriter { 41 42 final ConstantPool pool; 43 final ByteArrayDataOutput output; 44 AnnotationWriter(ConstantPool pool, ByteArrayDataOutput output)45 public AnnotationWriter(ConstantPool pool, ByteArrayDataOutput output) { 46 this.pool = pool; 47 this.output = output; 48 } 49 writeAnnotation(AnnotationInfo annotation)50 public void writeAnnotation(AnnotationInfo annotation) { 51 output.writeShort(pool.utf8(annotation.typeName())); 52 output.writeShort(annotation.elementValuePairs().size()); 53 for (Entry<String, ElementValue> entry : annotation.elementValuePairs().entrySet()) { 54 output.writeShort(pool.utf8(entry.getKey())); 55 writeElementValue(entry.getValue()); 56 } 57 } 58 writeElementValue(ElementValue value)59 void writeElementValue(ElementValue value) { 60 switch (value.kind()) { 61 case CONST: 62 writeConstElementValue(((ConstValue) value).value()); 63 break; 64 case ENUM: 65 writeEnumElementValue((EnumConstValue) value); 66 break; 67 case CLASS: 68 writeClassElementValue((ConstClassValue) value); 69 break; 70 case ARRAY: 71 writeArrayElementValue((ArrayValue) value); 72 break; 73 case ANNOTATION: 74 writeAnnotationElementValue((AnnotationValue) value); 75 break; 76 default: 77 throw new AssertionError(value.kind()); 78 } 79 } 80 writeConstElementValue(Value value)81 private void writeConstElementValue(Value value) { 82 switch (value.constantTypeKind()) { 83 case BYTE: 84 writeConst('B', pool.integer(value.asInteger().value())); 85 break; 86 case CHAR: 87 writeConst('C', pool.integer(value.asInteger().value())); 88 break; 89 case SHORT: 90 writeConst('S', pool.integer(value.asInteger().value())); 91 break; 92 case DOUBLE: 93 writeConst('D', pool.doubleInfo(value.asDouble().value())); 94 break; 95 case FLOAT: 96 writeConst('F', pool.floatInfo(value.asFloat().value())); 97 break; 98 case INT: 99 writeConst('I', pool.integer(value.asInteger().value())); 100 break; 101 case LONG: 102 writeConst('J', pool.longInfo(value.asLong().value())); 103 break; 104 case STRING: 105 writeConst('s', pool.utf8(value.asString().value())); 106 break; 107 case BOOLEAN: 108 writeConst('Z', pool.integer(value.asBoolean().value() ? 1 : 0)); 109 break; 110 default: 111 throw new AssertionError(value.constantTypeKind()); 112 } 113 } 114 writeConst(char tag, int index)115 private void writeConst(char tag, int index) { 116 output.writeByte(tag); 117 output.writeShort(index); 118 } 119 writeEnumElementValue(EnumConstValue value)120 private void writeEnumElementValue(EnumConstValue value) { 121 output.writeByte('e'); 122 output.writeShort(pool.utf8(value.typeName())); 123 output.writeShort(pool.utf8(value.constName())); 124 } 125 writeClassElementValue(ConstClassValue value)126 private void writeClassElementValue(ConstClassValue value) { 127 output.writeByte('c'); 128 output.writeShort(pool.utf8(value.className())); 129 } 130 writeArrayElementValue(ArrayValue value)131 private void writeArrayElementValue(ArrayValue value) { 132 output.writeByte('['); 133 output.writeShort(value.elements().size()); 134 for (ElementValue elementValue : value.elements()) { 135 writeElementValue(elementValue); 136 } 137 } 138 writeAnnotationElementValue(AnnotationValue value)139 private void writeAnnotationElementValue(AnnotationValue value) { 140 output.writeByte('@'); 141 writeAnnotation(value.annotation()); 142 } 143 writeTypeAnnotation(TypeAnnotationInfo annotation)144 public void writeTypeAnnotation(TypeAnnotationInfo annotation) { 145 output.writeByte(annotation.targetType().tag()); 146 writeTypeAnnotationTarget(annotation.target()); 147 writePath(annotation.path()); 148 writeAnnotation(annotation.anno()); 149 } 150 writePath(TypePath path)151 private void writePath(TypePath path) { 152 ImmutableList<TypePath> flat = path.flatten(); 153 output.writeByte(flat.size()); 154 for (TypePath curr : flat) { 155 output.writeByte(curr.tag()); 156 output.writeByte(curr.typeArgumentIndex()); 157 } 158 } 159 writeTypeAnnotationTarget(Target target)160 private void writeTypeAnnotationTarget(Target target) { 161 switch (target.kind()) { 162 case EMPTY: 163 break; 164 case TYPE_PARAMETER: 165 output.writeByte(((TypeParameterTarget) target).index()); 166 break; 167 case FORMAL_PARAMETER: 168 output.writeByte(((FormalParameterTarget) target).index()); 169 break; 170 case THROWS: 171 output.writeShort(((ThrowsTarget) target).index()); 172 break; 173 case SUPERTYPE: 174 output.writeShort(((SuperTypeTarget) target).index()); 175 break; 176 case TYPE_PARAMETER_BOUND: 177 TypeParameterBoundTarget typeParameterBoundTarget = (TypeParameterBoundTarget) target; 178 output.writeByte(typeParameterBoundTarget.typeParameterIndex()); 179 output.writeByte(typeParameterBoundTarget.boundIndex()); 180 break; 181 default: 182 throw new AssertionError(target.kind()); 183 } 184 } 185 } 186