Skip to content

Commit

Permalink
Add a new method to handle annotations not on the classpath
Browse files Browse the repository at this point in the history
  • Loading branch information
smillst authored Dec 1, 2023
1 parent 3bca5e2 commit 43db447
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,6 @@ public class CFGTranslationPhaseOne extends TreeScanner<Node, Void> {
*/
protected final Set<TypeMirror> newArrayExceptionTypes;

/** The AssertMethod.value argument/element. */
protected final ExecutableElement assertMethodValueElement;

/** The AssertMethod.parameter argument/element. */
protected final ExecutableElement assertMethodParameterElement;

/** The {@link AssertMethod#isAssertFalse()} argument/element. */
protected final ExecutableElement assertMethodIsAssertFalseElement;

/**
* Creates {@link CFGTranslationPhaseOne}.
*
Expand Down Expand Up @@ -458,11 +449,6 @@ public CFGTranslationPhaseOne(
if (outOfMemoryErrorType != null) {
newArrayExceptionTypes.add(outOfMemoryErrorType);
}

assertMethodValueElement = TreeUtils.getMethod(AssertMethod.class, "value", 0, env);
assertMethodParameterElement = TreeUtils.getMethod(AssertMethod.class, "parameter", 0, env);
assertMethodIsAssertFalseElement =
TreeUtils.getMethod(AssertMethod.class, "isAssertFalse", 0, env);
}

/**
Expand Down Expand Up @@ -1406,19 +1392,20 @@ protected AssertMethodTuple getAssertMethodTuple(ExecutableElement method) {
return AssertMethodTuple.NONE;
}

// Dataflow does not require checker-qual.jar to be on the users classpath, so
// AnnotationUtils.getElementValue(...) cannot be used.

int booleanParam =
AnnotationUtils.getElementValue(
assertMethodAnno, assertMethodParameterElement, Integer.class, 1)
AnnotationUtils.getElementValueNotOnClasspath(
assertMethodAnno, "parameter", Integer.class, 1)
- 1;

TypeMirror exceptionType =
AnnotationUtils.getElementValue(
assertMethodAnno,
assertMethodValueElement,
Type.ClassType.class,
(Type.ClassType) assertionErrorType);
AnnotationUtils.getElementValueNotOnClasspath(
assertMethodAnno, "value", Type.ClassType.class, (Type.ClassType) assertionErrorType);
boolean isAssertFalse =
AnnotationUtils.getElementValue(
assertMethodAnno, assertMethodIsAssertFalseElement, Boolean.class, false);
AnnotationUtils.getElementValueNotOnClasspath(
assertMethodAnno, "isAssertFalse", Boolean.class, false);
return new AssertMethodTuple(booleanParam, exceptionType, isAssertFalse);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,45 @@ public static EnumSet<ElementKind> getElementKindsForElementType(ElementType ele
// Annotation values: inefficient extractors that take an element name
// **********************************************************************

/**
* Get the element with the name {@code elementName} of the annotation {@code anno}. The result
* has type {@code expectedType}. If there is no value for {@code elementName}, {@code
* defaultValue} is returned
*
* <p>This method is intended only for use when the class of the annotation is not on the user's
* classpath. This is for users of the Dataflow Framework that do not use the rest of the Checker
* Framework. Type-checkers can assume that checker-qual.jar is on the classpath and should use
* {@link #getElementValue(AnnotationMirror, ExecutableElement, Class)} or {@link
* #getElementValue(AnnotationMirror, ExecutableElement, Class, Object)}.
*
* @param anno the annotation whose element to access
* @param elementName the name of the element to access
* @param expectedType the type of the element and the return value
* @param defaultValue the value to return if the element is not present
* @param <T> the class of the type
* @return the value of the element with the given name
*/
public static <T> T getElementValueNotOnClasspath(
AnnotationMirror anno, CharSequence elementName, Class<T> expectedType, T defaultValue) {
Map<? extends ExecutableElement, ? extends AnnotationValue> valmap = anno.getElementValues();

for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
valmap.entrySet()) {
ExecutableElement elem = entry.getKey();
if (elem.getSimpleName().contentEquals(elementName)) {
AnnotationValue val = entry.getValue();
try {
return expectedType.cast(val.getValue());
} catch (ClassCastException e) {
throw new BugInCF(
"getElementValueNotOnClasspath(%s, %s, %s): val=%s, val.getValue()=%s [%s]",
anno, elementName, expectedType, val, val.getValue(), val.getValue().getClass());
}
}
}
return defaultValue;
}

/**
* Returns the values of an annotation's elements, including defaults. The method with the same
* name in JavacElements cannot be used directly, because it includes a cast to
Expand Down Expand Up @@ -604,7 +643,7 @@ public static EnumSet<ElementKind> getElementKindsForElementType(ElementType ele
* @deprecated use {@link #getElementValue(AnnotationMirror, ExecutableElement, Class)} or {@link
* #getElementValue(AnnotationMirror, ExecutableElement, Class, Object)}
*/
@Deprecated // for use only by the framework
@Deprecated // for use only by the framework, not by clients
public static <T> T getElementValue(
AnnotationMirror anno, CharSequence elementName, Class<T> expectedType, boolean useDefaults) {
Map<? extends ExecutableElement, ? extends AnnotationValue> valmap;
Expand Down

0 comments on commit 43db447

Please sign in to comment.