This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 93a1ee3 GROOVY-9822: check for empty spec before recursive
application (closes #1426)
93a1ee3 is described below
commit 93a1ee3f033337b586f08ca416129676ed1b3473
Author: Eric Milles <[email protected]>
AuthorDate: Thu Nov 19 11:55:29 2020 -0600
GROOVY-9822: check for empty spec before recursive application (closes
#1426)
---
.../transform/stc/StaticTypeCheckingSupport.java | 70 ++++++++++++----------
.../groovy/transform/stc/GenericsSTCTest.groovy | 66 +++++++++++++++++++-
2 files changed, 103 insertions(+), 33 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 5034dec..488f3f6 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1866,38 +1866,44 @@ public abstract class StaticTypeCheckingSupport {
return false;
}
- static ClassNode[] applyGenericsContext(final Map<GenericsTypeName,
GenericsType> spec, final ClassNode[] bounds) {
- if (bounds == null) return null;
- ClassNode[] newBounds = new ClassNode[bounds.length];
- for (int i = 0, n = bounds.length; i < n; i += 1) {
- newBounds[i] = applyGenericsContext(spec, bounds[i]);
- }
- return newBounds;
- }
-
- static ClassNode applyGenericsContext(final Map<GenericsTypeName,
GenericsType> spec, final ClassNode bound) {
- if (bound == null) return null;
- if (bound.isArray()) {
- return applyGenericsContext(spec,
bound.getComponentType()).makeArray();
- }
- if (!bound.isUsingGenerics()) return bound;
- ClassNode newBound = bound.getPlainNodeReference();
- newBound.setGenericsTypes(applyGenericsContext(spec,
bound.getGenericsTypes()));
- if (bound.isGenericsPlaceHolder()) {
- GenericsType[] gt = newBound.getGenericsTypes();
- boolean hasBounds = hasNonTrivialBounds(gt[0]);
- if (hasBounds || !gt[0].isPlaceholder()) return
getCombinedBoundType(gt[0]);
- String placeHolderName = newBound.getGenericsTypes()[0].getName();
- if (!placeHolderName.equals(newBound.getUnresolvedName())) {
- // we should produce a clean placeholder ClassNode here
- ClassNode clean = make(placeHolderName);
- clean.setGenericsTypes(newBound.getGenericsTypes());
- clean.setRedirect(newBound);
- newBound = clean;
- }
- newBound.setGenericsPlaceHolder(true);
- }
- return newBound;
+ static ClassNode[] applyGenericsContext(final Map<GenericsTypeName,
GenericsType> spec, final ClassNode[] types) {
+ if (types == null) return null;
+ final int nTypes = types.length;
+ ClassNode[] newTypes = new ClassNode[nTypes];
+ for (int i = 0; i < nTypes; i += 1) {
+ newTypes[i] = applyGenericsContext(spec, types[i]);
+ }
+ return newTypes;
+ }
+
+ static ClassNode applyGenericsContext(final Map<GenericsTypeName,
GenericsType> spec, final ClassNode type) {
+ if (type == null || !isUsingGenericsOrIsArrayUsingGenerics(type)) {
+ return type;
+ }
+ if (type.isArray()) {
+ return applyGenericsContext(spec,
type.getComponentType()).makeArray();
+ }
+ ClassNode newType = type.getPlainNodeReference();
+ GenericsType[] gt = type.getGenericsTypes();
+ if (asBoolean(spec)) {
+ gt = applyGenericsContext(spec, gt);
+ }
+ newType.setGenericsTypes(gt);
+ if (type.isGenericsPlaceHolder()) {
+ boolean nonTrivial = hasNonTrivialBounds(gt[0]);
+ if (nonTrivial || !gt[0].isPlaceholder()) {
+ return getCombinedBoundType(gt[0]);
+ }
+ String placeholderName = gt[0].getName();
+ if (!placeholderName.equals(newType.getUnresolvedName())) {
+ ClassNode clean = make(placeholderName);
+ clean.setGenericsTypes(gt);
+ clean.setRedirect(newType);
+ newType = clean;
+ }
+ newType.setGenericsPlaceHolder(true);
+ }
+ return newType;
}
static ClassNode getCombinedBoundType(final GenericsType genericsType) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 6cc3a86..5db067d 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1507,7 +1507,71 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
}
}
new Element()
-'''
+ '''
+
+ // GROOVY-9822
+ config.with {
+ targetDirectory = File.createTempDir()
+ jointCompilationOptions = [memStub: true]
+ }
+ File parentDir = File.createTempDir()
+ try {
+ def a = new File(parentDir, 'Types.java')
+ a.write '''
+ import java.io.*;
+ import java.util.*;
+
+ // from org.apache.tinkerpop:gremlin-core:3.4.8
+
+ interface TraversalStrategy<S extends TraversalStrategy>
extends Serializable, Comparable<Class<? extends TraversalStrategy>> {
+ interface VerificationStrategy extends
TraversalStrategy<VerificationStrategy> {
+ }
+ }
+ abstract class AbstractTraversalStrategy<S extends
TraversalStrategy> implements TraversalStrategy<S> {
+ }
+ abstract // don't want to implement Comparable
+ class ReadOnlyStrategy extends
AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy>
+ implements TraversalStrategy.VerificationStrategy {
+ static ReadOnlyStrategy instance() { return null; }
+ }
+
+ interface TraversalSource extends Cloneable, AutoCloseable {
+ default TraversalSource
withStrategies(TraversalStrategy... strategies) {
+ return null;
+ }
+ }
+ abstract // don't want to implement AutoCloseable
+ class GraphTraversalSource implements TraversalSource {
+ @Override
+ public GraphTraversalSource
withStrategies(TraversalStrategy... strategies) {
+ return (GraphTraversalSource)
TraversalSource.super.withStrategies(strategies);
+ }
+ }
+ class Graph {
+ public <C extends TraversalSource> C traversal(Class<C> c)
{
+ return null;
+ }
+ public GraphTraversalSource traversal() {
+ return null;
+ }
+ }
+ '''
+ def b = new File(parentDir, 'Script.groovy')
+ b.write '''
+ GraphTraversalSource test(Graph graph) {
+ def strategy = ReadOnlyStrategy.instance()
+ graph.traversal().withStrategies(strategy)
+ }
+ '''
+
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ def cu = new JavaAwareCompilationUnit(config, loader)
+ cu.addSources(a, b)
+ cu.compile()
+ } finally {
+ parentDir.deleteDir()
+ config.targetDirectory.deleteDir()
+ }
}
void testRegressionInConstructorCheck() {