blob: 1c0c68d4e73c6417c99d5307ddd1cf60223a40b2 [file] [log] [blame]
package org.checkerframework.checker.fenum;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.util.Elements;
import org.checkerframework.checker.fenum.qual.Fenum;
import org.checkerframework.checker.fenum.qual.FenumBottom;
import org.checkerframework.checker.fenum.qual.FenumTop;
import org.checkerframework.checker.fenum.qual.FenumUnqualified;
import org.checkerframework.checker.fenum.qual.PolyFenum;
import org.checkerframework.checker.initialization.qual.UnderInitialization;
import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.framework.type.MostlyNoElementQualifierHierarchy;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.util.DefaultQualifierKindHierarchy;
import org.checkerframework.framework.util.QualifierKind;
import org.checkerframework.framework.util.QualifierKindHierarchy;
import org.checkerframework.javacutil.AnnotationBuilder;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.UserError;
import org.plumelib.reflection.Signatures;
/** The type factory for the Fenum Checker. */
public class FenumAnnotatedTypeFactory extends BaseAnnotatedTypeFactory {
/** AnnotationMirror for {@link FenumUnqualified}. */
protected AnnotationMirror FENUM_UNQUALIFIED;
/** AnnotationMirror for {@link FenumBottom}. */
protected AnnotationMirror FENUM_BOTTOM;
/** AnnotationMirror for {@link FenumTop}. */
protected AnnotationMirror FENUM_TOP;
/**
* Create a FenumAnnotatedTypeFactory.
*
* @param checker checker
*/
public FenumAnnotatedTypeFactory(BaseTypeChecker checker) {
super(checker);
FENUM_BOTTOM = AnnotationBuilder.fromClass(elements, FenumBottom.class);
FENUM_UNQUALIFIED = AnnotationBuilder.fromClass(elements, FenumUnqualified.class);
FENUM_TOP = AnnotationBuilder.fromClass(elements, FenumTop.class);
this.postInit();
}
/**
* Copied from SubtypingChecker. Instead of returning an empty set if no "quals" option is given,
* we return Fenum as the only qualifier.
*
* @return the supported type qualifiers
*/
@Override
protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() {
// Load everything in qual directory, and top, bottom, unqualified, and fake enum
Set<Class<? extends Annotation>> qualSet =
getBundledTypeQualifiers(
FenumTop.class,
Fenum.class,
FenumUnqualified.class,
FenumBottom.class,
PolyFenum.class);
// Load externally defined quals given in the -Aquals and/or -AqualDirs options
String qualNames = checker.getOption("quals");
String qualDirectories = checker.getOption("qualDirs");
// load individually named qualifiers
if (qualNames != null) {
for (String qualName : qualNames.split(",")) {
if (!Signatures.isBinaryName(qualName)) {
throw new UserError("Malformed qualifier \"%s\" in -Aquals=%s", qualName, qualNames);
}
qualSet.add(loader.loadExternalAnnotationClass(qualName));
}
}
// load directories of qualifiers
if (qualDirectories != null) {
for (String dirName : qualDirectories.split(":")) {
qualSet.addAll(loader.loadExternalAnnotationClassesFromDirectory(dirName));
}
}
// TODO: warn if no qualifiers given?
// Just Fenum("..") is still valid, though...
return qualSet;
}
@Override
public QualifierHierarchy createQualifierHierarchy() {
return new FenumQualifierHierarchy(getSupportedTypeQualifiers(), elements);
}
/** Fenum qualifier hierarchy. */
protected class FenumQualifierHierarchy extends MostlyNoElementQualifierHierarchy {
/** QualifierKind for {@link Fenum} qualifier. */
private final QualifierKind FENUM_KIND;
/**
* Creates FenumQualifierHierarchy.
*
* @param qualifierClasses qualifier classes
* @param elements element utils
*/
public FenumQualifierHierarchy(
Collection<Class<? extends Annotation>> qualifierClasses, Elements elements) {
super(qualifierClasses, elements);
this.FENUM_KIND =
this.qualifierKindHierarchy.getQualifierKind(Fenum.class.getCanonicalName());
}
@Override
protected QualifierKindHierarchy createQualifierKindHierarchy(
@UnderInitialization FenumQualifierHierarchy this,
Collection<Class<? extends Annotation>> qualifierClasses) {
return new DefaultQualifierKindHierarchy(qualifierClasses, FenumBottom.class);
}
@Override
protected boolean isSubtypeWithElements(
AnnotationMirror subAnno,
QualifierKind subKind,
AnnotationMirror superAnno,
QualifierKind superKind) {
return AnnotationUtils.areSame(subAnno, superAnno);
}
@Override
protected AnnotationMirror leastUpperBoundWithElements(
AnnotationMirror a1,
QualifierKind qualifierKind1,
AnnotationMirror a2,
QualifierKind qualifierKind2,
QualifierKind lubKind) {
if (qualifierKind1 == FENUM_KIND && qualifierKind2 == FENUM_KIND) {
if (AnnotationUtils.areSame(a1, a2)) {
return a1;
}
return FENUM_TOP;
} else if (qualifierKind1 == FENUM_KIND) {
return a1;
} else if (qualifierKind2 == FENUM_KIND) {
return a2;
}
throw new BugInCF("Unexpected QualifierKinds %s %s", qualifierKind1, qualifierKind2);
}
@Override
protected AnnotationMirror greatestLowerBoundWithElements(
AnnotationMirror a1,
QualifierKind qualifierKind1,
AnnotationMirror a2,
QualifierKind qualifierKind2,
QualifierKind glbKind) {
if (qualifierKind1 == FENUM_KIND && qualifierKind2 == FENUM_KIND) {
return FENUM_BOTTOM;
} else if (qualifierKind1 == FENUM_KIND) {
return a2;
} else if (qualifierKind2 == FENUM_KIND) {
return a1;
}
throw new BugInCF("Unexpected QualifierKinds %s %s", qualifierKind1, qualifierKind2);
}
}
}