Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly parse and unparse annotated wildcard types #214

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions janino/src/main/java/org/codehaus/janino/Java.java
Original file line number Diff line number Diff line change
Expand Up @@ -6437,16 +6437,21 @@ class Wildcard implements TypeArgument {
*/
public final int bounds;

/**
* The annotations of the wildcard type, defined by JLS8, 4.5.1 since JLS8.
*/
public final Annotation[] annotations;

/**
* The reference type of this wildcard's EXTENDS or SUPER bounds.
*/
@Nullable public final ReferenceType referenceType;

public
Wildcard() { this(Wildcard.BOUNDS_NONE, null); }
Wildcard(Annotation[] annotations) { this(Wildcard.BOUNDS_NONE, null, annotations); }

public
Wildcard(int bounds, @Nullable ReferenceType referenceType) {
Wildcard(int bounds, @Nullable ReferenceType referenceType, Annotation[] annotations) {
if (referenceType == null) {
assert bounds == Wildcard.BOUNDS_NONE;
this.bounds = bounds;
Expand All @@ -6456,6 +6461,9 @@ class Wildcard implements TypeArgument {
this.bounds = bounds;
this.referenceType = referenceType;
}

assert annotations != null;
this.annotations = annotations;
}

@Override public void
Expand All @@ -6468,7 +6476,9 @@ class Wildcard implements TypeArgument {

@Override public String
toString() {
return (
String s = Java.join(this.annotations, " ");
if (this.annotations.length >= 1) s += ' ';
return s + (
this.bounds == Wildcard.BOUNDS_EXTENDS ? "? extends " + this.referenceType :
this.bounds == Wildcard.BOUNDS_SUPER ? "? super " + this.referenceType :
"?"
Expand Down
42 changes: 35 additions & 7 deletions janino/src/main/java/org/codehaus/janino/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2613,9 +2613,25 @@ enum InterfaceDeclarationContext {
List<Annotation> annotations = new ArrayList<>();
while (this.peek("@")) annotations.add(this.parseAnnotation());

return this.parseReferenceType((Annotation[]) annotations.toArray(new Annotation[annotations.size()]));
}

/**
* Note: This method assumes that annotations of the reference type (if any) were already read
* ahead of time and that they are passed to this method. If this assumption is false,
* {@link #parseReferenceType()} should be used instead. This behaviour is required as
* {@link #parseTypeArgument()} cannot be certain whether the annotations are for a wildcard
* or for a reference type until all annotations have been read.
*
* <pre>
* ReferenceType := { Annotation } QualifiedIdentifier [ TypeArguments ]
* </pre>
*/
public ReferenceType
parseReferenceType(Annotation[] annotations) throws CompileException, IOException {
return new ReferenceType(
this.location(),
(Annotation[]) annotations.toArray(new Annotation[annotations.size()]),
annotations,
this.parseQualifiedIdentifier(),
this.parseTypeArgumentsOpt()
);
Expand Down Expand Up @@ -2683,21 +2699,33 @@ enum InterfaceDeclarationContext {
* TypeArgument :=
* ReferenceType { '[' ']' } &lt;= The optional brackets are missing in JLS7, section 18!?
* | PrimitiveType '[' ']' { '[' ']' }
* | '?' extends ReferenceType
* | '?' super ReferenceType
* | { Annotation } '?' extends ReferenceType
* | { Annotation } '?' super ReferenceType
* </pre>
*/
private TypeArgument
parseTypeArgument() throws CompileException, IOException {
List<Annotation> annotations = new ArrayList<>();
while (this.peek("@")) annotations.add(this.parseAnnotation());

if (this.peekRead("?")) {
Annotation[] annotationArray = (Annotation[]) annotations.toArray(new Annotation[annotations.size()]);
return (
this.peekRead("extends") ? new Wildcard(Wildcard.BOUNDS_EXTENDS, this.parseReferenceType()) :
this.peekRead("super") ? new Wildcard(Wildcard.BOUNDS_SUPER, this.parseReferenceType()) :
new Wildcard()
this.peekRead("extends") ? new Wildcard(Wildcard.BOUNDS_EXTENDS, this.parseReferenceType(), annotationArray) :
this.peekRead("super") ? new Wildcard(Wildcard.BOUNDS_SUPER, this.parseReferenceType(), annotationArray) :
new Wildcard(annotationArray)
);
}

Type t = this.parseType();
Type t;
if (annotations.isEmpty()) {
t = this.parseType();
} else {
// we know that primitives cannot be annotated with anything if they are a type argument so the
// only thing that would give trouble are arrays of primitives, which cannot be annotated yet.
Annotation[] annotationArray = (Annotation[]) annotations.toArray(new Annotation[annotations.size()]);
t = this.parseReferenceType(annotationArray);
}

int i = this.parseBracketsOpt();
for (; i > 0; i--) t = new ArrayType(t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,11 @@ class DeepCopier {

public TypeArgument
copyWildcard(Wildcard subject) throws CompileException {
return new Wildcard(subject.bounds, this.copyOptionalReferenceType(subject.referenceType));
return new Wildcard(
subject.bounds,
this.copyOptionalReferenceType(subject.referenceType),
this.copyAnnotations(subject.annotations)
);
}

public PackageDeclaration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,11 @@ class UnparserTest {
UnparserTest.helpTestScript("{ return a -> {}; }");
UnparserTest.helpTestScript("{ return (int a, int b) -> {}; }");
UnparserTest.helpTestScript("{ return () -> 3 + 7; }");

// Annotated wildcards (JLS8, 4.5.1).
UnparserTest.helpTestScript(
"{ java.util.Map<?, ?> map = new java.util.HashMap<@WildcardAnnotation ? extends String, ? extends @TypeAnnotation Integer>(); }"
);
}

@Test public void
Expand Down