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

checker.src.org.checkerframework.checker.nullness.KeyForPropagator 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.checker.nullness;

import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.visitor.AnnotatedTypeMerger;
import org.checkerframework.framework.util.AnnotationBuilder;
import org.checkerframework.framework.util.TypeArgumentMapper;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.Pair;

import java.util.List;
import java.util.Set;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Types;


/**
 * KeyForPropagator is used to move nested KeyFor annotations from one side of a pseudo-assignment to
 * the other.  The KeyForPropagationTreeAnnotator details the locations in which this occurs.
 * @see org.checkerframework.checker.nullness.KeyForPropagationTreeAnnotator
 */
public class KeyForPropagator {
    public static enum PropagationDirection {
        // transfer FROM the super type to the subtype
        TO_SUBTYPE,

        // transfer FROM the subtype to the supertype
        TO_SUPERTYPE,

        // first execute TO_SUBTYPE then TO_SUPERTYPE, if TO_SUBTYPE actually transfers
        // an annotation for a particular type T then T will not be affected by the
        // TO_SUPERTYPE transfer because it will already have a KeyFor annotation
        BOTH
    }


    // The top type of the KeyFor hierarchy, this class will replace @UnknownKeyFor annotations.
    // It will also add annotations when they are misisng for types that require primary annotation
    // (i.e. not TypeVars, Wildcards, Intersections, or Unions).
    private final AnnotationMirror UNKNOWN_KEYFOR;

    public KeyForPropagator(AnnotationMirror unknownKeyfor) {
        this.UNKNOWN_KEYFOR = unknownKeyfor;
    }

    /**
     * Propagate annotations from the type arguments of one type to another.  Which type is the
     * source and destination of the annotations depends on the direction parameter.  Only @KeyFor annotations
     * are propagated and only if the type to which it would be propagated contains an @UnknownKeyFor or
     * contains no key for annotations of any kind.  If any of the type arguments are wildcards than
     * they are ignored.
     *
     * Note the primary annotations of subtype/supertype are not used.
     *
     * Simple Example:
     * 
{@code
     * typeOf(subtype) = ArrayList<@KeyFor("a") String>
     * typeOf(supertype) = List<@UnknownKeyFor String>
     * direction = TO_SUPERTYPE
     * }
* The type of supertype after propagate would be: * {@code List<@KeyFor("a") String>} * * A more complex example would be: *
{@code
     * typeOf(subtype) = HashMap<@UnknownKeyFor String, @KeyFor("b") List<@KeyFor("c") String>>
     * typeOf(supertype) = Map<@KeyFor("a") String, @KeyFor("b") List<@KeyFor("c") String>>
     * direction = TO_SUBTYPE
     * }
* * The type of subtype after propagate would be: * {@code HashMap<@KeyFor("a") String, @KeyFor("b") List<@KeyFor("c") String>>} */ public void propagate(final AnnotatedDeclaredType subtype, final AnnotatedDeclaredType supertype, PropagationDirection direction, final AnnotatedTypeFactory typeFactory) { final TypeElement subtypeElement = (TypeElement) subtype.getUnderlyingType().asElement(); final TypeElement supertypeElement = (TypeElement) supertype.getUnderlyingType().asElement(); final Types types = typeFactory.getProcessingEnv().getTypeUtils(); // Note: The right hand side of this or expression will cover raw types if (subtype.getTypeArguments().isEmpty()) { return; } // else // this can happen for two reasons: // 1) the subclass introduced NEW type arguments when the superclass had none // 2) the supertype was RAW. // In either case, there is no reason to propagate if (supertype.getTypeArguments().isEmpty()) { return; } Set> typeParamMappings = TypeArgumentMapper.mapTypeArgumentIndices(subtypeElement, supertypeElement, types); KeyForPropagationMerger merger = new KeyForPropagationMerger(typeFactory.getProcessingEnv()); final List subtypeArgs = subtype.getTypeArguments(); final List supertypeArgs = supertype.getTypeArguments(); for (final Pair path : typeParamMappings) { final AnnotatedTypeMirror subtypeArg = subtypeArgs.get(path.first); final AnnotatedTypeMirror supertypeArg = supertypeArgs.get(path.second); if (subtypeArg.getKind() == TypeKind.WILDCARD || supertypeArg.getKind() == TypeKind.WILDCARD) { continue; } switch (direction) { case TO_SUBTYPE: merger.visit(supertypeArg, subtypeArg); break; case TO_SUPERTYPE: merger.visit(subtypeArg, supertypeArg); break; case BOTH: // note if they both have an annotation nothing will happen merger.visit(subtypeArg, supertypeArg); merger.visit(supertypeArg, subtypeArg); break; } } } /** * An annotated type merger that merges @KeyFor annotations and only if the * type that is receiving an annotation has an @UnknownKeyFor annotation or NO key for * annotations. */ private class KeyForPropagationMerger extends AnnotatedTypeMerger { private final ProcessingEnvironment env; private KeyForPropagationMerger(ProcessingEnvironment env) { this.env = env; } @Override protected void replaceAnnotations(AnnotatedTypeMirror from, AnnotatedTypeMirror to) { final AnnotationMirror fromKeyFor = from.getAnnotationInHierarchy(UNKNOWN_KEYFOR); final AnnotationMirror toKeyFor = to.getAnnotationInHierarchy(UNKNOWN_KEYFOR); boolean toNeedsAnnotation = toKeyFor == null || AnnotationUtils.areSame(toKeyFor, UNKNOWN_KEYFOR); if (fromKeyFor!= null && toNeedsAnnotation) { AnnotationBuilder annotationBuilder = new AnnotationBuilder(env, fromKeyFor); to.replaceAnnotation(annotationBuilder.build()); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy