This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY-11746 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 64240e42bc65e5d2b94d954e0abc588f69335bb7 Author: Eric Milles <[email protected]> AuthorDate: Fri Aug 29 14:46:30 2025 -0500 GROOVY-11746: retain accessible synthetic override --- .../transform/stc/StaticTypeCheckingSupport.java | 10 ++++++--- .../transform/stc/StaticTypeCheckingVisitor.java | 3 ++- .../groovy/groovy/transform/stc/BugsSTCTest.groovy | 12 +++++++++- .../provider/collection/runtime/NamedRecord.groovy | 26 ++++++++++++++++------ .../provider/collection/runtime/NamedTuple.groovy | 20 +++++++++++------ 5 files changed, 52 insertions(+), 19 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 c030eb3cca..5b7128988c 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -1192,7 +1192,7 @@ public abstract class StaticTypeCheckingSupport { if (toBeRemoved.contains(two)) continue; if (one.getParameters().length == two.getParameters().length) { ClassNode oneDC = one.getDeclaringClass(), twoDC = two.getDeclaringClass(); - if (oneDC == twoDC || isSynthetic(one,two)||isSynthetic(two,one)) { // GROOVY-11341 + if (oneDC == twoDC) { if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { ClassNode oneRT = one.getReturnType(), twoRT = two.getReturnType(); if (isCovariant(oneRT, twoRT)) { @@ -1201,8 +1201,8 @@ public abstract class StaticTypeCheckingSupport { toBeRemoved.add(one); } } else { - // imperfect solution to determining if two methods are - // equivalent, for example String#compareTo(Object) and + // imperfect solution of determining if two methods are + // equivalent; for example String#compareTo(Object) and // String#compareTo(String) -- in that case, the Object // version is marked as synthetic if (isSynthetic(one, two)) { @@ -1213,6 +1213,10 @@ public abstract class StaticTypeCheckingSupport { } } else if (!oneDC.equals(twoDC)) { if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { + // GROOVY-11341, GROOVY-11746: multi-level covariant and synthetic override + if (!one.getReturnType().equals(two.getReturnType())) { + toBeRemoved.add(isCovariant(two.getReturnType(), one.getReturnType()) ? one : two); + } else // GROOVY-6882, GROOVY-6970: drop overridden or interface equivalent method if (!twoDC.isInterface() ? oneDC.isDerivedFrom(twoDC) : oneDC.implementsInterface(twoDC) || // GROOVY-10897: concrete vs. abstract (!disjoint && !one.isAbstract() && !(two instanceof ExtensionMethodNode))) { diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 61b4c7e6bd..2e63acbe50 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -5060,10 +5060,11 @@ trying: for (ClassNode[] signature : signatures) { methods = findMethodsWithGenerated(receiver, name); if ("call".equals(name) && receiver.isInterface()) { MethodNode sam = findSAM(receiver); - if (sam != null) { + if (sam != null && !"call".equals(sam.getName())) { MethodNode callMethod = new MethodNode("call", sam.getModifiers(), sam.getReturnType(), sam.getParameters(), sam.getExceptions(), sam.getCode()); callMethod.setDeclaringClass(sam.getDeclaringClass()); callMethod.setSourcePosition(sam); + callMethod.setSynthetic(true); methods.add(callMethod); } } diff --git a/src/test/groovy/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/groovy/transform/stc/BugsSTCTest.groovy index db1f68c2a8..884431492a 100644 --- a/src/test/groovy/groovy/transform/stc/BugsSTCTest.groovy +++ b/src/test/groovy/groovy/transform/stc/BugsSTCTest.groovy @@ -1039,7 +1039,7 @@ class BugsSTCTest extends StaticTypeCheckingTestCase { 'Abstract method m() cannot be called directly' } - // GROOVY-8339, GROOVY-10109, GROOVY-10594 + // GROOVY-8339, GROOVY-10109, GROOVY-10594, GROOVY-11746 void testInvokePublicMethodFromInaccessibleBase() { assertScript ''' new StringBuilder().setLength(0) @@ -1055,6 +1055,16 @@ class BugsSTCTest extends StaticTypeCheckingTestCase { String sub = new StringBuilder("Hello World").substring(0,5) assert sub == 'Hello' ''' + + assertScript ''' + @Grab('org.apache.pdfbox:pdfbox:3.0.5') + import org.apache.pdfbox.pdmodel.PDPageContentStream + import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject + void test(PDPageContentStream stream, PDImageXObject image, float x, float y, float width, float height) { + stream.drawImage(image, x, y, width, height) // drawImage: synthetic in PDPageContentStream for access + } + assert true + ''' } void testInvokeSuperMethodFromCovariantOverride() { diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedRecord.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedRecord.groovy index d8730bf4c8..8dcd535dc2 100644 --- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedRecord.groovy +++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedRecord.groovy @@ -18,6 +18,7 @@ */ package org.apache.groovy.ginq.provider.collection.runtime +import groovy.transform.AutoFinal import groovy.transform.CompileStatic import groovy.transform.stc.POJO @@ -26,26 +27,37 @@ import groovy.transform.stc.POJO * * @since 4.0.0 */ -@POJO @CompileStatic +@AutoFinal +@POJO class NamedRecord<E, T> extends NamedTuple<E> { + private static final long serialVersionUID = -2554041223576761912L - private SourceRecord<T> sourceRecord + private final List<String> aliasList + private SourceRecord<T> sourceRecord NamedRecord(List<E> elementList, List<String> nameList, List<String> aliasList = Collections.emptyList()) { super(elementList, nameList) this.aliasList = aliasList } + @Override + String toString() { + return super.toString() + } + + @Override + def get(String name) { + return getAt(name) + } + @Override def getAt(String name) { if (exists(name)) { - def value = super.getAt(name) - return value + return super.get(name) } - - return sourceRecord.get(name) + return sourceRecord?.get(name) } List<String> getAliasList() { @@ -53,7 +65,7 @@ class NamedRecord<E, T> extends NamedTuple<E> { } NamedRecord<E, T> sourceRecord(T sr) { - this.sourceRecord = new SourceRecord<>(sr, aliasList) + sourceRecord = new SourceRecord<>(sr, getAliasList()) return this } } diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy index 7deb1d0411..5240c2728b 100644 --- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy +++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/NamedTuple.groovy @@ -18,20 +18,26 @@ */ package org.apache.groovy.ginq.provider.collection.runtime +import groovy.transform.AutoFinal import groovy.transform.CompileStatic import groovy.transform.PackageScope import groovy.transform.stc.POJO +import static groovy.transform.PackageScopeTarget.* + /** * Immutable named list to represent list result of GINQ * * @since 4.0.0 */ +@PackageScope([CLASS, CONSTRUCTORS, METHODS]) @CompileStatic -@PackageScope +@AutoFinal @POJO class NamedTuple<E> extends Tuple<E> { + private static final long serialVersionUID = -5067092453136522209L + private final Map<String, E> data NamedTuple(List<E> elementList, List<String> nameList) { @@ -54,11 +60,11 @@ class NamedTuple<E> extends Tuple<E> { } } - def get(String name) { - return getAt(name) + public get(String name) { + return data.get(name) } - def getAt(String name) { + public getAt(String name) { return data.get(name) } @@ -67,15 +73,15 @@ class NamedTuple<E> extends Tuple<E> { } List<String> getNameList() { - return Collections.unmodifiableList(data.keySet().toList()) + return new ArrayList<>(data.keySet()) } @Override - String toString() { + public String toString() { StringJoiner sj = new StringJoiner(', ', '(', ')') for (String name : getNameList()) { sj.add(name + ':' + this[name]) } - sj.toString() + return sj.toString() } }
