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

framework.src.org.checkerframework.qualframework.base.QualifiedTypeFactoryAdapter 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.qualframework.base;

import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.dataflow.analysis.TransferFunction;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFTransfer;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType;
import org.checkerframework.framework.util.MultiGraphQualifierHierarchy;
import org.checkerframework.framework.util.MultiGraphQualifierHierarchy.MultiGraphFactory;
import org.checkerframework.framework.util.defaults.QualifierDefaults;
import org.checkerframework.javacutil.Pair;
import org.checkerframework.qualframework.base.QualifiedTypeMirror.QualifiedExecutableType;
import org.checkerframework.qualframework.base.dataflow.QualAnalysis;
import org.checkerframework.qualframework.base.dataflow.QualTransferAdapter;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;

import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;

/**
 * Adapter class for {@link QualifiedTypeFactory}, extending
 * {@link BaseAnnotatedTypeFactory BaseAnnotatedTypeFactory}.
 */
class QualifiedTypeFactoryAdapter extends BaseAnnotatedTypeFactory {
    /** The underlying {@link QualifiedTypeFactory}. */
    private final QualifiedTypeFactory underlying;

    /** The qualAnalysis instance to use for dataflow. */
    private QualAnalysis qualAnalysis;

    public QualifiedTypeFactoryAdapter(QualifiedTypeFactory underlying,
            CheckerAdapter checker) {
        super(checker, true);
        this.underlying = underlying;

        // We can't call postInit yet.  See CheckerAdapter.getTypeFactory for
        // explanation.
    }

    /** Allow CheckerAdapter to call postInit when it's ready.  See
     * CheckerAdapter.getTypeFactory for explanation.
     */
    void doPostInit() {
        this.postInit();
    }

    // in the qualifier framework, type qualifiers are handled through the @AnnotationConverter
    // createSupportedTypeQualifiers() must return an empty set, otherwise it will try to reflectively load qualifier framework annotations
    // and process them in a classical manner
    @Override
    protected Set> createSupportedTypeQualifiers() {
        return Collections.emptySet();
    }

    @Override
    protected void addCheckedCodeDefaults(QualifierDefaults defs) {
        getCheckerAdapter().setupDefaults(defs);
    }

    /** Returns the underlying {@link QualifiedTypeFactory}. */
    public QualifiedTypeFactory getUnderlying() {
        return underlying;
    }

    /** Returns {@link checker}, downcast to a more precise type. */
    @SuppressWarnings("unchecked")
    CheckerAdapter getCheckerAdapter() {
        return (CheckerAdapter)checker;
    }

    /** Returns the same result as {@link getQualifierHierarchy}, but downcast
     * to a more precise type. */
    @SuppressWarnings("unchecked")
    private QualifierHierarchyAdapter.Implementation getQualifierHierarchyAdapter() {
        return (QualifierHierarchyAdapter.Implementation)getQualifierHierarchy();
    }

    @Override
    protected MultiGraphQualifierHierarchy.MultiGraphFactory createQualifierHierarchyFactory() {
        return new MultiGraphQualifierHierarchy.MultiGraphFactory(this);
    }

    @Override
    public MultiGraphQualifierHierarchy createQualifierHierarchy(MultiGraphFactory factory) {
        QualifierHierarchy underlyingHierarchy = underlying.getQualifierHierarchy();
        DefaultQualifiedTypeFactory defaultUnderlying = (DefaultQualifiedTypeFactory)underlying;
        AnnotationConverter annoConverter = defaultUnderlying.getAnnotationConverter();

        // See QualifierHierarchyAdapter for an explanation of why we need this
        // strange pattern instead of just making a single call to the
        // QualifierHierarchyAdapter constructor.
        QualifierHierarchyAdapter.Implementation adapter =
            new QualifierHierarchyAdapter(
                annoConverter,
                underlyingHierarchy,
                getCheckerAdapter().getTypeMirrorConverter())
            .createImplementation(factory);
        return adapter;
    }

    /* Constructs a TypeHierarchyAdapter for the underlying factory's
     * TypeHierarchy.
     */
    @Override
    protected org.checkerframework.framework.type.TypeHierarchy createTypeHierarchy() {
        TypeHierarchy underlyingHierarchy = underlying.getTypeHierarchy();

        TypeHierarchyAdapter adapter = new TypeHierarchyAdapter(
                underlyingHierarchy,
                getCheckerAdapter().getTypeMirrorConverter(),
                getCheckerAdapter(),
                getQualifierHierarchyAdapter(),
                checker.getOption("ignoreRawTypeArguments", "true").equals("true"),
                checker.hasOption("invariantArrays"));

        // TODO: Move this check (and others like it) into the adapter
        // constructor.
        if (underlyingHierarchy instanceof DefaultTypeHierarchy) {
            DefaultTypeHierarchy defaultHierarchy =
                (DefaultTypeHierarchy)underlyingHierarchy;
            defaultHierarchy.setAdapter(adapter);
        }

        return adapter;
    }

    /* Constructs a TreeAnnotatorAdapter for the underlying factory's
     * TreeAnnotator.
     */
    @Override
    protected org.checkerframework.framework.type.treeannotator.TreeAnnotator createTreeAnnotator() {
        if (!(underlying instanceof DefaultQualifiedTypeFactory)) {
            // In theory, the result of this branch should never be used.  Only
            // DefaultQTFs have a way to access the annotation-based logic
            // which requires the TreeAnnotator produced by this method.
            return null;
        }

        DefaultQualifiedTypeFactory defaultUnderlying =
            (DefaultQualifiedTypeFactory)underlying;
        TreeAnnotator underlyingAnnotator = defaultUnderlying.getTreeAnnotator();
        TreeAnnotatorAdapter adapter = new TreeAnnotatorAdapter(
                underlyingAnnotator,
                getCheckerAdapter().getTypeMirrorConverter(),
                this);

        underlyingAnnotator.setAdapter(adapter);

        return adapter;
    }

    /* Constructs a TypeAnnotatorAdapter for the underlying factory's
     * TypeAnnotator.
     */
    @Override
    protected org.checkerframework.framework.type.typeannotator.TypeAnnotator createTypeAnnotator() {
        if (!(underlying instanceof DefaultQualifiedTypeFactory)) {
            // In theory, the result of this branch should never be used.  Only
            // DefaultQTFs have a way to access the annotation-based logic
            // which requires the TypeAnnotator produced by this method.
            return null;
        }

        DefaultQualifiedTypeFactory defaultUnderlying =
            (DefaultQualifiedTypeFactory)underlying;
        TypeAnnotator underlyingAnnotator = defaultUnderlying.getTypeAnnotator();
        TypeAnnotatorAdapter adapter = new TypeAnnotatorAdapter(
                underlyingAnnotator,
                getCheckerAdapter().getTypeMirrorConverter(),
                this);

        underlyingAnnotator.setAdapter(adapter);

        return adapter;
    }


    @Override
    public boolean isSupportedQualifier(AnnotationMirror anno) {
        if (anno == null) {
            return false;
        }

        // If 'underlying' is not a DefaultQTF, there is no AnnotationConverter
        // for us to use for this check.
        if (!(underlying instanceof DefaultQualifiedTypeFactory)) {
            return true;
        }

        DefaultQualifiedTypeFactory defaultUnderlying = (DefaultQualifiedTypeFactory)underlying;
        AnnotationConverter annoConverter = defaultUnderlying.getAnnotationConverter();

        return annoConverter.isAnnotationSupported(anno)
                || getCheckerAdapter().getTypeMirrorConverter().isKey(anno);
    }


    @Override
    public AnnotatedTypeMirror getAnnotatedType(Element elt) {
        return getCheckerAdapter().getTypeMirrorConverter().getAnnotatedType(
                underlying.getQualifiedType(elt));
    }

    QualifiedTypeMirror superGetAnnotatedType(Element elt) {
        AnnotatedTypeMirror atm = super.getAnnotatedType(elt);
        return getCheckerAdapter().getTypeMirrorConverter().getQualifiedType(atm);
    }

    @Override
    public AnnotatedTypeMirror getAnnotatedType(Tree tree) {
        return getCheckerAdapter().getTypeMirrorConverter().getAnnotatedType(
                underlying.getQualifiedType(tree));
    }

    QualifiedTypeMirror superGetAnnotatedType(Tree tree) {
        AnnotatedTypeMirror atm = super.getAnnotatedType(tree);
        return getCheckerAdapter().getTypeMirrorConverter().getQualifiedType(atm);
    }

    @Override
    public AnnotatedTypeMirror getAnnotatedTypeFromTypeTree(Tree tree) {
        return getCheckerAdapter().getTypeMirrorConverter().getAnnotatedType(
                underlying.getQualifiedTypeFromTypeTree(tree));
    }

    QualifiedTypeMirror superGetAnnotatedTypeFromTypeTree(Tree tree) {
        AnnotatedTypeMirror atm = super.getAnnotatedTypeFromTypeTree(tree);
        return getCheckerAdapter().getTypeMirrorConverter().getQualifiedType(atm);
    }

    @Override
    public void postDirectSuperTypes(AnnotatedTypeMirror subtype, List supertypes) {
        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();

        for (AnnotatedTypeMirror atm: supertypes) {
            defaults.annotate((Element)null, atm);
        }

        QualifiedTypeMirror qualSubtype = conv.getQualifiedType(subtype);
        List> qualSupertypes = conv.getQualifiedTypeList(supertypes);

        List> qualResult = underlying.postDirectSuperTypes(qualSubtype, qualSupertypes);

        for (int i = 0; i < supertypes.size(); ++i) {
            conv.applyQualifiers(qualResult.get(i), supertypes.get(i));
        }
    }

    List> superPostDirectSuperTypes(QualifiedTypeMirror subtype, List> supertypes) {
        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();

        AnnotatedTypeMirror annoSubtype = conv.getAnnotatedType(subtype);
        List annoSupertypes = conv.getAnnotatedTypeList(supertypes);

        super.postDirectSuperTypes(annoSubtype, annoSupertypes);

        return conv.getQualifiedTypeList(annoSupertypes);
    }


    @Override
    public void postAsMemberOf(AnnotatedTypeMirror memberType, AnnotatedTypeMirror receiverType, Element memberElement) {
        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();

        QualifiedTypeMirror qualMemberType = conv.getQualifiedType(memberType);
        QualifiedTypeMirror qualReceiverType = conv.getQualifiedType(receiverType);

        QualifiedTypeMirror qualResult = underlying.postAsMemberOf(
                qualMemberType, qualReceiverType, memberElement);

        conv.applyQualifiers(qualResult, memberType);
    }

    QualifiedTypeMirror superPostAsMemberOf(
            QualifiedTypeMirror memberType, QualifiedTypeMirror receiverType, Element memberElement) {
        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();

        AnnotatedTypeMirror annoMemberType = conv.getAnnotatedType(memberType);
        AnnotatedTypeMirror annoReceiverType = conv.getAnnotatedType(receiverType);

        super.postAsMemberOf(annoMemberType, annoReceiverType, memberElement);

        QualifiedTypeMirror qualResult = conv.getQualifiedType(annoMemberType);
        return qualResult;
    }


    @Override
    public Pair> methodFromUse(MethodInvocationTree tree) {
        Pair, List>> qualResult =
            underlying.methodFromUse(tree);

        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();
        Pair> annoResult =
            Pair.of((AnnotatedExecutableType)conv.getAnnotatedType(qualResult.first),
                    conv.getAnnotatedTypeList(qualResult.second));

        return annoResult;
    }

    Pair, List>> superMethodFromUse(MethodInvocationTree tree) {
        Pair> annoResult =
            super.methodFromUse(tree);

        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();
        Pair, List>> qualResult =
            Pair.of((QualifiedExecutableType) conv.getQualifiedType(annoResult.first),
                    conv.getQualifiedTypeList(annoResult.second));
        return qualResult;
    }

    @Override
    public Pair> methodFromUse(ExpressionTree tree,
            ExecutableElement methodElt, AnnotatedTypeMirror receiverType) {

        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();
        Pair, List>> qualResult =
                underlying.methodFromUse(tree, methodElt, conv.getQualifiedType(receiverType));

        Pair> annoResult =
                Pair.of((AnnotatedExecutableType) conv.getAnnotatedType(qualResult.first),
                        conv.getAnnotatedTypeList(qualResult.second));
        return annoResult;
    }

    Pair, List>> superMethodFromUse(ExpressionTree tree,
            ExecutableElement methodElt, QualifiedTypeMirror receiverType) {
        TypeMirrorConverter conv = getCheckerAdapter().getTypeMirrorConverter();

        Pair> annoResult =
                super.methodFromUse(tree, methodElt, conv.getAnnotatedType(receiverType));

        Pair, List>> qualResult =
                Pair.of((QualifiedExecutableType) conv.getQualifiedType(annoResult.first),
                        conv.getQualifiedTypeList(annoResult.second));
        return qualResult;
    }

    /**
     * Create the {@link TransferFunction} to be used.
     *
     * @param analysis the {@link CFAbstractAnalysis} that the checker framework will actually use
     * @return the {@link CFTransfer} to be used
     */
    @Override
    public CFTransfer createFlowTransferFunction(CFAbstractAnalysis analysis) {
        if (qualAnalysis == null) {
            // TODO: When we actually use the qual analysis, we will have to initialize it with real data.
            qualAnalysis = underlying.createFlowAnalysis(null);
            qualAnalysis.setAdapter(analysis);
        }
        return new QualTransferAdapter<>(qualAnalysis.createTransferFunction(), analysis, qualAnalysis);
    }

    /**
     * Create an adapter using a TypeVariableSubstitutor from the qual type system.
     */
    @Override
    protected TypeVariableSubstitutorAdapter createTypeVariableSubstitutor() {

        TypeVariableSubstitutor substitutor = underlying.createTypeVariableSubstitutor();
        TypeVariableSubstitutorAdapter adapter = new TypeVariableSubstitutorAdapter(substitutor,
                this.getCheckerAdapter().getTypeMirrorConverter());
        substitutor.setAdapter(adapter);

        return adapter;
    }

    /**
     * The qual framework's tree and type annotators behave differently than the
     * checker frameworks. The default of the checker framework also does not apply.
     */
    @Override
    protected void addComputedTypeAnnotations(Tree tree, AnnotatedTypeMirror type, boolean iUseFlow) {
        assert root != null : "GenericAnnotatedTypeFactory.addComputedTypeAnnotations: " +
                " root needs to be set when used on trees; factory: " + this.getClass();

        if (iUseFlow) {
            /**
             * We perform flow analysis on each {@link ClassTree} that is
             * passed to addComputedTypeAnnotations.  This works correctly when
             * a {@link ClassTree} is passed to this method before any of its
             * sub-trees.  It also helps to satisfy the requirement that a
             * {@link ClassTree} has been advanced to annotation before we
             * analyze it.
             */
            checkAndPerformFlowAnalysis(tree);
        }

        defaults.annotate(tree, type);
        treeAnnotator.visit(tree, type);
        typeAnnotator.visit(type, null);

        if (iUseFlow) {
            CFValue as = getInferredValueFor(tree);
            if (as != null) {
                applyInferredAnnotations(type, as);
            }
        }

    }

    @Override
    public void addComputedTypeAnnotations(Element elt, AnnotatedTypeMirror type) {
        defaults.annotate(elt, type);
        typeAnnotator.visit(type, null);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy