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.turbine.bytecode.Attribute.AnnotationDefault; 21 import com.google.turbine.bytecode.Attribute.ConstantValue; 22 import com.google.turbine.bytecode.Attribute.ExceptionsAttribute; 23 import com.google.turbine.bytecode.Attribute.InnerClasses; 24 import com.google.turbine.bytecode.Attribute.MethodParameters; 25 import com.google.turbine.bytecode.Attribute.Signature; 26 import com.google.turbine.bytecode.ClassFile.AnnotationInfo; 27 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo; 28 import java.util.ArrayList; 29 import java.util.List; 30 31 /** Lower information in {@link ClassFile} structures to attributes. */ 32 public final class LowerAttributes { 33 34 /** Collects the {@link Attribute}s for a {@link ClassFile}. */ classAttributes(ClassFile classfile)35 static List<Attribute> classAttributes(ClassFile classfile) { 36 List<Attribute> attributes = new ArrayList<>(); 37 if (!classfile.innerClasses().isEmpty()) { 38 attributes.add(new InnerClasses(classfile.innerClasses())); 39 } 40 addAllAnnotations(attributes, classfile.annotations()); 41 addAllTypeAnnotations(attributes, classfile.typeAnnotations()); 42 if (classfile.signature() != null) { 43 attributes.add(new Signature(classfile.signature())); 44 } 45 if (classfile.module() != null) { 46 attributes.add(new Attribute.Module(classfile.module())); 47 } 48 if (classfile.nestHost() != null) { 49 attributes.add(new Attribute.NestHost(classfile.nestHost())); 50 } 51 if (!classfile.nestMembers().isEmpty()) { 52 attributes.add(new Attribute.NestMembers(classfile.nestMembers())); 53 } 54 if (classfile.record() != null) { 55 attributes.add(recordAttribute(classfile.record())); 56 } 57 if (!classfile.permits().isEmpty()) { 58 attributes.add(new Attribute.PermittedSubclasses(classfile.permits())); 59 } 60 if (classfile.transitiveJar() != null) { 61 attributes.add(new Attribute.TurbineTransitiveJar(classfile.transitiveJar())); 62 } 63 return attributes; 64 } 65 recordAttribute(ClassFile.RecordInfo record)66 private static Attribute recordAttribute(ClassFile.RecordInfo record) { 67 ImmutableList.Builder<Attribute.Record.Component> components = ImmutableList.builder(); 68 for (ClassFile.RecordInfo.RecordComponentInfo component : record.recordComponents()) { 69 List<Attribute> attributes = new ArrayList<>(); 70 if (component.signature() != null) { 71 attributes.add(new Attribute.Signature(component.signature())); 72 } 73 addAllAnnotations(attributes, component.annotations()); 74 addAllTypeAnnotations(attributes, component.typeAnnotations()); 75 components.add( 76 new Attribute.Record.Component(component.name(), component.descriptor(), attributes)); 77 } 78 return new Attribute.Record(components.build()); 79 } 80 81 /** Collects the {@link Attribute}s for a {@link MethodInfo}. */ methodAttributes(ClassFile.MethodInfo method)82 static List<Attribute> methodAttributes(ClassFile.MethodInfo method) { 83 List<Attribute> attributes = new ArrayList<>(); 84 addAllAnnotations(attributes, method.annotations()); 85 addAllTypeAnnotations(attributes, method.typeAnnotations()); 86 if (method.signature() != null) { 87 attributes.add(new Signature(method.signature())); 88 } 89 addParameterAnnotations(attributes, method.parameterAnnotations()); 90 if (!method.exceptions().isEmpty()) { 91 attributes.add(new ExceptionsAttribute(method.exceptions())); 92 } 93 if (method.defaultValue() != null) { 94 attributes.add(new AnnotationDefault(method.defaultValue())); 95 } 96 if (!method.parameters().isEmpty()) { 97 attributes.add(new MethodParameters(method.parameters())); 98 } 99 return attributes; 100 } 101 102 /** Collects the {@link Attribute}s for a {@link FieldInfo}. */ fieldAttributes(ClassFile.FieldInfo field)103 static List<Attribute> fieldAttributes(ClassFile.FieldInfo field) { 104 List<Attribute> attributes = new ArrayList<>(); 105 if (field.signature() != null) { 106 attributes.add(new Signature(field.signature())); 107 } 108 if (field.value() != null) { 109 attributes.add(new ConstantValue(field.value())); 110 } 111 addAllAnnotations(attributes, field.annotations()); 112 addAllTypeAnnotations(attributes, field.typeAnnotations()); 113 return attributes; 114 } 115 addAllAnnotations(List<Attribute> attributes, List<AnnotationInfo> annotations)116 static void addAllAnnotations(List<Attribute> attributes, List<AnnotationInfo> annotations) { 117 List<AnnotationInfo> visible = new ArrayList<>(); 118 List<AnnotationInfo> invisible = new ArrayList<>(); 119 for (AnnotationInfo annotation : annotations) { 120 if (annotation.typeName().equals("Ljava/lang/Deprecated;")) { 121 attributes.add(Attribute.DEPRECATED); 122 } 123 (annotation.isRuntimeVisible() ? visible : invisible).add(annotation); 124 } 125 if (!visible.isEmpty()) { 126 attributes.add(new Attribute.RuntimeVisibleAnnotations(visible)); 127 } 128 if (!invisible.isEmpty()) { 129 attributes.add(new Attribute.RuntimeInvisibleAnnotations(invisible)); 130 } 131 } 132 addAllTypeAnnotations( List<Attribute> attributes, ImmutableList<TypeAnnotationInfo> annotations)133 private static void addAllTypeAnnotations( 134 List<Attribute> attributes, ImmutableList<TypeAnnotationInfo> annotations) { 135 List<TypeAnnotationInfo> visible = new ArrayList<>(); 136 List<TypeAnnotationInfo> invisible = new ArrayList<>(); 137 for (TypeAnnotationInfo annotation : annotations) { 138 (annotation.anno().isRuntimeVisible() ? visible : invisible).add(annotation); 139 } 140 if (!visible.isEmpty()) { 141 attributes.add(new Attribute.RuntimeVisibleTypeAnnotations(ImmutableList.copyOf(visible))); 142 } 143 if (!invisible.isEmpty()) { 144 attributes.add( 145 new Attribute.RuntimeInvisibleTypeAnnotations(ImmutableList.copyOf(invisible))); 146 } 147 } 148 addParameterAnnotations( List<Attribute> attributes, ImmutableList<ImmutableList<AnnotationInfo>> annotations)149 static void addParameterAnnotations( 150 List<Attribute> attributes, ImmutableList<ImmutableList<AnnotationInfo>> annotations) { 151 List<List<AnnotationInfo>> visibles = new ArrayList<>(); 152 List<List<AnnotationInfo>> invisibles = new ArrayList<>(); 153 boolean hasVisible = false; 154 boolean hasInvisible = false; 155 for (List<AnnotationInfo> parameterAnnotations : annotations) { 156 List<AnnotationInfo> visible = new ArrayList<>(); 157 List<AnnotationInfo> invisible = new ArrayList<>(); 158 for (AnnotationInfo annotation : parameterAnnotations) { 159 if (annotation.isRuntimeVisible()) { 160 hasVisible = true; 161 visible.add(annotation); 162 } else { 163 hasInvisible = true; 164 invisible.add(annotation); 165 } 166 } 167 visibles.add(visible); 168 invisibles.add(invisible); 169 } 170 // only add the attributes if one of the nested lists is non-empty, 171 // i.e. at least one parameter was annotated 172 if (hasVisible) { 173 attributes.add(new Attribute.RuntimeVisibleParameterAnnotations(visibles)); 174 } 175 if (hasInvisible) { 176 attributes.add(new Attribute.RuntimeInvisibleParameterAnnotations(invisibles)); 177 } 178 } 179 LowerAttributes()180 private LowerAttributes() {} 181 } 182