Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update qualifier polymorphism assignment context solution. #114

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.util.TreePath;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
Expand Down Expand Up @@ -29,6 +30,7 @@
import org.checkerframework.framework.util.AnnotatedTypes;
import org.checkerframework.framework.util.AnnotationMirrorMap;
import org.checkerframework.framework.util.AnnotationMirrorSet;
import org.checkerframework.framework.util.QualifierPolymorphismUtil;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.javacutil.TypesUtils;
Expand Down Expand Up @@ -150,6 +152,21 @@ public void resolve(MethodInvocationTree tree, AnnotatedExecutableType type) {
atypeFactory.getReceiverType(tree), type.getReceiverType()));
}

TreePath path = atypeFactory.getPath(tree);
if (path != null) {
AnnotatedTypeMirror assignmentContext =
QualifierPolymorphismUtil.assignedTo(atypeFactory, path);

if (assignmentContext != null) {
instantiationMapping =
collector.reduceWithUpperBounds(
instantiationMapping,
collector.visit(
// Actual assignment lhs type
assignmentContext, type.getReturnType(), true));
}
}

if (instantiationMapping != null && !instantiationMapping.isEmpty()) {
replacer.visit(type, instantiationMapping);
} else {
Expand Down Expand Up @@ -383,6 +400,55 @@ public AnnotationMirrorMap<AnnotationMirrorSet> reduce(
return res;
}

/**
* Reduces lower bounds r1 with upper bounds r2.
*
* @param r1 a map from {@link AnnotationMirror} to {@link AnnotationMirrorSet}
* @param r2 a map from {@link AnnotationMirror} to {@link AnnotationMirrorSet}
* @return the reduced {@link AnnotationMirrorMap}
*/
private AnnotationMirrorMap<AnnotationMirrorSet> reduceWithUpperBounds(
AnnotationMirrorMap<AnnotationMirrorSet> r1,
AnnotationMirrorMap<AnnotationMirrorSet> r2) {

if (r1 == null || r1.isEmpty()) {
return r2;
}
if (r2 == null || r2.isEmpty()) {
return r1;
}

AnnotationMirrorMap<AnnotationMirrorSet> res = new AnnotationMirrorMap<>();
// Ensure that all qualifiers from r1 and r2 are visited.
AnnotationMirrorSet r2remain = new AnnotationMirrorSet();
r2remain.addAll(r2.keySet());
for (Map.Entry<AnnotationMirror, AnnotationMirrorSet> kv1 : r1.entrySet()) {
AnnotationMirror key1 = kv1.getKey();
AnnotationMirrorSet a1Annos = kv1.getValue();
AnnotationMirrorSet a2Annos = r2.get(key1);
if (a2Annos != null && !a2Annos.isEmpty()) {
r2remain.remove(key1);
AnnotationMirrorSet subres = new AnnotationMirrorSet();
for (AnnotationMirror top : topQuals) {
AnnotationMirror a1 = qualHierarchy.findAnnotationInHierarchy(a1Annos, top);
AnnotationMirror a2 = qualHierarchy.findAnnotationInHierarchy(a2Annos, top);
if (a1 != null) {
subres.add(a1);
} else if (a2 != null) {
subres.add(a2);
}
}
res.put(key1, subres);
} else {
res.put(key1, a1Annos);
}
}
for (AnnotationMirror key2 : r2remain) {
res.put(key2, r2.get(key2));
}
return res;
}

/**
* Calls {@link #visit(AnnotatedTypeMirror, AnnotatedTypeMirror)} for each type in {@code
* types}.
Expand Down Expand Up @@ -419,10 +485,12 @@ private AnnotationMirrorMap<AnnotationMirrorSet> visit(
*
* @param type AnnotateTypeMirror used to find instantiations
* @param polyType AnnotatedTypeMirror that may have polymorphic qualifiers
* @param polyIsSub boolean indicates whether {@code polyType} is the subtype of {@code
* type}
* @return a mapping of polymorphic qualifiers to their instantiations
*/
private AnnotationMirrorMap<AnnotationMirrorSet> visit(
AnnotatedTypeMirror type, AnnotatedTypeMirror polyType) {
AnnotatedTypeMirror type, AnnotatedTypeMirror polyType, boolean polyIsSub) {
if (type.getKind() == TypeKind.NULL) {
return mapQualifierToPoly(type, polyType);
}
Expand All @@ -438,19 +506,39 @@ private AnnotationMirrorMap<AnnotationMirrorSet> visit(

switch (polyType.getKind()) {
case WILDCARD:
AnnotatedTypeMirror asSuper =
AnnotatedTypes.asSuper(atypeFactory, wildcardType, polyType);
return visit(asSuper, polyType, null);
case TYPEVAR:
return mapQualifierToPoly(wildcardType.getExtendsBound(), polyType);
if (polyIsSub) {
return visit(
wildcardType,
AnnotatedTypes.asSuper(atypeFactory, polyType, wildcardType),
null);
} else {
return visit(
AnnotatedTypes.asSuper(atypeFactory, wildcardType, polyType),
polyType,
null);
}
default:
return mapQualifierToPoly(wildcardType.getExtendsBound(), polyType);
}
}

AnnotatedTypeMirror asSuper = AnnotatedTypes.asSuper(atypeFactory, type, polyType);
if (polyIsSub) {
return visit(type, AnnotatedTypes.asSuper(atypeFactory, polyType, type), null);
} else {
return visit(AnnotatedTypes.asSuper(atypeFactory, type, polyType), polyType, null);
}
}

return visit(asSuper, polyType, null);
/**
* A helper method of {@link #visit(AnnotatedTypeMirror, AnnotatedTypeMirror, boolean)}.
*
* @param type AnnotateTypeMirror used to find instantiations
* @param polyType AnnotatedTypeMirror that may have polymorphic qualifiers
* @return {@code visit(type, polyType, false)}
*/
private AnnotationMirrorMap<AnnotationMirrorSet> visit(
AnnotatedTypeMirror type, AnnotatedTypeMirror polyType) {
return visit(type, polyType, false);
}

@Override
Expand Down
Loading