You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/09/28 20:18:29 UTC
[groovy] 01/01: GROOVY-10234: handle raw types in class signature
without looping
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-10234
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit e1280c3be1facfefe6df78ab9c73a69c5d06ef6f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Sep 28 15:02:32 2021 -0500
GROOVY-10234: handle raw types in class signature without looping
interface ConversionService<Impl extends ConversionService>
https://github.com/micronaut-projects/micronaut-core/blob/3.0.x/core/src/main/java/io/micronaut/core/convert/ConversionService.java
---
.../groovy/ast/decompiled/DecompiledClassNode.java | 16 ++++----
.../groovy/ast/decompiled/TypeSignatureParser.java | 43 ++++++++++++++--------
.../groovy/transform/stc/GenericsSTCTest.groovy | 40 ++++++++++++++++++++
3 files changed, 76 insertions(+), 23 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
index f6a81ff..8156670 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
@@ -45,9 +45,9 @@ public class DecompiledClassNode extends ClassNode {
private volatile boolean supersInitialized;
private volatile boolean membersInitialized;
- public DecompiledClassNode(ClassStub data, AsmReferenceResolver resolver) {
- super(data.className, getFullModifiers(data), null, null, MixinNode.EMPTY_ARRAY);
- classData = data;
+ public DecompiledClassNode(final ClassStub classData, final AsmReferenceResolver resolver) {
+ super(classData.className, getFullModifiers(classData), null, null, MixinNode.EMPTY_ARRAY);
+ this.classData = classData;
this.resolver = resolver;
isPrimaryNode = false;
}
@@ -168,6 +168,10 @@ public class DecompiledClassNode extends ClassNode {
throw new UnsupportedOperationException();
}
+ public boolean isParameterized() {
+ return (classData.signature != null && classData.signature.charAt(0) == '<');
+ }
+
@Override
public boolean isResolved() {
return true;
@@ -204,12 +208,11 @@ public class DecompiledClassNode extends ClassNode {
synchronized (lazyInitLock) {
if (!supersInitialized) {
- ClassSignatureParser.configureClass(this, this.classData, this.resolver);
+ ClassSignatureParser.configureClass(this, classData, resolver);
addAnnotations(classData, this);
supersInitialized = true;
}
}
-
}
private void lazyInitMembers() {
@@ -284,5 +287,4 @@ public class DecompiledClassNode extends ClassNode {
}
return node;
}
-
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
index 691d7e8..43cc00e 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
@@ -58,7 +58,7 @@ abstract class TypeSignatureParser extends SignatureVisitor {
final TypeSignatureParser outer = this;
return new TypeSignatureParser(resolver) {
@Override
- void finished(ClassNode result) {
+ void finished(final ClassNode result) {
outer.finished(result.makeArray());
}
};
@@ -91,14 +91,6 @@ abstract class TypeSignatureParser extends SignatureVisitor {
};
}
- private static GenericsType createWildcard(final ClassNode[] upper, final ClassNode lower) {
- ClassNode base = ClassHelper.makeWithoutCaching("?");
- base.setRedirect(ClassHelper.OBJECT_TYPE);
- GenericsType t = new GenericsType(base, upper, lower);
- t.setWildcard(true);
- return t;
- }
-
@Override
public void visitInnerClassType(final String name) {
baseName += "$" + name;
@@ -107,14 +99,33 @@ abstract class TypeSignatureParser extends SignatureVisitor {
@Override
public void visitEnd() {
- ClassNode base = resolver.resolveClass(baseName);
- if (arguments.isEmpty()) {
- finished(base);
- return;
+ ClassNode baseType = resolver.resolveClass(baseName);
+ if (arguments.isEmpty() && isNotParameterized(baseType)) {
+ finished(baseType);
+ } else {
+ ClassNode parameterizedType = baseType.getPlainNodeReference();
+ if (!arguments.isEmpty()) { // else GROOVY-10234: no type arguments -> raw type
+ parameterizedType.setGenericsTypes(arguments.toArray(GenericsType.EMPTY_ARRAY));
+ }
+ finished(parameterizedType);
}
+ }
- ClassNode bound = base.getPlainNodeReference();
- bound.setGenericsTypes(arguments.toArray(GenericsType.EMPTY_ARRAY));
- finished(bound);
+ //--------------------------------------------------------------------------
+
+ private static GenericsType createWildcard(final ClassNode[] upper, final ClassNode lower) {
+ ClassNode base = ClassHelper.makeWithoutCaching("?");
+ base.setRedirect(ClassHelper.OBJECT_TYPE);
+ GenericsType t = new GenericsType(base, upper, lower);
+ t.setWildcard(true);
+ return t;
+ }
+
+ private static boolean isNotParameterized(final ClassNode cn) {
+ // DecompiledClassNode may not have generics initialized
+ if (cn instanceof DecompiledClassNode) {
+ return !((DecompiledClassNode) cn).isParameterized();
+ }
+ return (cn.getGenericsTypes() == null);
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 5a8e324..76edb23 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -3634,6 +3634,46 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
+ // GROOVY-10234
+ void testSelfReferentialTypeParameter() {
+ config.with {
+ targetDirectory = File.createTempDir()
+ jointCompilationOptions = [memStub: true]
+ }
+ File parentDir = File.createTempDir()
+ try {
+ def a = new File(parentDir, 'Main.groovy')
+ a.write '''
+ def <T> T getBean(Class<T> beanType) {
+ { obj, Class target -> Optional.of(obj.toString()) } as Service
+ }
+
+ def result = getBean(Service).convert(new ArrayList(), String)
+ assert result.get() == '[]'
+ '''
+ def b = new File(parentDir, 'Service.java')
+ b.write '''
+ import java.util.Optional;
+ import java.util.function.Function;
+
+ public interface Service<Impl extends Service> {
+ <T> Optional<T> convert(Object object, Class<T> targetType);
+ <S, T> Impl addConverter(Class<S> sourceType, Class<T> targetType, Function<S, T> typeConverter);
+ }
+ '''
+
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ def cu = new JavaAwareCompilationUnit(config, loader)
+ cu.addSources(a, b)
+ cu.compile()
+
+ loader.loadClass('Main').main()
+ } finally {
+ parentDir.deleteDir()
+ config.targetDirectory.deleteDir()
+ }
+ }
+
// GROOVY-7804
void testParameterlessClosureToGenericSAMTypeArgumentCoercion() {
assertScript '''