package checkers.fenum; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.annotation.processing.SupportedOptions; import checkers.fenum.quals.FenumTop; import checkers.fenum.quals.Fenum; import checkers.fenum.quals.FenumUnqualified; import checkers.fenum.quals.FenumBottom; import checkers.types.AnnotatedTypeMirror.AnnotatedDeclaredType; import checkers.basetype.BaseTypeChecker; /** * The main checker class for the fake enum checker. * * There are two options to distinguish different enumerators: * * <ol> * <li> {@code @Fenum("Name")}: introduces a fake enumerator with the name * "Name". Enumerators with different names are distinct. The default name is * empty, but you are encouraged to use a unique name for your purpose. * </li> * * <li> Alternatively, you can specify the annotation to use with the * {@code -Aqual} command line argument. * </li> * </ul> * * @author wmdietl */ @SupportedOptions( { "quals" } ) public class FenumChecker extends BaseTypeChecker { /** Copied from BasicChecker. * Instead of returning an empty set if no "quals" option is given, * we return Fenum as the only qualifier. */ @Override @SuppressWarnings("unchecked") protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() { Set<Class<? extends Annotation>> qualSet = new HashSet<Class<? extends Annotation>>(); String qualNames = env.getOptions().get("quals"); if (qualNames == null) { // maybe issue a warning? qualSet.add(FenumTop.class); qualSet.add(Fenum.class); qualSet.add(FenumUnqualified.class); qualSet.add(FenumBottom.class); } else { try { for (String qualName : qualNames.split(",")) { final Class<? extends Annotation> q = (Class<? extends Annotation>) Class.forName(qualName); qualSet.add(q); } } catch (ClassNotFoundException e) { throw new Error(e); } qualSet.add(FenumTop.class); qualSet.add(Fenum.class); qualSet.add(FenumUnqualified.class); qualSet.add(FenumBottom.class); } return Collections.unmodifiableSet(qualSet); } /** Copied from BasicChecker; cannot reuse it, because BasicChecker is final. */ @Override public Collection<String> getSuppressWarningsKey() { Set<String> swKeys = new HashSet<String>(); Set<Class<? extends Annotation>> annos = getSupportedTypeQualifiers(); if (annos.isEmpty()) return super.getSuppressWarningsKey(); for (Class<? extends Annotation> anno : annos) swKeys.add(anno.getSimpleName().toLowerCase()); return swKeys; } @Override public boolean isValidUse(AnnotatedDeclaredType declarationType, AnnotatedDeclaredType useType) { // The checker calls this method to compare the annotation used in a // type to the modifier it adds to the class declaration. As our default // modifier is Unqualified, this results in an error when a non-subtype // is used. Just ignore this check here and do them manually in the // visitor. return true; } }