Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.checkerframework.qualframework.poly;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.Pair;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.qualframework.base.DefaultQualifiedTypeFactory;
import org.checkerframework.qualframework.base.QualifiedTypeMirror;
import org.checkerframework.qualframework.base.QualifiedTypeMirror.QualifiedExecutableType;
import org.checkerframework.qualframework.base.QualifiedTypeMirror.QualifiedTypeVariable;
import org.checkerframework.qualframework.base.QualifiedTypeMirror.QualifiedWildcardType;
import org.checkerframework.qualframework.base.QualifierHierarchy;
import org.checkerframework.qualframework.base.QualifierMapVisitor;
import org.checkerframework.qualframework.base.SetQualifierVisitor;
import org.checkerframework.qualframework.util.QualifierContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.Kind;
/** Type factory with qualifier polymorphism support. This type factory
* extends an underlying qualifier system with qualifier variables, combined
* qualifiers (using {@link CombiningOperation}), wildcards, typechecking
* support for all of the above, substitution for accessing fields whose types
* refer to qualifier parameters, and qualifier inference for method qualifier
* parameters.
*/
public abstract class QualifierParameterTypeFactory extends DefaultQualifiedTypeFactory> {
QualifierHierarchy groundHierarchy;
public QualifierParameterTypeFactory(QualifierContext> context) {
super(context);
}
@Override
protected abstract QualifierParameterAnnotationConverter createAnnotationConverter();
@Override
public QualifierParameterAnnotationConverter getAnnotationConverter() {
return (QualifierParameterAnnotationConverter)super.getAnnotationConverter();
}
/** Create a {@link QualifierHierarchy} for ground qualifiers (represented
* by instances of {@code Q}).
*/
protected abstract QualifierHierarchy createGroundQualifierHierarchy();
/** Get the ground qualifier hierarchy used by this type system. */
public QualifierHierarchy getGroundQualifierHierarchy() {
if (groundHierarchy == null) {
groundHierarchy = createGroundQualifierHierarchy();
}
return groundHierarchy;
}
@Override
protected QualifierHierarchy> createQualifierHierarchy() {
return QualifierParameterHierarchy.fromGround(getGroundQualifierHierarchy());
}
@Override
protected QualifierParameterTypeAnnotator createTypeAnnotator() {
return new QualifierParameterTypeAnnotator(getContext(), getAnnotationConverter(),
new ContainmentHierarchy<>(new PolyQualHierarchy<>(getGroundQualifierHierarchy())));
}
@Override
protected QualifierParameterTreeAnnotator createTreeAnnotator() {
return new QualifierParameterTreeAnnotator(this);
}
/*
public final QualParams applyCaptureConversion(QualParams objectQual) {
if (objectQual == null || objectQual == QualParams.getBottom()
|| objectQual == QualParams.getTop())
return objectQual;
return objectQual.capture();
}
*/
/** Apply substitution to get the effective type of a class member when
* accessed through an instance with particular qualifiers. This method
* roughly corresponds to AnnotatedTypes.asMemberOf.
*/
private QualParams qualifierAsMemberOf(QualParams memberQual, QualParams objectQual) {
if (memberQual == getQualifierHierarchy().getBottom()) {
// Substituting in the object qualifier would not change the bottom qualifier.
return getQualifierHierarchy().getBottom();
} else if (objectQual == getQualifierHierarchy().getBottom()) {
// objectQual (the receiver) is bottom. Right now just return the existing qualifier.
// If objectQual is not an @Var, then nothing should have been substituted anyway.
// If objectQual is an @Var, then what ground qualifier should be used?
return memberQual;
}
return memberQual.substituteAll(objectQual);
}
/** Visitor to apply {@code qualifierAsMemberOf} at every location within a
* {@link QualifiedTypeMirror}.
*/
private final QualifierMapVisitor, QualParams, QualParams> AS_MEMBER_OF_VISITOR =
new QualifierMapVisitor, QualParams, QualParams>() {
@Override
public QualParams process(QualParams memberQual, QualParams objectQual) {
return qualifierAsMemberOf(memberQual, objectQual);
}
};
@Override
public QualifiedTypeMirror> postAsMemberOf(
QualifiedTypeMirror> memberType,
QualifiedTypeMirror> receiverType,
Element memberElement) {
// Don't run postAsMemberOf when viewing members from inside a class.
if (receiverType.getUnderlyingType().isDeclaration()) {
return memberType;
}
final QualParams effectiveReceiverQualifier;
switch (receiverType.getKind()) {
case WILDCARD:
effectiveReceiverQualifier = ((QualifiedWildcardType>) receiverType).getExtendsBound().getQualifier();
break;
case TYPEVAR:
if (((QualifiedTypeVariable>) receiverType).isPrimaryQualifierValid()) {
effectiveReceiverQualifier = receiverType.getQualifier();
} else {
effectiveReceiverQualifier = this.getQualifiedTypeParameterBounds(
((QualifiedTypeVariable>) receiverType).getDeclaration().getUnderlyingType()).
getUpperBound().getQualifier();
}
break;
default:
effectiveReceiverQualifier = receiverType.getQualifier();
}
return AS_MEMBER_OF_VISITOR.visit(memberType, effectiveReceiverQualifier);
}
/** Visitor to apply substitution at every location within a {@link
* QualifiedTypeMirror}. This is used in {@code methodFromUse} to
* substitute in the newly-inferred values for method qualifier parameters.
*/
private final QualifierMapVisitor, QualParams, Map>> SUBSTITUTE_VISITOR =
new QualifierMapVisitor, QualParams, Map>>() {
@Override
public QualParams process(QualParams params, Map> substs) {
if (params.equals(getQualifierHierarchy().getBottom())) {
return getQualifierHierarchy().getBottom();
}
return params.substituteAll(substs);
}
};
@Override
public Pair>, List>>> methodFromUse(ExpressionTree tree,
ExecutableElement methodElt, QualifiedTypeMirror> receiverType) {
Pair>, List>>> result = super.methodFromUse(tree,
methodElt, receiverType);
Element elt = result.first.getUnderlyingType().asElement();
Set qualParams = getAnnotationConverter().getDeclaredParameters(
elt, getDeclAnnotations(elt), getDecoratedElement(elt));
if (qualParams.isEmpty()) {
// This check is not just a performance optimization - it saves us
// from crashing in one obscure corner case. An `enum`
// declarations gets an auto-generated constructor with an
// auto-generated `super()` call. But the actual java.lang.Enum
// constructor takes two arguments. So trying to do inference on
// that super call will cause a crash. (This problem shows up as
// an IndexOutOfBoundsException in tests/all-systems/Enums.java.)
// The constructor has no qualifier parameters, though, so we can
// skip processing it using this check.
return result;
}
List>> formals = new ArrayList<>();
List>> actuals = new ArrayList<>();
if (tree.getKind() == Kind.METHOD_INVOCATION) {
formals.addAll(getQualifiedTypes().expandVarArgs(result.first, ((MethodInvocationTree)tree).getArguments()));
for (ExpressionTree actualExpr : ((MethodInvocationTree)tree).getArguments()) {
actuals.add(getQualifiedType(actualExpr));
}
}
if (! ElementUtils.isStatic(TreeUtils.elementFromUse(tree))) {
// Need to include receivers in the inference.
formals.add(result.first.getReceiverType());
actuals.add(receiverType);
}
QualifierParameterHierarchy hierarchy = (QualifierParameterHierarchy)getQualifierHierarchy();
MethodParameterInference inference = new MethodParameterInference<>(
new ArrayList<>(qualParams), formals, actuals,
groundHierarchy, new PolyQualHierarchy<>(groundHierarchy),
hierarchy, getTypeHierarchy());
Map> subst = inference.infer();
if (subst != null) {
Map> wildSubst = new HashMap<>();
for (String name : subst.keySet()) {
wildSubst.put(name, new Wildcard<>(subst.get(name)));
}
QualifiedExecutableType> newMethodType =
(QualifiedExecutableType>)SUBSTITUTE_VISITOR.visit(result.first, wildSubst);
List>> newTypeArgs = new ArrayList<>();
for (QualifiedTypeMirror> qtm : result.second) {
newTypeArgs.add(SUBSTITUTE_VISITOR.visit(qtm, wildSubst));
}
result = Pair.of(newMethodType, newTypeArgs);
} else {
// TODO: report error
}
return result;
}
@Override
public List>> postDirectSuperTypes(
QualifiedTypeMirror> subtype,
List>> supertypes) {
QualParams subQuals = subtype.getQualifier();
if (subQuals == null) {
return new ArrayList<>(supertypes);
}
List>> result = new ArrayList<>();
for (QualifiedTypeMirror> supertype : supertypes) {
QualParams superQuals;
if (subQuals == getQualifierHierarchy().getBottom()) {
// If subclass qualifier is bottom, use bottom for the superclass qualifier.
// Substituting in bottom is undefined -- If there are any superclass qualifier parameters,
// what should be the arguments to those parameters? Because of invariant subtyping, there
// are no arguments where the resulting qualifier would still be bottom.
superQuals = subQuals;
} else {
superQuals = supertype.getQualifier().substituteAll(subQuals);
// substituteAll performs substitutions on the primary, but when viewing the superclass we want to
// use the exact primary qualifier of the subclass.
// This was needed to get the Ternary.java test to work.
superQuals.setPrimary(subQuals.getPrimary());
}
result.add(SetQualifierVisitor.apply(supertype, superQuals));
}
return result;
}
}