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 2022/09/22 18:49:03 UTC
[groovy] branch GROOVY_2_5_X updated: GROOVY-10700: STC: non-static (not just default) interface/trait methods
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new f383f2674f GROOVY-10700: STC: non-static (not just default) interface/trait methods
f383f2674f is described below
commit f383f2674f57b5dd3616baff9f9ef540a07e3cdc
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jul 21 16:29:46 2022 -0500
GROOVY-10700: STC: non-static (not just default) interface/trait methods
---
.../groovy/ast/tools/WideningCategories.java | 5 --
.../transform/stc/StaticTypeCheckingVisitor.java | 20 ++++--
src/test/groovy/bugs/Groovy10700.groovy | 82 ++++++++++++++++++++++
.../traitx/TraitASTTransformationTest.groovy | 32 +++++++++
4 files changed, 127 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
index 5c11d0637f..a0888a89a1 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -20,7 +20,6 @@ package org.codehaus.groovy.ast.tools;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.GenericsType;
-import org.codehaus.groovy.ast.MethodNode;
import java.util.ArrayList;
import java.util.Arrays;
@@ -601,10 +600,6 @@ public class WideningCategories {
for (ClassNode anInterface : interfaces) {
usesGenerics |= anInterface.isUsingGenerics();
genericsTypesList.add(anInterface.getGenericsTypes());
- for (MethodNode methodNode : anInterface.getMethods()) {
- MethodNode method = addMethod(methodNode.getName(), methodNode.getModifiers(), methodNode.getReturnType(), methodNode.getParameters(), methodNode.getExceptions(), methodNode.getCode());
- method.setDeclaringClass(anInterface); // important for static compilation!
- }
}
setUsingGenerics(usesGenerics);
if (usesGenerics) {
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 209917dcc8..303dd596a0 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4649,15 +4649,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
List<MethodNode> methods = receiver.getMethods(name);
- if (receiver.isAbstract()) {
- collectAllInterfaceMethodsByName(receiver, name, methods);
- } else { // GROOVY-9890: always search for default methods
- List<MethodNode> interfaceMethods = new ArrayList<>();
- collectAllInterfaceMethodsByName(receiver, name, interfaceMethods);
- for (MethodNode method : interfaceMethods) {
- if (method.isDefault()) methods.add(method);
+
+ // GROOVY-5166, GROOVY-9890, GROOVY-10700: non-static interface/trait methods
+ Set<ClassNode> done = new HashSet<>();
+ for (ClassNode next = receiver; next != null; next = next.getSuperClass()) {
+ done.add(next);
+ for (ClassNode face : next.getAllInterfaces()) {
+ if (done.add(face)) {
+ for (MethodNode mn : face.getDeclaredMethods(name)) {
+ if (mn.isPublic() && !mn.isStatic()) methods.add(mn);
+ }
+ }
}
}
+
if (receiver.isInterface()) {
methods.addAll(OBJECT_TYPE.getMethods(name));
}
@@ -4914,6 +4919,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return null;
}
+ @Deprecated
protected void collectAllInterfaceMethodsByName(final ClassNode type, final String name, final List<MethodNode> methods) {
Set<ClassNode> done = new LinkedHashSet<>();
for (ClassNode next = type; next != null; next = next.getSuperClass()) {
diff --git a/src/test/groovy/bugs/Groovy10700.groovy b/src/test/groovy/bugs/Groovy10700.groovy
new file mode 100644
index 0000000000..7f55822375
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy10700.groovy
@@ -0,0 +1,82 @@
+/*
+ * 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 groovy.bugs
+
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy10700 {
+ @Test
+ void testDelegateAndInterface() {
+ def config = new CompilerConfiguration(targetDirectory: File.createTempDir())
+
+ def parentDir = File.createTempDir()
+ try {
+ new File(parentDir, 'p').mkdir()
+
+ def a = new File(parentDir, 'p/ABC.groovy')
+ a.write '''
+ package p
+
+ interface A {
+ String decode(String s)
+ }
+
+ class B implements A {
+ String decode(String s) { s }
+ }
+
+ class C implements A {
+ @Delegate private final B b = new B()
+ }
+ '''
+ def b = new File(parentDir, 'p/D.groovy')
+ b.write '''
+ package p
+
+ class D extends C { // implements A
+ @groovy.transform.TypeChecked
+ void test() {
+ def x = decode('string')
+ assert x == 'string'
+ }
+ }
+ '''
+
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ def cu = new CompilationUnit(config, null, loader)
+ cu.addSources(a, b)
+ cu.compile()
+
+ def basePath = config.targetDirectory.absolutePath.replace('\\','/')
+ assertScript """
+ def loader = new GroovyClassLoader(this.class.classLoader)
+ loader.addClasspath('$basePath')
+ def d = loader.loadClass('p.D')
+ d.newInstance().test()
+ """
+ } finally {
+ config.targetDirectory.deleteDir()
+ parentDir.deleteDir()
+ }
+ }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 4f17389bf4..1ac9f6febe 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -2278,6 +2278,38 @@ d.foo()
'''
}
+ // GROOVY-10767
+ void testSimpleSelfTypeInSubTrait2() {
+ assertScript '''
+ import groovy.transform.SelfType
+ import groovy.transform.TypeChecked
+
+ trait A {
+ void methodA() {
+ }
+ }
+ @TypeChecked
+ @SelfType(T)
+ trait B implements A {
+ void methodB() {
+ methodA() // Cannot find matching method <UnionType:T+B>#methodA()
+ }
+ }
+ class C extends T implements B {
+ void method() {
+ methodA()
+ methodB()
+ }
+ }
+ class T {
+ void methodT() {
+ }
+ }
+
+ new C().method()
+ '''
+ }
+
void testDoubleSelfType() {
assertScript '''import groovy.transform.SelfType
import groovy.transform.CompileStatic