blob: a2a4b087c35738af2b4ae5e7f71b33f87ccf46dd [file] [log] [blame]
package org.checkerframework.framework.type.visitor;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.BugInCF;
/** Changes each parameter type to be the GLB of the parameter type and visited type. */
public class AnnotatedTypeCombiner extends DoubleAnnotatedTypeScanner<Void> {
/**
* Combines all annotations from {@code from} and {@code to} into {@code to} using the GLB.
*
* @param from the annotated type mirror from which to take annotations
* @param to the annotated type mirror into which annotations should be combined
* @param hierarchy the top type of the hierarchy whose annotations should be combined
*/
@SuppressWarnings("interning:not.interned") // assertion
public static void combine(
final AnnotatedTypeMirror from,
final AnnotatedTypeMirror to,
final QualifierHierarchy hierarchy) {
if (from == to) {
throw new BugInCF("from == to: %s", from);
}
new AnnotatedTypeCombiner(hierarchy).visit(from, to);
}
/** The hierarchy used to compute the GLB. */
private final QualifierHierarchy hierarchy;
/**
* Create an AnnotatedTypeCombiner.
*
* @param hierarchy the hierarchy used to the compute the GLB
*/
public AnnotatedTypeCombiner(final QualifierHierarchy hierarchy) {
this.hierarchy = hierarchy;
}
@Override
@SuppressWarnings("interning:not.interned") // assertion
protected Void defaultAction(AnnotatedTypeMirror one, AnnotatedTypeMirror two) {
assert one != two;
if (one != null && two != null) {
combineAnnotations(one, two);
}
return null;
}
/**
* Computes the greatest lower bound of each set of annotations shared by from and to, and
* replaces the annotations in to with the result.
*
* @param from the first set of annotations
* @param to the second set of annotations. This is modified by side-effect to hold the result.
*/
protected void combineAnnotations(final AnnotatedTypeMirror from, final AnnotatedTypeMirror to) {
Set<AnnotationMirror> combinedAnnotations = AnnotationUtils.createAnnotationSet();
for (AnnotationMirror top : hierarchy.getTopAnnotations()) {
AnnotationMirror aFrom = from.getAnnotationInHierarchy(top);
AnnotationMirror aTo = to.getAnnotationInHierarchy(top);
if (aFrom != null && aTo != null) {
combinedAnnotations.add(hierarchy.greatestLowerBound(aFrom, aTo));
} else if (aFrom != null) {
combinedAnnotations.add(aFrom);
} else if (aTo != null) {
combinedAnnotations.add(aTo);
}
}
to.replaceAnnotations(combinedAnnotations);
}
}