diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AbstractDBAnnotationValidator.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AbstractDBAnnotationValidator.java index 8cdf8a422c..3b5886c948 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AbstractDBAnnotationValidator.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AbstractDBAnnotationValidator.java @@ -20,13 +20,31 @@ import java.lang.annotation.Annotation; import javax.lang.model.element.*; import javax.tools.Diagnostic.Kind; +/** + * An abstract class for validating annotations on {@link DBAnnotatedObject}. + *

+ * Performs validation checks on annotated fields and their enclosing types. + *

+ */ public class AbstractDBAnnotationValidator { protected final ValidationContext ctx; + /** + * Construct a new {@code AbstractDBAnnotationValidator} with the specified validation context. + * + * @param ctx the validation context + */ public AbstractDBAnnotationValidator(ValidationContext ctx) { this.ctx = ctx; } + /** + * Check the enclosing type of the annotated field. + * + * @param annotType the type of the annotation being validated + * @param field the field being validated + * @param type the enclosing type of the field + */ protected void checkEnclosingType(Class annotType, VariableElement field, TypeElement type) { if (type.getKind() != ElementKind.CLASS) { diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AccessSpec.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AccessSpec.java index 8d07f21386..74c94a03d6 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AccessSpec.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/AccessSpec.java @@ -19,6 +19,10 @@ import java.util.Set; import javax.lang.model.element.Modifier; +/** + * An enum to represent different levels of access specifiers + * (private, package-private, protected, public) with corresponding access levels + */ public enum AccessSpec { PRIVATE(0), PACKAGE(1), PROTECTED(2), PUBLIC(3); @@ -29,7 +33,7 @@ public enum AccessSpec { } /** - * Checks if the second permits the same or more access than the first + * Check if the second permits the same or more access than the first * * @param first the first * @param second the second diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedColumnValidator.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedColumnValidator.java index a88c9e68af..ac128e35a8 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedColumnValidator.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedColumnValidator.java @@ -22,14 +22,40 @@ import javax.tools.Diagnostic.Kind; import ghidra.util.database.annot.DBAnnotatedColumn; +/** + * A class for validating fields annotated with {@link DBAnnotatedColumn} + *

+ * To ensure fields annotated with {@link DBAnnotatedColumn} + * comply with the expected criteria for database columns in Ghidra. + *

+ */ + public class DBAnnotatedColumnValidator extends AbstractDBAnnotationValidator { final VariableElement column; + /** + * Construct a new {@code DBAnnotatedColumnValidator} with the specified validation context and the column element. + * @param ctx + * @param column + */ public DBAnnotatedColumnValidator(ValidationContext ctx, VariableElement column) { super(ctx); this.column = column; } + /** + * Validate the annotated column field. + * + *

+ * It performs the following checks to ensure it meets the requirements for database columns: + *

+ *

+ */ public void validate() { if (!ctx.hasType(column, ctx.DB_OBJECT_COLUMN_ELEM)) { ctx.messager.printMessage(Kind.ERROR, diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedFieldValidator.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedFieldValidator.java index e9173d9378..49c9857fd9 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedFieldValidator.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedFieldValidator.java @@ -23,6 +23,14 @@ import javax.tools.Diagnostic.Kind; import ghidra.util.database.annot.DBAnnotatedField; +/** + * A class for validating fields annotated with {@link DBAnnotatedField} + *

+ * To ensure fields annotated with {@link DBAnnotatedField} meet the criteria required for database fields + * in Ghidra. It extends the {@code AbstractDBAnnotationValidator} to provide additional + * validation logic specific to database field annotations. + *

+ */ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { final VariableElement field; final Map javaToDBTypeMap; @@ -39,6 +47,11 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { final TypeElement ENUM_CODEC_ELEM; + /** + * Construct a new {@code DBAnnotatedFieldValidator} with the specified validation context and field element. + * @param ctx + * @param field + */ public DBAnnotatedFieldValidator(ValidationContext ctx, VariableElement field) { super(ctx); this.field = field; @@ -59,6 +72,13 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { ENUM_CODEC_ELEM = ctx.elementUtils.getTypeElement(ENUM_CODEC_NAME); } + /** + * Associate a primitive type and its boxed type with the specified codec type in the map. + * + * @param map the map linking java types to their corresponding codec types + * @param kind the primitive type kind + * @param codecName the fully qualified name of the codec type + */ protected void putPrimitiveTypeCodec(Map map, TypeKind kind, String codecName) { PrimitiveType primitive = ctx.typeUtils.getPrimitiveType(kind); @@ -68,12 +88,26 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { map.put(boxed, codec); } + /** + * Associate a specified class type with the specified codec type in the map. + * + * @param map the map linking Java types to their corresponding codec types + * @param cls the class type + * @param codecName the fully qualified name of the codec type + */ protected void putTypeCodec(Map map, Class cls, String codecName) { TypeMirror type = ctx.elementUtils.getTypeElement(cls.getCanonicalName()).asType(); TypeElement codec = ctx.elementUtils.getTypeElement(codecName); map.put(type, codec); } + /** + * Associate a primitive array type with the specified codec type inthe map. + * + * @param map the map linking Java types to their corresponding codec types + * @param kind the primitive type kind + * @param codecName the fully qualified name of the codec type + */ protected void putPrimitiveArrayTypeCodec(Map map, TypeKind kind, String codecName) { PrimitiveType primitive = ctx.typeUtils.getPrimitiveType(kind); @@ -82,6 +116,18 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { map.put(array, codec); } + /** + * Validate the annotated field to ensure it meets the requirements for database fields. + *

+ * It performs the following checks: + *

    + *
  • The field must not be declared as {@code final}.
  • + *
  • The field must not be declared as {@code static}.
  • + *
  • The enclosing type of the field must meet the criteria defined in {@code checkEnclosingType}.
  • + *
  • The codec types for the field must be appropriate.
  • + *
+ *

+ */ public void validate() { Set mods = field.getModifiers(); if (mods.contains(Modifier.FINAL)) { @@ -101,6 +147,12 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { checkCodecTypes(type); } + /** + * Return the default codec type element for the specified Java type. + * + * @param javaType the Java type for which the default codec is needed + * @return the default codec type element, or {@code null} if no default codec is found + */ protected TypeElement getDefaultCodecType(TypeMirror javaType) { if (ctx.isEnumType(javaType)) { return ENUM_CODEC_ELEM; @@ -108,6 +160,12 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { return javaToDBTypeMap.get(javaType); } + /** + * Return the codec type element specified in the {@link DBAnnotatedField} annotation + * for the field, or the default codec type if none is specified. + * + * @return the codec type element for the field + */ protected TypeElement getCodecTypeElement() { DBAnnotatedField annotation = field.getAnnotation(DBAnnotatedField.class); TypeElement codecElem; @@ -123,6 +181,11 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { return codecElem; } + /** + * Check the codec types associated with the field to ensure they meet the necessary requirements. + * + * @param objectType the type of the enclosing object + */ protected void checkCodecTypes(TypeElement objectType) { TypeElement codecType = getCodecTypeElement(); diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectProcessor.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectProcessor.java index 314bb1ad3b..70b67f3f00 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectProcessor.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectProcessor.java @@ -29,8 +29,12 @@ import ghidra.util.database.annot.*; /** * A compile-time annotation processor for {@link DBAnnotatedObject}-related annotations. * - * Currently just performs compile-time checks. It does not generate any code, but perhaps one day, - * it will. + *

+ * This processor performs compile-time validation checks on annotations related to + * {@link DBAnnotatedObject}. + * Currently just performs compile-time checks. It does not generate any code, but perhaps one day, + * it will. + *

*/ //@AutoService(Processor.class) // TODO: Evaluate Google's auto-service as a dependency public class DBAnnotatedObjectProcessor extends AbstractProcessor { @@ -39,6 +43,11 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor { private ValidationContext ctx; + /** + * Initialize the processor with the given preprocessing environment. + * + * @param env the processing environment + */ @Override public synchronized void init(ProcessingEnvironment env) { //System.err.println("HERE4"); @@ -46,6 +55,13 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor { ctx = new ValidationContext(env); } + /** + * Process the specified annotations for the current round of processing.. + * + * @param annotations the set of annotations to process + * @param roundEnv the environment for information about the current and prior round + * @return {@code true} if the annotations are claimed by this processor, {@code false} otherwise + */ @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { Map types = new LinkedHashMap<>(); @@ -76,6 +92,15 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor { return true; } + /** + * Provide completion suggestion for the specified element, annotation, and member. + * + * @param element the element being annotated + * @param annotation the annotation being processed + * @param member the annotation member being completed + * @param userText the text entered by the user + * @return an iterable of completions. + */ @Override public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { @@ -83,11 +108,21 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor { return super.getCompletions(element, annotation, member, userText); } + /** + * Return the latest supported source version. + * + * @return the latest supported source version + */ @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } + /** + * Return the set of supported annotation types. + * + * @return the set of supported annotation types + */ @Override public Set getSupportedAnnotationTypes() { return SUPPORTED_ANNOTATIONS.stream().map(Class::getCanonicalName).collect( diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectValidator.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectValidator.java index 6de69c6af6..5066626206 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectValidator.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/DBAnnotatedObjectValidator.java @@ -22,29 +22,57 @@ import javax.tools.Diagnostic.Kind; import ghidra.util.database.annot.*; +/** + * Validate {@link DBAnnotatedObject}-related annotations on a given type element. + *

+ * This class ensures that annotations such as {@link DBAnnotatedField}, {@link DBAnnotatedColumn}, + * and {@link DBAnnotatedObjectInfo} are applied correctly and consistently on the fields and columns + * of a class. + *

+ */ public class DBAnnotatedObjectValidator { private final ValidationContext ctx; private final TypeElement type; private final Map fieldsByName = new LinkedHashMap<>(); private final Map columnsByName = new LinkedHashMap<>(); + /** + * Construct a new validator for the given type element within the specified validation context + * + * @param ctx the validation context + * @param type the type element to be validated + */ public DBAnnotatedObjectValidator(ValidationContext ctx, TypeElement type) { this.ctx = ctx; this.type = type; } + /** + * Add a field annotated with {@link DBAnnotatedField} to be validator. + * + * @param field the field element annotated with {@link DBAnnotatedField} + */ public void addAnnotatedField(VariableElement field) { DBAnnotatedField annotation = field.getAnnotation(DBAnnotatedField.class); assert annotation != null; fieldsByName.put(annotation.column(), new DBAnnotatedFieldValidator(ctx, field)); } + /** + * Add a column annotated with {@link DBAnnotatedColumn} to the validator. + * + * @param column the field element annotated with {@link DBAnnotatedColumn} + */ public void addAnnotatedColumn(VariableElement column) { DBAnnotatedColumn annotation = column.getAnnotation(DBAnnotatedColumn.class); assert annotation != null; columnsByName.put(annotation.value(), new DBAnnotatedColumnValidator(ctx, column)); } + /** + * Validate the annotated fields, columns, and the type element itself. + * Checks for various annotation constraints and consistency rules. + */ public void validate() { DBAnnotatedObjectInfo annotation = type.getAnnotation(DBAnnotatedObjectInfo.class); if (annotation != null && type.getKind() != ElementKind.CLASS) { @@ -81,18 +109,27 @@ public class DBAnnotatedObjectValidator { checkMissing(); } + /** + * Validate all fields annotated with {@link DBAnnotatedField}. + */ protected void validateFields() { for (DBAnnotatedFieldValidator fv : fieldsByName.values()) { fv.validate(); } } + /** + * Validate all columns annotated with {@link DBAnnotatedColumn}. + */ protected void validateColumns() { for (DBAnnotatedColumnValidator cv : columnsByName.values()) { cv.validate(); } } + /** + * Check for missing corresponding annotations between fields and columns. + */ protected void checkMissing() { Set names = new LinkedHashSet<>(); names.addAll(fieldsByName.keySet()); @@ -121,6 +158,12 @@ public class DBAnnotatedObjectValidator { } + /** + * Check that the access specifiers of the field and column are compatible. + * @param field the field element + * @param column the column element + * @param name the name of the column + */ protected void checkAccess(VariableElement field, VariableElement column, String name) { AccessSpec fieldSpec = AccessSpec.get(field.getModifiers()); AccessSpec columnSpec = AccessSpec.get(column.getModifiers()); diff --git a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/ValidationContext.java b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/ValidationContext.java index 292d810a7d..c712382020 100644 --- a/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/ValidationContext.java +++ b/Ghidra/Debug/AnnotationValidator/src/main/java/ghidra/util/database/annotproc/ValidationContext.java @@ -38,6 +38,11 @@ public class ValidationContext { final TypeElement DEFAULT_CODEC_ELEM; final TypeElement ENUM_ELEM; + /** + * Construct a Validation Context with the specified processing environment/ + * + * @param env the processing environment + */ public ValidationContext(ProcessingEnvironment env) { typeUtils = env.getTypeUtils(); elementUtils = env.getElementUtils(); @@ -54,14 +59,35 @@ public class ValidationContext { ENUM_ELEM = elementUtils.getTypeElement(Enum.class.getCanonicalName()); } + /** + * Check if t1 is a subclass of t2. + * + * @param t1 the potential subclass + * @param t2 the potential superclass + * @return true if t1 is a subclass of t2, false otherwise + */ public boolean isSubclass(TypeElement t1, TypeElement t2) { return typeUtils.isSubtype(typeUtils.erasure(t1.asType()), typeUtils.erasure(t2.asType())); } + /** + * Check if the field has the specified type. + * + * @param field the field element + * @param type the type element + * @return true if the field has the specified type, false otherwise + */ public boolean hasType(VariableElement field, TypeElement type) { return hasType(field, type.asType()); } + /** + * Check if the field has the specified type. + * + * @param field the field element + * @param type the type mirror + * @return true if the field has the specified type, false otherwise + */ public boolean hasType(VariableElement field, TypeMirror type) { TypeMirror fieldType = field.asType(); try { @@ -86,9 +112,16 @@ public class ValidationContext { } return typeUtils.isAssignable(fieldType, type); -// return typeUtils.isSameType(fieldType, type); + // return typeUtils.isSameType(fieldType, type); } + /** + * Check if t1 is capturable by t2. + * + * @param t1 is the type to check + * @param t2 the capture target type + * @return true if t1 is capturable by t2, false otherwise + */ public boolean isCapturable(TypeMirror t1, TypeMirror t2) { // TODO: This only works for typevar at top level... // TODO: Need to figure out how to check for capture and check @@ -105,6 +138,12 @@ public class ValidationContext { return typeUtils.isSubtype(t1, t2); } + /** + * Check if the type is an enum type. + * + * @param t the type mirror to check + * @return true if the type is an enum type, false otherwise + */ public boolean isEnumType(TypeMirror t) { if (t.getKind() != TypeKind.DECLARED) { return false; @@ -113,6 +152,14 @@ public class ValidationContext { return typeUtils.isSubtype(t, enumType); } + /** + * Find the supertype of a set of declared types that matches the specified + * super type. + * + * @param types the set of declared types + * @param superType the super type element to match + * @return the matching declared type, or null if no match is found + */ protected DeclaredType findSupertype(Set types, TypeElement superType) { Set next; while (!types.isEmpty()) { @@ -132,14 +179,37 @@ public class ValidationContext { return null; } + /** + * Find the supertype of a declared type that matches the specified super type + * element. + * + * @param type the declared type + * @param superElem the super type element to match + * @return the matching declared type, or null if no match is found + */ public DeclaredType findSupertype(DeclaredType type, TypeElement superElem) { return findSupertype(Set.of(type), superElem); } + /** + * Find the supertype of a type element that matches the specified super type + * element. + * + * @param elem the type element + * @param superElem the super type element to match + * @return the matching declared type, or null if no match is found + */ public DeclaredType findSupertype(TypeElement elem, TypeElement superElem) { return findSupertype((DeclaredType) elem.asType(), superElem); } + /** + * Convert the type arguments of the super type element to a map. + * + * @param superElem the super type element + * @param superType the declared super type + * @return a map of type argument names to their corresponding type mirrors + */ protected Map toArgsMap(TypeElement superElem, DeclaredType superType) { List typeParameters = superElem.getTypeParameters(); List typeArguments = superType.getTypeArguments(); @@ -151,14 +221,34 @@ public class ValidationContext { return result; } + /** + * Get the type arguments of a declared type as a map. + * + * @param type the declared type + * @param superElem the super type element + * @return a map of type argument names to their corresponding type mirrors + */ public Map getArguments(DeclaredType type, TypeElement superElem) { return toArgsMap(superElem, findSupertype(type, superElem)); } + /** + * Get the type arguments of a type element as a map. + * + * @param elem the type element + * @param superElem the super type element + * @return a map of type argument names to their corresponding type mirrors + */ public Map getArguments(TypeElement elem, TypeElement superElem) { return toArgsMap(superElem, findSupertype(elem, superElem)); } + /** + * Format the given type mirror as a string. + * + * @param type the type mirror to format + * @return the formatted type mirror as a string + */ public String format(TypeMirror type) { FormatVisitor vis = new FormatVisitor(); type.accept(vis, null); @@ -166,9 +256,20 @@ public class ValidationContext { } } +/** + * Class for formatting {@link TypeMirror} instances into a readable string + */ class FormatVisitor implements TypeVisitor { StringBuffer buf = new StringBuffer(); + /** + * Visit method for {@link TypeMirror}. Delegates to specific visit methods + * based on the type kind. + * + * @param t the type mirror to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visit(TypeMirror t, Void p) { switch (t.getKind()) { @@ -207,18 +308,39 @@ class FormatVisitor implements TypeVisitor { } } + /** + * Visit method for {@link PrimitiveType}. + * + * @param t the primitive type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitPrimitive(PrimitiveType t, Void p) { buf.append(t.toString()); return null; } + /** + * Visit method for {@link NullType}. + * + * @param t the null type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitNull(NullType t, Void p) { buf.append(t.toString()); return null; } + /** + * Visit method for {@link ArrayType}. + * + * @param t the array type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitArray(ArrayType t, Void p) { visit(t.getComponentType()); @@ -226,6 +348,13 @@ class FormatVisitor implements TypeVisitor { return null; } + /** + * Visit method for {@link DeclaredType}. + * + * @param t the declared type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitDeclared(DeclaredType t, Void p) { buf.append(t.asElement().toString()); @@ -242,12 +371,26 @@ class FormatVisitor implements TypeVisitor { return null; } + /** + * Visit method for {@link ErrorType}. + * + * @param t the error type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitError(ErrorType t, Void p) { buf.append(t.toString()); return null; } + /** + * Visit method for {@link TypeVariable}. + * + * @param t the type variable to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitTypeVariable(TypeVariable t, Void p) { buf.append(t.toString()); @@ -264,6 +407,13 @@ class FormatVisitor implements TypeVisitor { return null; } + /** + * Visit method for {@link WindcardType}. + * + * @param t the wildcard type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitWildcard(WildcardType t, Void p) { buf.append("?"); @@ -280,24 +430,52 @@ class FormatVisitor implements TypeVisitor { return null; } + /** + * Visit method for {@link ExecutableType}. + * + * @param t the executable type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitExecutable(ExecutableType t, Void p) { buf.append(t.toString()); return null; } + /** + * Visit method for {@link NoType}. + * + * @param t the no-type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitNoType(NoType t, Void p) { buf.append(t.toString()); return null; } + /** + * Visit method for unknown {@link TypeMirror} instances. + * + * @param t the unknown type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitUnknown(TypeMirror t, Void p) { buf.append(t.toString()); return null; } + /** + * Visit method for {@link UnionType}. + * + * @param t the union type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitUnion(UnionType t, Void p) { Iterator it = t.getAlternatives().iterator(); @@ -311,6 +489,13 @@ class FormatVisitor implements TypeVisitor { return null; } + /** + * Visit method for {@link IntersectionType}. + * + * @param t the intersection type to visit + * @param p unused parameter (can be {@code null}) + * @return {@code null} + */ @Override public Void visitIntersection(IntersectionType t, Void p) { Iterator it = t.getBounds().iterator();