Skip to content

Commit

Permalink
Merge pull request #153 from Ladicek/type-parameter-annotation-on-bri…
Browse files Browse the repository at this point in the history
…dge-method

Fix indexing bridge methods with type annotations on type parameters
  • Loading branch information
Ladicek authored Oct 6, 2021
2 parents be03767 + 60b7735 commit 2838410
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 2 deletions.
6 changes: 6 additions & 0 deletions core/src/main/java/org/jboss/jandex/Indexer.java
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,12 @@ private TypeAnnotationState processTypeAnnotation(DataInputStream data, Annotati

BooleanHolder genericsRequired = new BooleanHolder();
BooleanHolder bridgeIncompatible = new BooleanHolder();

if (typeTarget.usage() == TypeTarget.Usage.TYPE_PARAMETER
|| typeTarget.usage() == TypeTarget.Usage.TYPE_PARAMETER_BOUND) {
genericsRequired.bool = true;
}

ArrayList<PathElement> pathElements = processTargetPath(data, genericsRequired, bridgeIncompatible);
AnnotationInstance annotation = processAnnotation(data, typeTarget, visible);
return new TypeAnnotationState(typeTarget, annotation, pathElements, genericsRequired.bool, bridgeIncompatible.bool);
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jboss/jandex/NameTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ private int lastIndexOf(String name, char delim) {
// avoid splitting on '$' if previous char is a delimiter or the '$'
// is in position 0, because subsequent split would produce an empty
// local name
if (pos >=0 && name.charAt(pos) == '$' && (pos == 0 || name.charAt(pos - 1) == delim)) {
if (pos >= 0 && name.charAt(pos) == '$' && (pos == 0 || name.charAt(pos - 1) == delim)) {
pos--;
}

Expand Down
83 changes: 83 additions & 0 deletions core/src/test/java/org/jboss/jandex/test/BridgeMethodTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
Expand Down Expand Up @@ -130,4 +135,82 @@ private void verifyMethodSignature(
Assert.fail("At least one '" + methodName + "' method is expected in " + klass);
}
}

@Test
public void returnType() throws IOException {
DotName nullable = DotName.createSimple("test.Nullable");
DotName untainted = DotName.createSimple("test.Untainted");

Indexer indexer = new Indexer();
ClassInfo clazz = indexer.index(getClassBytes("test/BridgeMethods$Subclass.class"));
for (MethodInfo method : filterMethods(clazz, "typeVariable")) {
if (method.returnType().name().equals(DotName.createSimple(Collection.class.getName()))) {
// bridge method
Assert.assertTrue(isBridge(method));
Assert.assertEquals(Type.Kind.CLASS, method.returnType().kind());
Assert.assertTrue(method.typeParameters().isEmpty());

Assert.assertNotNull(method.annotation(nullable));
Assert.assertEquals(Type.Kind.VOID, method.annotation(nullable).target().asType().target().kind());

Assert.assertNotNull(method.annotation(untainted));
Assert.assertEquals(Type.Kind.VOID, method.annotation(untainted).target().asType().target().kind());
} else if (method.returnType().name().equals(DotName.createSimple(Set.class.getName()))) {
// actual overridden method
Assert.assertFalse(isBridge(method));
Assert.assertEquals(Type.Kind.PARAMETERIZED_TYPE, method.returnType().kind());
Assert.assertFalse(method.typeParameters().isEmpty());

Assert.assertNotNull(method.annotation(nullable));
Assert.assertEquals(Type.Kind.CLASS, method.annotation(nullable).target().asType().target().kind());
Assert.assertNotNull(method.typeParameters().get(0).asTypeVariable()
.bounds().get(0).annotation(nullable));

Assert.assertNotNull(method.annotation(untainted));
Assert.assertEquals(Type.Kind.TYPE_VARIABLE, method.annotation(untainted).target().asType().target().kind());
Assert.assertNotNull(method.typeParameters().get(0).asTypeVariable().annotation(untainted));
} else {
Assert.fail();
}
}

for (MethodInfo method : filterMethods(clazz, "wildcard")) {
if (method.returnType().name().equals(DotName.createSimple(Collection.class.getName()))) {
// bridge method
Assert.assertTrue(isBridge(method));
Assert.assertEquals(Type.Kind.CLASS, method.returnType().kind());

Assert.assertNotNull(method.annotation(nullable));
Assert.assertEquals(Type.Kind.VOID, method.annotation(nullable).target().asType().target().kind());

Assert.assertNotNull(method.annotation(untainted));
Assert.assertEquals(Type.Kind.VOID, method.annotation(untainted).target().asType().target().kind());
} else if (method.returnType().name().equals(DotName.createSimple(Set.class.getName()))) {
// actual overridden method
Assert.assertFalse(isBridge(method));
Assert.assertEquals(Type.Kind.PARAMETERIZED_TYPE, method.returnType().kind());

Assert.assertNotNull(method.annotation(nullable));
Assert.assertEquals(Type.Kind.CLASS, method.annotation(nullable).target().asType().target().kind());
Assert.assertNotNull(method.returnType().asParameterizedType().arguments().get(0)
.asWildcardType().extendsBound().annotation(nullable));

Assert.assertNotNull(method.annotation(untainted));
Assert.assertEquals(Type.Kind.WILDCARD_TYPE, method.annotation(untainted).target().asType().target().kind());
Assert.assertNotNull(method.returnType().asParameterizedType().arguments().get(0).annotation(untainted));
} else {
Assert.fail();
}
}
}

private List<MethodInfo> filterMethods(ClassInfo clazz, String methodName) {
List<MethodInfo> result = new ArrayList<MethodInfo>();
for (MethodInfo method : clazz.methods()) {
if (methodName.equals(method.name())) {
result.add(method);
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
Expand All @@ -21,6 +23,7 @@
import net.bytebuddy.description.type.TypeDescription;

public class Utf8ConstantEncodingTest {
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value();
}
Expand All @@ -34,7 +37,7 @@ public class Utf8ConstantEncodingTest {
// it is encoded as 0xC0 0x80 (this is not the only difference between the two encodings,
// but is the easiest to test with)
StringBuilder longString = new StringBuilder();
for (int i = 0; i < 25_000; i++) {
for (int i = 0; i < 25000; i++) {
longString.append('\0');
}
LONG_STRING = longString.toString();
Expand Down
24 changes: 24 additions & 0 deletions test-data/src/main/java/test/BridgeMethods.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package test;

import java.util.Collection;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

Expand Down Expand Up @@ -46,4 +48,26 @@ public static class NullableArraySupplier
return null;
}
}

public static class Superclass {
public <@Untainted E extends @Nullable Object> Collection<E> typeVariable() {
return null;
}

public Collection<@Untainted ? extends @Nullable Object> wildcard() {
return null;
}
}

public static class Subclass extends Superclass {
@Override
public <@Untainted E extends @Nullable Object> Set<E> typeVariable() {
return null;
}

@Override
public Set<@Untainted ? extends @Nullable Object> wildcard() {
return null;
}
}
}

0 comments on commit 2838410

Please sign in to comment.