/******************************************************************************* * Copyright (c) 2012, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409247 - [1.8][compiler] Verify error with code allocating multidimensional array * Bug 409517 - [1.8][compiler] Type annotation problems on more elaborate array references * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.codegen; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.internal.compiler.ClassFile; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; @SuppressWarnings({"rawtypes"}) public class TypeAnnotationCodeStream extends StackMapFrameCodeStream { public List allTypeAnnotationContexts; public TypeAnnotationCodeStream(ClassFile givenClassFile) { super(givenClassFile); this.generateAttributes |= ClassFileConstants.ATTR_TYPE_ANNOTATION; this.allTypeAnnotationContexts = new ArrayList(); } private void addAnnotationContext(TypeReference typeReference, int info, int targetType, ArrayAllocationExpression allocationExpression) { allocationExpression.getAllAnnotationContexts(targetType, info, this.allTypeAnnotationContexts); } private void addAnnotationContext(TypeReference typeReference, int info, int targetType) { typeReference.getAllAnnotationContexts(targetType, info, this.allTypeAnnotationContexts); } private void addAnnotationContext(TypeReference typeReference, int info, int typeIndex, int targetType) { typeReference.getAllAnnotationContexts(targetType, info, typeIndex, this.allTypeAnnotationContexts); } public void instance_of(TypeReference typeReference, TypeBinding typeBinding) { if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.INSTANCEOF); } super.instance_of(typeReference, typeBinding); } public void multianewarray( TypeReference typeReference, TypeBinding typeBinding, int dimensions, ArrayAllocationExpression allocationExpression) { if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW, allocationExpression); } super.multianewarray(typeReference, typeBinding, dimensions, allocationExpression); } public void new_(TypeReference typeReference, TypeBinding typeBinding) { if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW); } super.new_(typeReference, typeBinding); } public void newArray(TypeReference typeReference, ArrayAllocationExpression allocationExpression, ArrayBinding arrayBinding) { if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW, allocationExpression); } super.newArray(typeReference, allocationExpression, arrayBinding); } public void checkcast(TypeReference typeReference, TypeBinding typeBinding) { /* We use a slightly sub-optimal generation for intersection casts by resorting to a runtime cast for every intersecting type, but in reality this should not matter. In its intended use form such as (I & Serializable) () -> {}, no cast is emitted at all. Also note intersection cast type references cannot nest i.e ((X & I) & J) is not valid syntax. */ if (typeReference != null) { TypeReference [] typeReferences = typeReference.getTypeReferences(); for (int i = typeReferences.length - 1; i >= 0; i--) { // need to emit right to left. typeReference = typeReferences[i]; if (typeReference != null) { if ((typeReference.bits & ASTNode.HasTypeAnnotations) != 0) addAnnotationContext(typeReference, this.position, i, AnnotationTargetTypeConstants.CAST); super.checkcast(typeReference, typeReference.resolvedType); } } } else { super.checkcast(null, typeBinding); } } public void invoke(byte opcode, MethodBinding methodBinding, TypeBinding declaringClass, TypeReference[] typeArguments) { if (typeArguments != null) { int targetType = methodBinding.isConstructor() ? AnnotationTargetTypeConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : AnnotationTargetTypeConstants.METHOD_INVOCATION_TYPE_ARGUMENT; for (int i = 0, max = typeArguments.length; i < max; i++) { TypeReference typeArgument = typeArguments[i]; if ((typeArgument.bits & ASTNode.HasTypeAnnotations) != 0) { addAnnotationContext(typeArgument, this.position, i, targetType); } } } super.invoke(opcode, methodBinding, declaringClass, typeArguments); } public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature, boolean isConstructorReference, TypeReference lhsTypeReference, TypeReference [] typeArguments) { if (lhsTypeReference != null && (lhsTypeReference.bits & ASTNode.HasTypeAnnotations) != 0) { if (isConstructorReference) { addAnnotationContext(lhsTypeReference, this.position, 0, AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE); } else { addAnnotationContext(lhsTypeReference, this.position, 0, AnnotationTargetTypeConstants.METHOD_REFERENCE); } } if (typeArguments != null) { int targetType = isConstructorReference ? AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT; for (int i = 0, max = typeArguments.length; i < max; i++) { TypeReference typeArgument = typeArguments[i]; if ((typeArgument.bits & ASTNode.HasTypeAnnotations) != 0) { addAnnotationContext(typeArgument, this.position, i, targetType); } } } super.invokeDynamic(bootStrapIndex, argsSize, returnTypeSize, selector, signature, isConstructorReference, lhsTypeReference, typeArguments); } public void reset(ClassFile givenClassFile) { super.reset(givenClassFile); this.allTypeAnnotationContexts = new ArrayList(); } public void init(ClassFile targetClassFile) { super.init(targetClassFile); this.allTypeAnnotationContexts = new ArrayList(); } }