org.checkerframework.framework.type.AnnotatedTypeReplacer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checker Show documentation
Show all versions of checker Show documentation
The Checker Framework enhances Java's type system to
make it more powerful and useful. This lets software developers
detect and prevent errors in their Java programs.
The Checker Framework includes compiler plug-ins ("checkers")
that find bugs or verify their absence. It also permits you to
write your own compiler plug-ins.
package org.checkerframework.framework.type;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.framework.type.visitor.DoubleAnnotatedTypeScanner;
import org.checkerframework.javacutil.BugInCF;
/**
* Replaces or adds all the annotations in the parameter with the annotations from the visited type.
* An annotation is replaced if the parameter type already has an annotation in the same hierarchy
* at the same location as the visited type.
*
* Example use:
*
*
{@code
* AnnotatedTypeMirror visitType = ...;
* AnnotatedTypeMirror parameter = ...;
* visitType.accept(new AnnotatedTypeReplacer(), parameter);
* }
*/
public class AnnotatedTypeReplacer extends DoubleAnnotatedTypeScanner {
/**
* Replaces or adds all annotations from {@code from} to {@code to}. Annotations from {@code from}
* will be used everywhere they exist, but annotations in {@code to} will be kept anywhere that
* {@code from} is unannotated.
*
* @param from the annotated type mirror from which to take new annotations
* @param to the annotated type mirror to which the annotations will be added
* @deprecated use {@link AnnotatedTypeFactory#replaceAnnotations(AnnotatedTypeMirror,
* AnnotatedTypeMirror)} instead.
*/
@Deprecated // 2021-03-25
@SuppressWarnings("interning:not.interned") // assertion
public static void replace(final AnnotatedTypeMirror from, final AnnotatedTypeMirror to) {
if (from == to) {
throw new BugInCF("From == to");
}
new AnnotatedTypeReplacer().visit(from, to);
}
/**
* Replaces or adds annotations in {@code top}'s hierarchy from {@code from} to {@code to}.
* Annotations from {@code from} will be used everywhere they exist, but annotations in {@code to}
* will be kept anywhere that {@code from} is unannotated.
*
* @param from the annotated type mirror from which to take new annotations
* @param to the annotated type mirror to which the annotations will be added
* @param top the top type of the hierarchy whose annotations will be added
* @deprecated use {@link AnnotatedTypeFactory#replaceAnnotations(AnnotatedTypeMirror,
* AnnotatedTypeMirror, AnnotationMirror)} instead.
*/
@Deprecated // 2021-03-25
@SuppressWarnings("interning:not.interned") // assertion
public static void replace(
final AnnotatedTypeMirror from, final AnnotatedTypeMirror to, final AnnotationMirror top) {
if (from == to) {
throw new BugInCF("from == to: %s", from);
}
new AnnotatedTypeReplacer(top).visit(from, to);
}
/** If top != null we replace only the annotations in the hierarchy of top. */
private AnnotationMirror top;
/** Construct an AnnotatedTypeReplacer that will replace all annotations. */
public AnnotatedTypeReplacer() {
this.top = null;
}
/**
* Construct an AnnotatedTypeReplacer that will only replace annotations in {@code top}'s
* hierarchy.
*
* @param top if top != null, then only annotation in the hierarchy of top are affected
*/
public AnnotatedTypeReplacer(final AnnotationMirror top) {
this.top = top;
}
/**
* If {@code top != null}, then only annotations in the hierarchy of {@code top} are affected;
* otherwise, all annotations are replaced.
*
* @param top if top != null, then only annotations in the hierarchy of top are replaced;
* otherwise, all annotations are replaced.
*/
public void setTop(@Nullable AnnotationMirror top) {
this.top = top;
}
@SuppressWarnings("interning:not.interned") // assertion
@Override
protected Void defaultAction(AnnotatedTypeMirror from, AnnotatedTypeMirror to) {
assert from != to;
if (from != null && to != null) {
replaceAnnotations(from, to);
}
return null;
}
/**
* Replace the annotations in to with the annotations in from, wherever from has an annotation.
*
* @param from the source of the annotations
* @param to the destination of the annotations, modified by this method
*/
protected void replaceAnnotations(final AnnotatedTypeMirror from, final AnnotatedTypeMirror to) {
if (top == null) {
to.replaceAnnotations(from.getAnnotations());
} else {
final AnnotationMirror replacement = from.getAnnotationInHierarchy(top);
if (replacement != null) {
to.replaceAnnotation(from.getAnnotationInHierarchy(top));
}
}
}
@Override
public Void visitTypeVariable(AnnotatedTypeVariable from, AnnotatedTypeMirror to) {
resolvePrimaries(from, to);
return super.visitTypeVariable(from, to);
}
@Override
public Void visitWildcard(AnnotatedWildcardType from, AnnotatedTypeMirror to) {
resolvePrimaries(from, to);
return super.visitWildcard(from, to);
}
/**
* For type variables and wildcards, the absence of a primary annotations has an implied meaning
* on substitution. Therefore, in these cases we remove the primary annotation and rely on the
* fact that the bounds are also merged into the type to.
*
* @param from a type variable or wildcard
* @param to the destination annotated type mirror
*/
public void resolvePrimaries(AnnotatedTypeMirror from, AnnotatedTypeMirror to) {
if (from.getKind() == TypeKind.WILDCARD || from.getKind() == TypeKind.TYPEVAR) {
if (top != null) {
if (from.getAnnotationInHierarchy(top) == null) {
to.removeAnnotationInHierarchy(top);
}
} else {
for (final AnnotationMirror toPrimaryAnno : to.getAnnotations()) {
if (from.getAnnotationInHierarchy(toPrimaryAnno) == null) {
to.removeAnnotation(toPrimaryAnno);
}
}
}
} else {
throw new BugInCF(
"ResolvePrimaries's from argument should be a type variable OR wildcard%n"
+ "from=%s%nto=%s",
from.toString(true), to.toString(true));
}
}
}