| package org.checkerframework.framework.util.element; |
| |
| import com.sun.tools.javac.code.Attribute; |
| import com.sun.tools.javac.code.Symbol; |
| import com.sun.tools.javac.code.TargetType; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import org.checkerframework.framework.type.AnnotatedTypeFactory; |
| import org.checkerframework.framework.type.AnnotatedTypeMirror; |
| import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; |
| import org.checkerframework.framework.util.element.ElementAnnotationUtil.UnexpectedAnnotationLocationException; |
| import org.checkerframework.javacutil.BugInCF; |
| |
| /** Applies the annotations present for a method type parameter onto an AnnotatedTypeVariable. */ |
| public class MethodTypeParamApplier extends TypeParamElementAnnotationApplier { |
| |
| /** Apply annotations from {@code element} to {@code type}. */ |
| public static void apply( |
| AnnotatedTypeVariable type, Element element, AnnotatedTypeFactory typeFactory) |
| throws UnexpectedAnnotationLocationException { |
| new MethodTypeParamApplier(type, element, typeFactory).extractAndApply(); |
| } |
| |
| /** |
| * Returns true if element represents a type parameter for a method. |
| * |
| * @param type ignored |
| * @param element the element that might be a type parameter for a method |
| * @return true if element represents a type parameter for a method |
| */ |
| public static boolean accepts(final AnnotatedTypeMirror type, final Element element) { |
| return element.getKind() == ElementKind.TYPE_PARAMETER |
| && element.getEnclosingElement() instanceof Symbol.MethodSymbol; |
| } |
| |
| private final Symbol.MethodSymbol enclosingMethod; |
| |
| MethodTypeParamApplier( |
| AnnotatedTypeVariable type, Element element, AnnotatedTypeFactory typeFactory) { |
| super(type, element, typeFactory); |
| |
| if (!(element.getEnclosingElement() instanceof Symbol.MethodSymbol)) { |
| throw new BugInCF( |
| "TypeParameter not enclosed by method? Type( " |
| + type |
| + " ) " |
| + "Element ( " |
| + element |
| + " ) "); |
| } |
| |
| enclosingMethod = (Symbol.MethodSymbol) element.getEnclosingElement(); |
| } |
| |
| /** |
| * Returns TargetType.METHOD_TYPE_PARAMETER. |
| * |
| * @return TargetType.METHOD_TYPE_PARAMETER |
| */ |
| @Override |
| protected TargetType lowerBoundTarget() { |
| return TargetType.METHOD_TYPE_PARAMETER; |
| } |
| |
| /** |
| * Returns TargetType.METHOD_TYPE_PARAMETER_BOUND. |
| * |
| * @return TargetType.METHOD_TYPE_PARAMETER_BOUND |
| */ |
| @Override |
| protected TargetType upperBoundTarget() { |
| return TargetType.METHOD_TYPE_PARAMETER_BOUND; |
| } |
| |
| /** |
| * Returns the index of element in the type parameter list of its enclosing method. |
| * |
| * @return the index of element in the type parameter list of its enclosing method |
| */ |
| @Override |
| public int getElementIndex() { |
| return enclosingMethod.getTypeParameters().indexOf(element); |
| } |
| |
| @Override |
| protected TargetType[] validTargets() { |
| return new TargetType[] { |
| TargetType.METHOD_RETURN, |
| TargetType.METHOD_FORMAL_PARAMETER, |
| TargetType.METHOD_RECEIVER, |
| TargetType.THROWS, |
| TargetType.LOCAL_VARIABLE, |
| TargetType.RESOURCE_VARIABLE, |
| TargetType.EXCEPTION_PARAMETER, |
| TargetType.NEW, |
| TargetType.CAST, |
| TargetType.INSTANCEOF, |
| TargetType.METHOD_INVOCATION_TYPE_ARGUMENT, |
| TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, |
| TargetType.METHOD_REFERENCE, |
| TargetType.CONSTRUCTOR_REFERENCE, |
| TargetType.METHOD_REFERENCE_TYPE_ARGUMENT, |
| TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, |
| // TODO: from generic anonymous classes; remove when |
| // we can depend on only seeing classfiles that were |
| // generated by a javac that contains a fix for: |
| // https://bugs.openjdk.java.net/browse/JDK-8198945 |
| TargetType.CLASS_EXTENDS, |
| // TODO: Test case from Issue 3277 produces invalid position. |
| // Ignore until this javac bug is fixed: |
| // https://bugs.openjdk.java.net/browse/JDK-8233945 |
| TargetType.UNKNOWN |
| }; |
| } |
| |
| /** |
| * Returns the TypeCompounds (annotations) of the declaring element. |
| * |
| * @return the TypeCompounds (annotations) of the declaring element |
| */ |
| @Override |
| protected Iterable<Attribute.TypeCompound> getRawTypeAttributes() { |
| return enclosingMethod.getRawTypeAttributes(); |
| } |
| |
| @Override |
| protected boolean isAccepted() { |
| return accepts(type, element); |
| } |
| } |