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

framework.src.org.checkerframework.framework.util.typeinference.GlbUtil 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.typeinference;

import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedNullType;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.type.TypeHierarchy;
import org.checkerframework.javacutil.AnnotationUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;

/**
 *  A class used to determine the greatest lower bounds for a set of AnnotatedTypeMirrors.
 */
public class GlbUtil {

    /**
     * Note: This method can be improved for wildcards and type variables.
     * @return the greatest lower bound of typeMirrors.  If any of the type mirrors are incomparable, use
     * an AnnotatedNullType that will contain the greatest lower bounds of the primary annotations of typeMirrors
     */
    public static AnnotatedTypeMirror glbAll(final Map> typeMirrors, final AnnotatedTypeFactory typeFactory) {
        final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
        if (typeMirrors.isEmpty()) {
            return null;
        }

        // dtermine the greatest lower bounds for the primary annotations
        Map glbPrimaries = AnnotationUtils.createAnnotationMap();
        for (Entry> tmEntry : typeMirrors.entrySet()) {
            final Set typeAnnoHierarchies = tmEntry.getValue();
            final AnnotatedTypeMirror type = tmEntry.getKey();

            for (AnnotationMirror top : typeAnnoHierarchies) {
                //TODO: When all of the typeMirrors are either wildcards or type variables than the greatest lower bound
                //TODO: should involve handling the bounds individually rather than using the effective annotation
                //TODO: We are doing this for expediency
                final AnnotationMirror typeAnno = type.getEffectiveAnnotationInHierarchy(top);
                final AnnotationMirror currentAnno = glbPrimaries.get(top);
                if (typeAnno != null && currentAnno != null) {
                    glbPrimaries.put(top, qualifierHierarchy.greatestLowerBound(currentAnno, typeAnno));
                } else if (typeAnno != null) {
                    glbPrimaries.put(top, typeAnno);
                }
            }
        }

        final List glbTypes = new ArrayList<>();

        // create a copy of all of the types and apply the glb primary annotation
        final Set values = new HashSet<>(glbPrimaries.values());
        for (AnnotatedTypeMirror type : typeMirrors.keySet()) {
            if (type.getKind() != TypeKind.TYPEVAR
             || !qualifierHierarchy.isSubtype(type.getEffectiveAnnotations(), values)) {
                final AnnotatedTypeMirror copy = type.deepCopy();
                copy.replaceAnnotations(values);
                glbTypes.add(copy);

            } else {
                // if the annotations came from the upper bound of this typevar
                // we do NOT want to place them as primary annotations (and destroy the
                // type vars lower bound)
               glbTypes.add(type);
            }
        }

        final TypeHierarchy typeHierarchy = typeFactory.getTypeHierarchy();

        // sort placing supertypes first
        sortForGlb(glbTypes, typeFactory);

        // find the lowest type in the list that is not an AnnotatedNullType
        AnnotatedTypeMirror glbType = glbTypes.get(0);
        int index = 1;
        while (index < glbTypes.size()) {
            // avoid using null if possible, since constraints form the lower bound will often have NULL types
            if (glbType.getKind() != TypeKind.NULL) {
                glbType = glbTypes.get(index);
            }
            index += 1;
        }

        // if the lowest type is a subtype of all glbTypes then it is the GLB, otherwise
        // there are two types  in glbTypes that are incomparable and we need to use bottom (AnnotatedNullType)
        boolean incomparable = false;
        for (final AnnotatedTypeMirror type : glbTypes) {
            if (!incomparable && !typeHierarchy.isSubtype(glbType, type) && type.getKind() != TypeKind.NULL) {
                incomparable = true;
            }
        }

        // we had two incomparable types in glbTypes
        if (incomparable) {
            return createBottom(typeFactory, glbType.getEffectiveAnnotations());
        }

        return glbType;
    }

    /**
     * Returns an AnnotatedNullType with the given annotations as primaries
     */
    private static AnnotatedNullType createBottom(final AnnotatedTypeFactory typeFactory,
                                           final Set annos) {
        return typeFactory.getAnnotatedNullType(annos);
    }

    /**
     * Sort the list of type mirrors, placing supertypes first and subtypes last.
     *
     * E.g.
     * the list:  {@code ArrayList, List, AbstractList}
     * becomes:   {@code List, AbstractList, ArrayList}
     *
     */
    public static void sortForGlb(final List typeMirrors, final AnnotatedTypeFactory typeFactory) {
        final QualifierHierarchy qualifierHierarchy = typeFactory.getQualifierHierarchy();
        final Types types = typeFactory.getProcessingEnv().getTypeUtils();

        Collections.sort(typeMirrors, new Comparator() {
            @Override
            public int compare(AnnotatedTypeMirror type1, AnnotatedTypeMirror type2) {
                final TypeMirror underlyingType1 = type1.getUnderlyingType();
                final TypeMirror underlyingType2 = type2.getUnderlyingType();

                if (types.isSameType(underlyingType1, underlyingType2)) {
                    return compareAnnotations(qualifierHierarchy, type1, type2);
                }

                if (types.isSubtype(underlyingType1, underlyingType2)) {
                    return 1;
                }

                // if they're incomparable or type2 is a subtype of type1
                return -1;
            }

            private int compareAnnotations(final QualifierHierarchy qualHierarchy, final AnnotatedTypeMirror type1, final AnnotatedTypeMirror type2) {
                if (AnnotationUtils.areSame(type1.getAnnotations(), type2.getAnnotations())) {
                    return 0;
                }

                if (qualHierarchy.isSubtype(type1.getAnnotations(), type2.getAnnotations())) {
                    return 1;

                } else {
                    return -1;
                }
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy