blob: a49c95056062e595510d5b52af6c1252474cb159 [file] [log] [blame]
package org.checkerframework.framework.util.element;
import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Attribute.TypeCompound;
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;
import org.checkerframework.framework.util.element.ElementAnnotationUtil.UnexpectedAnnotationLocationException;
import org.checkerframework.javacutil.TypesUtils;
/** 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)
throws UnexpectedAnnotationLocationException {
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;
/**
* Returns true if type is an annotated declared type and element is a ClassSymbol.
*
* @param type a type
* @param element an element
* @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[] {
TargetType.RESOURCE_VARIABLE,
TargetType.EXCEPTION_PARAMETER,
TargetType.NEW,
TargetType.CAST,
TargetType.INSTANCEOF,
TargetType.METHOD_INVOCATION_TYPE_ARGUMENT,
TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT,
TargetType.METHOD_REFERENCE,
TargetType.CONSTRUCTOR_REFERENCE,
TargetType.METHOD_REFERENCE_TYPE_ARGUMENT,
TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT,
TargetType.CLASS_TYPE_PARAMETER,
TargetType.CLASS_TYPE_PARAMETER_BOUND
};
}
@Override
protected TargetType[] annotatedTargets() {
return new TargetType[] {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<TypeCompound> extendsAndImplementsAnnos)
throws UnexpectedAnnotationLocationException {
if (TypesUtils.isAnonymous(typeSymbol.type)) {
// If this is an anonymous class, then the annotations after "new" but before the class name
// are stored as super class annotations. Treat them as annotations on the class.
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() throws UnexpectedAnnotationLocationException {
// 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());
ElementAnnotationUtil.applyAllElementAnnotations(
declaredType.getTypeArguments(), typeSymbol.getTypeParameters(), typeFactory);
}
@Override
protected boolean isAccepted() {
return accepts(type, element);
}
}