package org.checkerframework.framework.util.element;
import static com.sun.tools.javac.code.TargetType.CAST;
import static com.sun.tools.javac.code.TargetType.CLASS_EXTENDS;
import static com.sun.tools.javac.code.TargetType.CLASS_TYPE_PARAMETER;
import static com.sun.tools.javac.code.TargetType.CLASS_TYPE_PARAMETER_BOUND;
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.INSTANCEOF;
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.applyAllElementAnnotations;
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 org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
/** Apply annotations to a declared type based on its declaration. */
public class TypeDeclarationApplier extends TargetedElementAnnotationApplier {
public static void apply(
final AnnotatedTypeMirror type,
final Element element,
final AnnotatedTypeFactory typeFactory) {
new TypeDeclarationApplier(type, element, typeFactory).extractAndApply();
}
/**
* If a type_index == -1 it means that the index refers to the immediate supertype class of the
* declaration. There is only ever one of these since java has no multiple inheritance
*/
public static final int SUPERCLASS_INDEX = -1;
/** @return true if type is an annotated declared type and element is a ClassSymbol */
public static boolean accepts(final AnnotatedTypeMirror type, final Element element) {
return type instanceof AnnotatedDeclaredType && element instanceof Symbol.ClassSymbol;
}
private final AnnotatedTypeFactory typeFactory;
private final Symbol.ClassSymbol typeSymbol;
private final AnnotatedDeclaredType declaredType;
TypeDeclarationApplier(
final AnnotatedTypeMirror type,
final Element element,
final AnnotatedTypeFactory typeFactory) {
super(type, element);
this.typeFactory = typeFactory;
this.typeSymbol = (Symbol.ClassSymbol) element;
this.declaredType = (AnnotatedDeclaredType) type;
}
@Override
protected TargetType[] validTargets() {
return new TargetType[] {
RESOURCE_VARIABLE,
EXCEPTION_PARAMETER,
NEW,
CAST,
INSTANCEOF,
METHOD_INVOCATION_TYPE_ARGUMENT,
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT,
METHOD_REFERENCE,
CONSTRUCTOR_REFERENCE,
METHOD_REFERENCE_TYPE_ARGUMENT,
CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT,
CLASS_TYPE_PARAMETER,
CLASS_TYPE_PARAMETER_BOUND
};
}
@Override
protected TargetType[] annotatedTargets() {
return new TargetType[] {CLASS_EXTENDS};
}
/** All TypeCompounds (annotations) on the ClassSymbol */
@Override
protected Iterable<Attribute.TypeCompound> getRawTypeAttributes() {
return typeSymbol.getRawTypeAttributes();
}
/**
* While more than just annotations on extends or implements clause are annotated by this class,
* only these annotations are passed to handleTargeted (as they are the only in the
* annotatedTargets list). See extractAndApply for type parameters
*
* @param extendsAndImplementsAnnos annotations with a TargetType of CLASS_EXTENDS
*/
@Override
protected void handleTargeted(List<Attribute.TypeCompound> extendsAndImplementsAnnos) {
for (final Attribute.TypeCompound anno : extendsAndImplementsAnnos) {
if (anno.position.type_index >= SUPERCLASS_INDEX && anno.position.location.isEmpty()) {
type.addAnnotation(anno);
}
}
}
/** Adds extends/implements and class annotations to type. Annotates type parameters. */
@Override
public void extractAndApply() {
// ensures that we check that there only valid target types on this class, there are no "targeted" locations
super.extractAndApply();
// Annotate raw types //TODO: ASK WERNER WHAT THIS MIGHT MEAN? WHAT ACTUALLY GOES HERE?
type.addAnnotations(typeSymbol.getAnnotationMirrors());
applyAllElementAnnotations(
declaredType.getTypeArguments(), typeSymbol.getTypeParameters(), typeFactory);
}
@Override
protected boolean isAccepted() {
return accepts(type, element);
}
}