All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.framework.util.element.TypeParamElementAnnotationApplier Maven / Gradle / Ivy

package org.checkerframework.framework.util.element;

import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.TargetType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeKind;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.javacutil.ErrorReporter;

/**
 * Applies Element annotations to a single AnnotatedTypeVariable representing a type parameter.
 * Note, the index of IndexedElementAnnotationApplier refers to the type parameter's index in the
 * list that encloses it.
 */
abstract class TypeParamElementAnnotationApplier extends IndexedElementAnnotationApplier {

    /** @return true if element is a TYPE_PARAMETER */
    public static boolean accepts(AnnotatedTypeMirror typeMirror, Element element) {
        return element.getKind() == ElementKind.TYPE_PARAMETER;
    }

    protected final AnnotatedTypeVariable typeParam;
    protected final AnnotatedTypeFactory typeFactory;

    /** @return target type that represents the location of the lower bound of element */
    protected abstract TargetType lowerBoundTarget();

    /** @return target type that represents the location of the upper bound of element */
    protected abstract TargetType upperBoundTarget();

    TypeParamElementAnnotationApplier(
            final AnnotatedTypeVariable type,
            final Element element,
            final AnnotatedTypeFactory typeFactory) {
        super(type, element);
        this.typeParam = type;
        this.typeFactory = typeFactory;
    }

    /** @return the lower bound and upper bound targets */
    @Override
    protected TargetType[] annotatedTargets() {
        return new TargetType[] {lowerBoundTarget(), upperBoundTarget()};
    }

    /**
     * @return the parameter_index of anno's TypeAnnotationPosition which will actually point to the
     *     type parameter's index in its enclosing type parameter list
     */
    @Override
    public int getTypeCompoundIndex(final TypeCompound anno) {
        return anno.getPosition().parameter_index;
    }

    /**
     * @param targeted the list of annotations that were on the lower/upper bounds of the type
     *     parameter
     *     

Note: When handling type parameters we NEVER add primary annotations to the type * parameter. Primary annotations are reserved for the use of a type parameter * (e.g. @Nullable T t; ) *

If an annotation is present on the type parameter itself, it represents the * lower-bound annotation of that type parameter. Any annotation on the extends bound of a * type parameter is placed on that bound. */ @Override protected void handleTargeted(final List targeted) { final int paramIndex = getElementIndex(); final List upperBoundAnnos = new ArrayList<>(); final List lowerBoundAnnos = new ArrayList<>(); for (final TypeCompound anno : targeted) { final AnnotationMirror aliasedAnno = typeFactory.aliasedAnnotation(anno); final AnnotationMirror canonicalAnno = (aliasedAnno != null) ? aliasedAnno : anno; if (anno.position.parameter_index != paramIndex || !typeFactory.isSupportedQualifier(canonicalAnno)) { continue; } if (ElementAnnotationUtil.isOnComponentType(anno)) { applyComponentAnnotation(anno); } else if (anno.position.type == upperBoundTarget()) { upperBoundAnnos.add(anno); } else { lowerBoundAnnos.add(anno); } } applyLowerBounds(lowerBoundAnnos); applyUpperBounds(upperBoundAnnos); } /** * Applies a list of annotations to the upperBound of the type parameter. If the type of the * upper bound is an intersection we must first find the correct location for each annotation. */ private void applyUpperBounds(final List upperBounds) { if (!upperBounds.isEmpty()) { final AnnotatedTypeMirror upperBoundType = typeParam.getUpperBound(); if (upperBoundType.getKind() == TypeKind.INTERSECTION) { final List intersectionTypes = upperBoundType.directSuperTypes(); final int boundIndexOffset = ElementAnnotationUtil.getBoundIndexOffset(intersectionTypes); for (final TypeCompound anno : upperBounds) { final int boundIndex = anno.position.bound_index + boundIndexOffset; if (boundIndex < 0 || boundIndex > intersectionTypes.size()) { ErrorReporter.errorAbort( "Invalid bound index on element annotation ( " + anno + " ) " + "for type ( " + typeParam + " ) with " + "upper bound ( " + typeParam.getUpperBound() + " ) " + "and boundIndex( " + boundIndex + " ) "); } intersectionTypes.get(boundIndex).replaceAnnotation(anno); // TODO: WHY NOT ADD? } } else { upperBoundType.addAnnotations(upperBounds); } } } /** * In the event of multiple annotations on an AnnotatedNullType lower bound we want to preserve * the multiple annotations so that an type.invalid exception is raised later. */ private void applyLowerBounds(final List annos) { if (!annos.isEmpty()) { final AnnotatedTypeMirror lowerBound = typeParam.getLowerBound(); for (AnnotationMirror anno : annos) { lowerBound.addAnnotation(anno); } } } private void addAnnotationToMap( final AnnotatedTypeMirror type, final TypeCompound anno, final Map> typeToAnnos) { List annoList = typeToAnnos.get(type); if (annoList == null) { annoList = new ArrayList<>(); typeToAnnos.put(type, annoList); } annoList.add(anno); } private void applyComponentAnnotation(final TypeCompound anno) { final AnnotatedTypeMirror upperBoundType = typeParam.getUpperBound(); Map> typeToAnnotations = new HashMap<>(); if (anno.position.type == upperBoundTarget()) { if (upperBoundType.getKind() == TypeKind.INTERSECTION) { final List intersectionTypes = upperBoundType.directSuperTypes(); final int boundIndex = anno.position.bound_index + ElementAnnotationUtil.getBoundIndexOffset(intersectionTypes); if (boundIndex < 0 || boundIndex > intersectionTypes.size()) { ErrorReporter.errorAbort( "Invalid bound index on element annotation ( " + anno + " ) " + "for type ( " + typeParam + " ) with upper bound ( " + typeParam.getUpperBound() + " )"); } addAnnotationToMap(intersectionTypes.get(boundIndex), anno, typeToAnnotations); } else { addAnnotationToMap(upperBoundType, anno, typeToAnnotations); } } else { addAnnotationToMap(typeParam.getLowerBound(), anno, typeToAnnotations); } for (Entry> typeToAnno : typeToAnnotations.entrySet()) { ElementAnnotationUtil.annotateViaTypeAnnoPosition( typeToAnno.getKey(), typeToAnno.getValue()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy