blob: 897149cda8363f0e4f90d46090126de433335495 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package gls.generics
class GenericsBytecodeTest extends GenericsTestBase {
void testClassWithoutParameterExtendsClassWithFixedParameter() {
createClassInfo """
class B extends ArrayList<Long> {}
"""
assert signatures == ["class": "Ljava/util/ArrayList<Ljava/lang/Long;>;Lgroovy/lang/GroovyObject;",]
}
void testMultipleImplementsWithParameter() {
createClassInfo """
abstract class B<T> implements Runnable,List<T> {}
"""
assert signatures == [
"class": "<T:Ljava/lang/Object;>Ljava/lang/Object;Ljava/lang/Runnable;Ljava/util/List<TT;>;Lgroovy/lang/GroovyObject;"
]
}
void testImplementsWithParameter() {
createClassInfo """
abstract class B<T> implements List<T> {}
"""
assert signatures == [
"class": "<T:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/List<TT;>;Lgroovy/lang/GroovyObject;"
]
}
void testExtendsWithParameter() {
createClassInfo """
class B<T> extends ArrayList<T> {}
"""
assert signatures == ["class": "<T:Ljava/lang/Object;>Ljava/util/ArrayList<TT;>;Lgroovy/lang/GroovyObject;"]
}
void testNestedExtendsWithParameter() {
createClassInfo """
class B<T> extends HashMap<T,List<T>> {}
"""
assert signatures == [
"class": "<T:Ljava/lang/Object;>Ljava/util/HashMap<TT;Ljava/util/List<TT;>;>;Lgroovy/lang/GroovyObject;"
]
}
void testBoundInterface() {
createClassInfo """
class B<T extends List> {}
"""
assert signatures == ["class": "<T::Ljava/util/List;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;"]
}
void testNestedReuseOfParameter() {
createClassInfo """
class B<Y,T extends Map<String,Map<Y,Integer>>> {}
"""
assert signatures == [
"class": "<Y:Ljava/lang/Object;T::Ljava/util/Map<Ljava/lang/String;Ljava/util/Map<TY;Ljava/lang/Integer;>;>;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;"
]
}
void testFieldWithParameter() {
createClassInfo """
class B { public Collection<Integer> books }
"""
assert signatures == [books: "Ljava/util/Collection<Ljava/lang/Integer;>;"]
}
void testFieldReusedParameter() {
createClassInfo """
class B<T> { public Collection<T> collection }
"""
assert signatures == ["class" : "<T:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
collection: "Ljava/util/Collection<TT;>;"]
}
void testParameterAsReturnType() {
createClassInfo """
class B {
static <T> T foo() {return null}
}
"""
assert signatures == ["foo()Ljava/lang/Object;": "<T:Ljava/lang/Object;>()TT;"]
}
void testParameterAsReturnTypeAndParameter() {
createClassInfo """
class B {
static <T> T foo(T t) {return null}
}
"""
assert signatures == ["foo(Ljava/lang/Object;)Ljava/lang/Object;": "<T:Ljava/lang/Object;>(TT;)TT;"]
}
void testParameterAsMethodParameter() {
createClassInfo """
class B<T> {
void foo(T t){}
}
"""
assert signatures == [
"class" : "<T:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
"foo(Ljava/lang/Object;)V": "(TT;)V"
]
}
void testParameterAsNestedMethodParameter() {
createClassInfo """
class B<T> {
void foo(List<T> t){}
}
"""
assert signatures == [
"class" : "<T:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
"foo(Ljava/util/List;)V": "(Ljava/util/List<TT;>;)V"
]
}
void testParameterAsNestedMethodParameterReturningInterface() {
createClassInfo """
class B<T> {
Cloneable foo(List<T> t){}
}
"""
assert signatures == [
"class" : "<T:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
"foo(Ljava/util/List;)Ljava/lang/Cloneable;": "(Ljava/util/List<TT;>;)Ljava/lang/Cloneable;"
]
}
void testArray() {
createClassInfo """
class B<T> {
T[] get(T[] arr) {return null}
}
"""
assert signatures == [
"class" : "<T:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
"get([Ljava/lang/Object;)[Ljava/lang/Object;": "([TT;)[TT;"
]
}
void testMultipleBounds() {
createClassInfo """
class Pair< A extends Comparable<A> & Cloneable ,
B extends Cloneable & Comparable<B> >
{
A foo(){}
B bar(){}
}
"""
assert signatures == [
"class" : "<A::Ljava/lang/Comparable<TA;>;:Ljava/lang/Cloneable;B::Ljava/lang/Cloneable;:Ljava/lang/Comparable<TB;>;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
"foo()Ljava/lang/Comparable;": "()TA;",
"bar()Ljava/lang/Cloneable;" : "()TB;"
]
}
void testWildCard() {
createClassInfo """
class B {
private Collection<?> f1
private List<? extends Number> f2
private Comparator<? super String> f3
private Map<String,?> f4
}
"""
assert signatures == [
f1: "Ljava/util/Collection<*>;",
f2: "Ljava/util/List<+Ljava/lang/Number;>;",
f3: "Ljava/util/Comparator<-Ljava/lang/String;>;",
f4: "Ljava/util/Map<Ljava/lang/String;*>;"
]
}
void testwildcardWithBound() {
createClassInfo """
class Something<T extends Number> {
List<? super T> dependency
}
"""
assert signatures == [
"class" : "<T:Ljava/lang/Number;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
dependency : "Ljava/util/List<-TT;>;",
"setDependency(Ljava/util/List;)V": "(Ljava/util/List<-TT;>;)V",
"getDependency()Ljava/util/List;" : "()Ljava/util/List<-TT;>;",
]
}
void testParameterAsParameterForReturnTypeAndFieldClass() {
createClassInfo """
class B<T> {
private T owner;
Class<T> getOwnerClass(){}
}
"""
assert signatures == [
"class" : "<T:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
"owner" : "TT;",
"getOwnerClass()Ljava/lang/Class;": "()Ljava/lang/Class<TT;>;"
]
}
void testInterfaceWithParameter() {
createClassInfo """
interface B<T> {}
"""
assert signatures == ["class": "<T:Ljava/lang/Object;>Ljava/lang/Object;"]
}
void testTypeParamAsBound() {
createClassInfo """
class Box<A> {
public <V extends A> void foo(V v) {
}
}
"""
assert signatures == [
"foo(Ljava/lang/Object;)V": "<V:TA;>(TV;)V", "class": "<A:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;"
]
}
void "test method with generic return type defined at class level"() {
// class Bar should compile successfully
// the classes it references should be available as class files to check for ASM resolving
// so they're defined in compiled GenericsTestData and not loaded from text in the test
createClassInfo 'class Bar extends gls.generics.GenericsTestData.Abstract<String> {}'
}
}