package org.checkerframework.framework.util.element; import static com.sun.tools.javac.code.TargetType.CAST; import static com.sun.tools.javac.code.TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; import static com.sun.tools.javac.code.TargetType.CONSTRUCTOR_REFERENCE; import static com.sun.tools.javac.code.TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT; import static com.sun.tools.javac.code.TargetType.EXCEPTION_PARAMETER; import static com.sun.tools.javac.code.TargetType.FIELD; import static com.sun.tools.javac.code.TargetType.INSTANCEOF; import static com.sun.tools.javac.code.TargetType.LOCAL_VARIABLE; import static com.sun.tools.javac.code.TargetType.METHOD_INVOCATION_TYPE_ARGUMENT; import static com.sun.tools.javac.code.TargetType.METHOD_REFERENCE; import static com.sun.tools.javac.code.TargetType.METHOD_REFERENCE_TYPE_ARGUMENT; import static com.sun.tools.javac.code.TargetType.NEW; import static com.sun.tools.javac.code.TargetType.RESOURCE_VARIABLE; import static org.checkerframework.framework.util.element.ElementAnnotationUtil.addAnnotationsFromElement; import static org.checkerframework.framework.util.element.ElementAnnotationUtil.annotateViaTypeAnnoPosition; import static org.checkerframework.framework.util.element.ElementAnnotationUtil.contains; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.TargetType; import java.util.List; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.type.TypeKind; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.javacutil.ErrorReporter; /** * Applies annotations to variable declaration (providing they are not the use of a TYPE_PARAMETER). */ public class VariableApplier extends TargetedElementAnnotationApplier { public static void apply(final AnnotatedTypeMirror type, final Element element) { new VariableApplier(type, element).extractAndApply(); } private static final ElementKind[] acceptedKinds = { ElementKind.LOCAL_VARIABLE, ElementKind.RESOURCE_VARIABLE, ElementKind.EXCEPTION_PARAMETER }; /** @return true if this is a variable declaration including fields an enum constants */ public static boolean accepts(final AnnotatedTypeMirror typeMirror, final Element element) { return contains(element.getKind(), acceptedKinds) || element.getKind().isField(); } private final Symbol.VarSymbol varSymbol; VariableApplier(final AnnotatedTypeMirror type, final Element element) { super(type, element); varSymbol = (Symbol.VarSymbol) element; if (type.getKind() == TypeKind.UNION && element.getKind() != ElementKind.EXCEPTION_PARAMETER) { ErrorReporter.errorAbort( "Union types only allowed for exception parameters! " + "Type: " + type + " for element: " + element); } // TODO: need a way to split the union types into the right alternative // to use for the annotation. The exception_index is probably what we // need to look at, but it might not be set at this point. } @Override protected TargetType[] annotatedTargets() { return new TargetType[] {LOCAL_VARIABLE, RESOURCE_VARIABLE, EXCEPTION_PARAMETER, FIELD}; } @Override protected TargetType[] validTargets() { return new TargetType[] { NEW, CAST, INSTANCEOF, METHOD_INVOCATION_TYPE_ARGUMENT, CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, METHOD_REFERENCE, CONSTRUCTOR_REFERENCE, METHOD_REFERENCE_TYPE_ARGUMENT, CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT }; } @Override protected Iterable<Attribute.TypeCompound> getRawTypeAttributes() { return varSymbol.getRawTypeAttributes(); } @Override protected boolean isAccepted() { return accepts(type, element); } @Override protected void handleTargeted(final List<Attribute.TypeCompound> targeted) { annotateViaTypeAnnoPosition(type, targeted); } @Override public void extractAndApply() { // Add declaration annotations to the local variable type addAnnotationsFromElement(type, varSymbol.getAnnotationMirrors()); super.extractAndApply(); } }