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

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

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.framework.util.element;

import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.javacutil.ErrorReporter;

import static org.checkerframework.framework.util.element.ElementAnnotationUtil.annotateViaTypeAnnoPosition;
import static org.checkerframework.framework.util.element.ElementAnnotationUtil.getBoundIndexOffset;
import static org.checkerframework.framework.util.element.ElementAnnotationUtil.isOnComponentType;

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 com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.TargetType;

/**
 * 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
     */
    abstract protected TargetType lowerBoundTarget();

    /**
     * @return target type that represents the location of the upper bound of element
     */
    abstract protected 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 (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 = 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 + 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()) {
             annotateViaTypeAnnoPosition(typeToAnno.getKey(), typeToAnno.getValue());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy