framework.src.org.checkerframework.framework.type.typeannotator.ImplicitsTypeAnnotator Maven / Gradle / Ivy
Show all versions of checker Show documentation
package org.checkerframework.framework.type.typeannotator;
import org.checkerframework.framework.qual.ImplicitFor;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.ErrorReporter;
import org.checkerframework.javacutil.TypesUtils;
import java.lang.annotation.Annotation;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import com.sun.source.tree.Tree;
/**
* Adds annotations to a type based on the contents of a type. By default, this
* class honors the {@link ImplicitFor} annotation and applies implicit
* annotations specified by {@link ImplicitFor} for any type whose visitor is
* not overridden or does not call {@code super}; it is designed to be invoked
* from
* {@link org.checkerframework.framework.type.AnnotatedTypeFactory#addComputedTypeAnnotations(Element, org.checkerframework.framework.type.AnnotatedTypeMirror)}
* and
* {@link org.checkerframework.framework.type.AnnotatedTypeFactory#addComputedTypeAnnotations(Tree, org.checkerframework.framework.type.AnnotatedTypeMirror)}.
*
*
*
* {@link ImplicitsTypeAnnotator} traverses types deeply by default, except that it skips
* the method receiver of executable types (for interoperability with
* {@link org.checkerframework.framework.type.AnnotatedTypeFactory#annotateInheritedFromClass(org.checkerframework.framework.type.AnnotatedTypeMirror)}).
*
* This class takes care of two of the attributes of {@link ImplicitFor};
* the others are handled in {@link org.checkerframework.framework.type.treeannotator.TreeAnnotator}.
*
* @see org.checkerframework.framework.type.treeannotator.TreeAnnotator
*/
public class ImplicitsTypeAnnotator extends TypeAnnotator {
private final Map> typeKinds;
private final Map, Set> typeClasses;
private final Map> typeNames;
private final QualifierHierarchy qualHierarchy;
// private final AnnotatedTypeFactory atypeFactory;
/**
* Creates a {@link ImplicitsTypeAnnotator} from the given checker, using
* that checker to determine the annotations that are in the type hierarchy.
*/
public ImplicitsTypeAnnotator(AnnotatedTypeFactory typeFactory) {
super(typeFactory);
this.typeKinds = new EnumMap>(TypeKind.class);
this.typeClasses = new HashMap, Set>();
this.typeNames = new IdentityHashMap>();
this.qualHierarchy = typeFactory.getQualifierHierarchy();
// this.atypeFactory = atypeFactory;
// Get type qualifiers from the checker.
Set> quals = typeFactory.getSupportedTypeQualifiers();
// For each qualifier, read the @ImplicitFor annotation and put its type
// classes and kinds into maps.
for (Class qual : quals) {
ImplicitFor implicit = qual.getAnnotation(ImplicitFor.class);
if (implicit == null) continue;
AnnotationMirror theQual = AnnotationUtils.fromClass(typeFactory.getElementUtils(), qual);
for (TypeKind typeKind : implicit.types()) {
addTypeKind(typeKind, theQual);
}
for (Class typeName : implicit.typeNames()) {
addTypeName(typeName, theQual);
}
}
}
public void addTypeKind(TypeKind typeKind, AnnotationMirror theQual) {
boolean res = qualHierarchy.updateMappingToMutableSet(typeKinds, typeKind, theQual);
if (!res) {
ErrorReporter.errorAbort("TypeAnnotator: invalid update of typeKinds " +
typeKinds + " at " + typeKind + " with " + theQual);
}
}
public void addTypeClass(Class typeClass, AnnotationMirror theQual) {
boolean res = qualHierarchy.updateMappingToMutableSet(typeClasses, typeClass, theQual);
if (!res) {
ErrorReporter.errorAbort("TypeAnnotator: invalid update of typeClasses " +
typeClasses + " at " + typeClass + " with " + theQual);
}
}
public void addTypeName(Class typeName, AnnotationMirror theQual) {
String typeNameString = typeName.getCanonicalName().intern();
boolean res = qualHierarchy.updateMappingToMutableSet(typeNames, typeNameString, theQual);
if (!res) {
ErrorReporter.errorAbort("TypeAnnotator: invalid update of typeNames " +
typeNames + " at " + typeName + " with " + theQual);
}
}
@Override
protected Void scan(AnnotatedTypeMirror type, Void p) {
if (type == null) // on bounds, etc.
return super.scan(type, p);
// If the type's fully-qualified name is in the appropriate map, annotate
// the type. Do this before looking at kind or class, as this information
// is more specific.
String qname = null;
if (type.getKind() == TypeKind.DECLARED) {
qname = TypesUtils.getQualifiedName((DeclaredType)type.getUnderlyingType()).toString();
} else if (type.getKind().isPrimitive()) {
qname = type.getUnderlyingType().toString();
}
qname = (qname == null) ? null : qname.intern();
if (qname != null && typeNames.containsKey(qname)) {
Set fnd = typeNames.get(qname);
type.addMissingAnnotations(fnd);
}
// If the type's kind or class is in the appropriate map, annotate the
// type.
if (typeKinds.containsKey(type.getKind())) {
Set fnd = typeKinds.get(type.getKind());
type.addMissingAnnotations(fnd);
} else if (!typeClasses.isEmpty()) {
Class t = type.getClass();
if (typeClasses.containsKey(t)) {
Set fnd = typeClasses.get(t);
type.addMissingAnnotations(fnd);
}
}
return super.scan(type, p);
}
}