package testlib.wholeprograminference; import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.lang.model.element.AnnotationMirror; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.reflection.qual.UnknownClass; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.framework.type.treeannotator.ImplicitsTreeAnnotator; import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; import org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.framework.util.AnnotationBuilder; import org.checkerframework.framework.util.MultiGraphQualifierHierarchy; import org.checkerframework.framework.util.MultiGraphQualifierHierarchy.MultiGraphFactory; import org.checkerframework.javacutil.AnnotationUtils; import testlib.wholeprograminference.qual.DefaultType; import testlib.wholeprograminference.qual.ImplicitAnno; import testlib.wholeprograminference.qual.Parent; import testlib.wholeprograminference.qual.Sibling1; import testlib.wholeprograminference.qual.Sibling2; import testlib.wholeprograminference.qual.SiblingWithFields; import testlib.wholeprograminference.qual.Top; import testlib.wholeprograminference.qual.WholeProgramInferenceBottom; /** * AnnotatedTypeFactory to test whole-program inference using .jaif files. * * <p>The used qualifier hierarchy is straightforward and only intended for test purposes. * * @author pbsf */ public class WholeProgramInferenceTestAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { private final AnnotationMirror PARENT = new AnnotationBuilder(processingEnv, Parent.class).build(); private final AnnotationMirror BOTTOM = new AnnotationBuilder(processingEnv, WholeProgramInferenceBottom.class).build(); public WholeProgramInferenceTestAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); postInit(); addTypeNameImplicit(java.lang.Void.class, BOTTOM); } @Override protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() { return new HashSet<Class<? extends Annotation>>( Arrays.asList( Parent.class, DefaultType.class, Top.class, Sibling1.class, Sibling2.class, WholeProgramInferenceBottom.class, SiblingWithFields.class, ImplicitAnno.class)); } @Override public TreeAnnotator createTreeAnnotator() { ImplicitsTreeAnnotator implicitsTreeAnnotator = new ImplicitsTreeAnnotator(this); implicitsTreeAnnotator.addTreeKind(com.sun.source.tree.Tree.Kind.NULL_LITERAL, BOTTOM); implicitsTreeAnnotator.addTreeKind(com.sun.source.tree.Tree.Kind.INT_LITERAL, BOTTOM); return new ListTreeAnnotator(new PropagationTreeAnnotator(this), implicitsTreeAnnotator); } @Override public QualifierHierarchy createQualifierHierarchy(MultiGraphFactory factory) { return new WholeProgramInferenceTestQualifierHierarchy(factory); } /** * Using a MultiGraphQualifierHierarchy to enable tests with Annotations that contain * fields. @see SiblingWithFields. * * @author pbsf */ protected class WholeProgramInferenceTestQualifierHierarchy extends MultiGraphQualifierHierarchy { public WholeProgramInferenceTestQualifierHierarchy(MultiGraphFactory f) { super(f); } @Override public AnnotationMirror getBottomAnnotation(AnnotationMirror start) { return BOTTOM; } @Override public AnnotationMirror leastUpperBound(AnnotationMirror a1, AnnotationMirror a2) { if ((AnnotationUtils.areSameByClass(a1, Sibling1.class) && AnnotationUtils.areSameByClass(a2, Sibling2.class)) || (AnnotationUtils.areSameByClass(a1, Sibling2.class) && AnnotationUtils.areSameByClass(a2, Sibling1.class)) || (AnnotationUtils.areSameByClass(a1, Sibling1.class) && AnnotationUtils.areSameByClass(a2, SiblingWithFields.class)) || (AnnotationUtils.areSameByClass(a1, SiblingWithFields.class) && AnnotationUtils.areSameByClass(a2, Sibling2.class)) || (AnnotationUtils.areSameByClass(a1, Sibling2.class) && AnnotationUtils.areSameByClass(a2, SiblingWithFields.class))) { return PARENT; } return super.leastUpperBound(a1, a2); } @Override public boolean isSubtype(AnnotationMirror subAnno, AnnotationMirror superAnno) { if (AnnotationUtils.areSame(subAnno, superAnno) || AnnotationUtils.areSameByClass(superAnno, UnknownClass.class) || AnnotationUtils.areSameByClass(subAnno, WholeProgramInferenceBottom.class) || AnnotationUtils.areSameByClass(superAnno, Top.class)) { return true; } if (AnnotationUtils.areSameByClass(subAnno, UnknownClass.class) || AnnotationUtils.areSameByClass( superAnno, WholeProgramInferenceBottom.class)) { return false; } if (AnnotationUtils.areSameByClass(subAnno, Top.class)) { return false; } if (AnnotationUtils.areSameByClass(subAnno, ImplicitAnno.class) && (AnnotationUtils.areSameByClass(superAnno, Sibling1.class) || AnnotationUtils.areSameByClass(superAnno, Sibling2.class) || AnnotationUtils.areSameByClass( superAnno, SiblingWithFields.class))) { return true; } if ((AnnotationUtils.areSameByClass(subAnno, Sibling1.class) || AnnotationUtils.areSameByClass(subAnno, Sibling2.class) || AnnotationUtils.areSameByClass(subAnno, ImplicitAnno.class) || AnnotationUtils.areSameByClass(subAnno, SiblingWithFields.class)) && AnnotationUtils.areSameByClass(superAnno, Parent.class)) { return true; } if ((AnnotationUtils.areSameByClass(subAnno, Sibling1.class) || AnnotationUtils.areSameByClass(subAnno, Sibling2.class) || AnnotationUtils.areSameByClass(subAnno, ImplicitAnno.class) || AnnotationUtils.areSameByClass(subAnno, SiblingWithFields.class) || AnnotationUtils.areSameByClass(subAnno, Parent.class)) && AnnotationUtils.areSameByClass(superAnno, DefaultType.class)) { return true; } if (AnnotationUtils.areSameByClass(subAnno, SiblingWithFields.class) && AnnotationUtils.areSameByClass(superAnno, SiblingWithFields.class)) { List<String> subVal1 = AnnotationUtils.getElementValueArray(subAnno, "value", String.class, true); List<String> supVal1 = AnnotationUtils.getElementValueArray( superAnno, "value", String.class, true); String subVal2 = AnnotationUtils.getElementValue(subAnno, "value2", String.class, true); String supVal2 = AnnotationUtils.getElementValue(superAnno, "value2", String.class, true); return subVal1.equals(supVal1) && subVal2.equals(supVal2); } return false; } } }