package org.checkerframework.framework.util; import java.util.Collection; import java.util.List; import java.util.Map; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.InvisibleQualifier; import org.checkerframework.javacutil.ErrorReporter; /** A utility for converting AnnotationMirrors to Strings. */ public class DefaultAnnotationFormatter implements AnnotationFormatter { /** * Returns true if, by default, anno should not be printed * * @see org.checkerframework.framework.qual.InvisibleQualifier * @return true if anno's declaration was qualified by InvisibleQualifier */ public static boolean isInvisibleQualified(AnnotationMirror anno) { return ((TypeElement) anno.getAnnotationType().asElement()) .getAnnotation(InvisibleQualifier.class) != null; } /** * Creates a space String of each annotation in annos separated by a single space character, * obeying the printInvisible parameter. * * @param annos a collection of annotations to print * @param printInvisible whether or not to print "invisible" annotation mirrors * @return the list of annotations converted to a String */ @Override @SideEffectFree public String formatAnnotationString( Collection<? extends AnnotationMirror> annos, boolean printInvisible) { StringBuilder sb = new StringBuilder(); for (AnnotationMirror obj : annos) { if (obj == null) { ErrorReporter.errorAbort( "AnnotatedTypeMirror.formatAnnotationString: found null AnnotationMirror!"); } if (isInvisibleQualified(obj) && !printInvisible) { continue; } formatAnnotationMirror(obj, sb); sb.append(" "); } return sb.toString(); } /** * @param anno the annotation mirror to convert * @return the string representation of a single AnnotationMirror, without showing full package * names */ @Override @SideEffectFree public String formatAnnotationMirror(AnnotationMirror anno) { StringBuilder sb = new StringBuilder(); formatAnnotationMirror(anno, sb); return sb.toString(); } /** A helper method to output a single AnnotationMirror, without showing full package names. */ protected void formatAnnotationMirror(AnnotationMirror am, StringBuilder sb) { sb.append("@"); sb.append(am.getAnnotationType().asElement().getSimpleName()); Map<? extends ExecutableElement, ? extends AnnotationValue> args = am.getElementValues(); if (!args.isEmpty()) { sb.append("("); boolean oneValue = false; if (args.size() == 1) { Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> first = args.entrySet().iterator().next(); if (first.getKey().getSimpleName().contentEquals("value")) { formatAnnotationMirrorArg(first.getValue(), sb); oneValue = true; } } if (!oneValue) { boolean notfirst = false; for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> arg : args.entrySet()) { if (notfirst) { sb.append(", "); } notfirst = true; sb.append(arg.getKey().getSimpleName() + "="); formatAnnotationMirrorArg(arg.getValue(), sb); } } sb.append(")"); } } // A helper method to print AnnotationValues (annotation arguments), without showing full package names. @SuppressWarnings("unchecked") protected void formatAnnotationMirrorArg(AnnotationValue av, StringBuilder sb) { Object val = av.getValue(); if (List.class.isAssignableFrom(val.getClass())) { List<AnnotationValue> vallist = (List<AnnotationValue>) val; if (vallist.size() == 1) { formatAnnotationMirrorArg(vallist.get(0), sb); } else { sb.append('{'); boolean notfirst = false; for (AnnotationValue nav : vallist) { if (notfirst) { sb.append(", "); } notfirst = true; formatAnnotationMirrorArg(nav, sb); } sb.append('}'); } } else if (VariableElement.class.isAssignableFrom(val.getClass())) { VariableElement ve = (VariableElement) val; sb.append(ve.getEnclosingElement().getSimpleName() + "." + ve.getSimpleName()); } else { sb.append(av.toString()); } } }