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

framework.src.org.checkerframework.framework.type.typeannotator.PropagationTypeAnnotator 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.type.typeannotator;

import com.sun.tools.javac.code.Type.WildcardType;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.javacutil.ErrorReporter;
import org.checkerframework.javacutil.TypesUtils;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import java.util.*;

/**
 * {@link PropagationTypeAnnotator} adds qualifiers to types where the qualifier
 * to add should be transferred from one or more other types.
 *
 * At the moment, the only function PropagationTypeAnnotator provides, is the
 * propagation of generic type parameter annotations to unannotated wildcards
 * with missing bounds annotations.
 *
 * @see #visitWildcard(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType, Object)
 *
 * PropagationTypeAnnotator traverses trees deeply by default.
 *
 */
public class PropagationTypeAnnotator extends TypeAnnotator {

    // The PropagationTypeAnnotator is called recursively via TypeAnnotatorUtil.eraseBoundsThenAnnotate.
    // This flag prevents infinite recursion.
    private boolean pause  = false;
    private Stack parents = new Stack<>();

    public PropagationTypeAnnotator(AnnotatedTypeFactory typeFactory) {
        super(typeFactory);
    }

    @Override
    public void reset() {
        if (!pause) {
            // when the PropagationTypeAnnotator is called recursively we don't
            // want the visit method to reset the list of visited types
            super.reset();
        }
    }

    /*
     * When pause == true, the PropagationTypeAnnotator caused a recursive call
     * and there is no need to execute the PropagationTypeAnnotator
     */
    @Override
    protected Void scan(AnnotatedTypeMirror type, Void aVoid) {
        if (pause) {
            return null;
        }

        return super.scan(type, aVoid);
    }

    /**
     * Sometimes the underlying type parameters of AnnotatedWildcardTypes are not available
     * on the wildcards themselves.  Instead, record enclosing class to find the type parameter
     * to use as a backup in visitWildcards.
     * @param declaredType type to record
     */
    @Override
    public Void visitDeclared(AnnotatedDeclaredType declaredType, Void aVoid) {
        if (pause) {
            return null;
        }
        parents.push(declaredType);
        super.visitDeclared(declaredType, aVoid);
        parents.pop();
        return null;
    }


    /**
     * Rather than defaulting the missing bounds of a wildcard, find the bound
     * annotations on the type parameter it replaced.  Place those annotations
     * on the wildcard.
     * @param wildcardAtm type to annotate
     */
    @Override
    public Void visitWildcard(AnnotatedWildcardType wildcardAtm, Void aVoid) {
        if (visitedNodes.containsKey(wildcardAtm) || pause) {
            return null;
        }
        visitedNodes.put(wildcardAtm, null);

        final WildcardType wildcard = (WildcardType) wildcardAtm.getUnderlyingType();
        Element typeParamElement = TypesUtils.wildcardToTypeParam(wildcard);
        if (typeParamElement == null) {
            typeParamElement = (parents.empty()) ? null : getTypeParamFromEnclosingClass(wildcardAtm, parents.peek());
        }

        if (typeParamElement != null) {
            pause = true;
            AnnotatedTypeVariable typeParam = (AnnotatedTypeVariable) typeFactory.getAnnotatedType(typeParamElement);
            pause = false;

            final Set tops = typeFactory.getQualifierHierarchy().getTopAnnotations();

            if (wildcard.isUnbound()) {
                propagateExtendsBound(wildcardAtm, typeParam, tops);
                propagateSuperBound(wildcardAtm, typeParam, tops);

            } else if (wildcard.isExtendsBound()) {
                propagateSuperBound(wildcardAtm, typeParam, tops);

            } else { // is super bound
                propagateExtendsBound(wildcardAtm, typeParam, tops);
            }

        }
        scan(wildcardAtm.getExtendsBound(), null);
        scan(wildcardAtm.getSuperBound(), null);
        return null;
    }

    private void propagateSuperBound(AnnotatedWildcardType wildcard, AnnotatedTypeVariable typeParam,
                                     Set tops) {
        applyAnnosFromBound(wildcard.getSuperBound(), typeParam.getLowerBound(), tops);
    }

    private void propagateExtendsBound(AnnotatedWildcardType wildcard, AnnotatedTypeVariable typeParam,
                                       Set tops) {
        applyAnnosFromBound(wildcard.getExtendsBound(), typeParam.getUpperBound(), tops);

    }

    /** Take the primary annotations from typeParamBound and place them as primary annotations on wildcard bound */
    private void applyAnnosFromBound(final AnnotatedTypeMirror wildcardBound, final AnnotatedTypeMirror typeParamBound,
                                     final Set tops) {
        // Type variables do not need primary annotations.
        // The type variable will have annotations placed on its
        // bounds via its declaration or defaulting rules
        if (wildcardBound.getKind() == TypeKind.TYPEVAR
         || typeParamBound.getKind() == TypeKind.TYPEVAR) {
            return;
        }

        for (final AnnotationMirror top : tops) {
            if (wildcardBound.getAnnotationInHierarchy(top) == null) {
                final AnnotationMirror typeParamAnno = typeParamBound.getAnnotationInHierarchy(top);
                if (typeParamAnno == null) {
                    ErrorReporter.errorAbort("Missing annotation on type parameter\n"
                        + "top=" + top + "\n"
                        + "wildcardBound=" + wildcardBound + "\n"
                        + "typeParamBound=" + typeParamBound + "\n"
                    );
                } // else
                wildcardBound.addAnnotation(typeParamAnno);
            }
        }
    }

    /**
     * Search parent's type arguments for wildcard.  Using the index of wildcard,
     * find the corresponding type parameter element and return it.
     * Returns null if the wildcard is the result of substitution and therefore
     * not in the list of type arguments.
     */
    private Element getTypeParamFromEnclosingClass(final AnnotatedWildcardType wildcard,
                                                   final AnnotatedDeclaredType parent) {
        Integer wildcardIndex = null;
        int currentIndex = 0;
        for (AnnotatedTypeMirror typeArg : parent.getTypeArguments()) {
            // the only cases in which the wildcard is not one of the type arguments are cases in
            // which they should have been replaced by capture
            if (typeArg == wildcard) {
                wildcardIndex = currentIndex;
                break;
            }
            currentIndex += 1;
        }

        if (wildcardIndex != null) {
            final TypeElement typeElement = (TypeElement)
                    typeFactory
                        .getProcessingEnv()
                        .getTypeUtils()
                        .asElement(parent.getUnderlyingType());

            return typeElement.getTypeParameters().get(wildcardIndex);
        }

        return null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy