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/08/18 17:32:39 UTC
[groovy] 02/02: GROOVY-10102: trait SelfType: continue checking
self type for self types
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 2c43daa690d12c1698778f72a09b66fb4eae3fb5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed May 26 09:48:31 2021 -0500
GROOVY-10102: trait SelfType: continue checking self type for self types
Conflicts:
src/test/groovy/transform/stc/BugsSTCTest.groovy
---
.../codehaus/groovy/transform/trait/Traits.java | 46 ++++++++-------
src/test/groovy/transform/stc/BugsSTCTest.groovy | 69 ++++++++++++++++------
2 files changed, 75 insertions(+), 40 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
index e051ad2..a2c5110 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -298,13 +298,12 @@ public abstract class Traits {
* Collects all the self types that a type should extend or implement, given
* the traits is implements. Collects from interfaces and superclasses too.
* @param receiver a class node that may implement a trait
- * @param selfTypes a collection where the list of self types will be written
- * @return the selfTypes collection itself
+ * @param selfTypes a set where the self types will be put
+ * @return the {@code selfTypes} collection
+ *
* @since 2.4.0
*/
- public static LinkedHashSet<ClassNode> collectSelfTypes(
- ClassNode receiver,
- LinkedHashSet<ClassNode> selfTypes) {
+ public static LinkedHashSet<ClassNode> collectSelfTypes(final ClassNode receiver, final LinkedHashSet<ClassNode> selfTypes) {
return collectSelfTypes(receiver, selfTypes, true, true);
}
@@ -312,28 +311,30 @@ public abstract class Traits {
* Collects all the self types that a type should extend or implement, given
* the traits is implements.
* @param receiver a class node that may implement a trait
- * @param selfTypes a collection where the list of self types will be written
+ * @param selfTypes a set where the self types will be put
* @param checkInterfaces should the interfaces that the node implements be collected too
- * @param checkSuper should we collect from the superclass too
- * @return the selfTypes collection itself
+ * @param checkSuperClass should we collect from the superclass too
+ * @return the {@code selfTypes} collection
+ *
* @since 2.4.0
*/
- public static LinkedHashSet<ClassNode> collectSelfTypes(
- ClassNode receiver,
- LinkedHashSet<ClassNode> selfTypes,
- boolean checkInterfaces,
- boolean checkSuper) {
+ public static LinkedHashSet<ClassNode> collectSelfTypes(final ClassNode receiver, final LinkedHashSet<ClassNode> selfTypes, final boolean checkInterfaces, final boolean checkSuperClass) {
if (Traits.isTrait(receiver)) {
List<AnnotationNode> annotations = receiver.getAnnotations(SELFTYPE_CLASSNODE);
for (AnnotationNode annotation : annotations) {
Expression value = annotation.getMember("value");
if (value instanceof ClassExpression) {
- selfTypes.add(value.getType());
+ ClassNode selfType = value.getType();
+ if (selfTypes.add(selfType)) {
+ collectSelfTypes(selfType, selfTypes, checkInterfaces, checkSuperClass);
+ }
} else if (value instanceof ListExpression) {
- List<Expression> expressions = ((ListExpression) value).getExpressions();
- for (Expression expression : expressions) {
+ for (Expression expression : ((ListExpression) value).getExpressions()) {
if (expression instanceof ClassExpression) {
- selfTypes.add(expression.getType());
+ ClassNode selfType = expression.getType();
+ if (selfTypes.add(selfType)) {
+ collectSelfTypes(selfType, selfTypes, checkInterfaces, checkSuperClass);
+ }
}
}
}
@@ -341,14 +342,15 @@ public abstract class Traits {
}
if (checkInterfaces) {
ClassNode[] interfaces = receiver.getInterfaces();
- for (ClassNode anInterface : interfaces) {
- collectSelfTypes(anInterface, selfTypes, true, checkSuper);
+ for (ClassNode interFace : interfaces) {
+ if (!selfTypes.contains(interFace)) {
+ collectSelfTypes(interFace, selfTypes, true, checkSuperClass);
+ }
}
}
-
- if (checkSuper) {
+ if (checkSuperClass) {
ClassNode superClass = receiver.getSuperClass();
- if (superClass != null) {
+ if (superClass != null && !superClass.equals(ClassHelper.OBJECT_TYPE)) {
collectSelfTypes(superClass, selfTypes, checkInterfaces, true);
}
}
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 887fc86..393845f 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -90,34 +90,67 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-7929
void testShouldDetectInvalidMethodUseWithinTraitWithCompileStaticAndSelfType() {
shouldFailWithMessages '''
- class C1 {
- def c1() { }
+ class C {
+ def m() { }
}
@groovy.transform.CompileStatic
- @groovy.transform.SelfType(C1)
- trait TT {
- def foo() {
- c2()
+ @groovy.transform.SelfType(C)
+ trait T {
+ void test() {
+ x()
}
}
- ''', 'Cannot find matching method <UnionType:C1+TT>#c2'
+ ''', 'Cannot find matching method <UnionType:C+T>#x'
}
- void testGroovy5444() {
+ // GROOVY-10102
+ void testShouldDetectValidMethodUseWithinTraitWithCompileStaticAndSelfType() {
assertScript '''
- def curr = { System.currentTimeMillis() }
+ import groovy.transform.*
- 5.times {
- @ASTTest(phase=INSTRUCTION_SELECTION, value= {
- assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
- })
- def t0 = curr()
- 100000.times {
- "echo"
+ trait A {
+ String foo = 'foo'
+ String m(String s, Closure x) {
+ s + x()
+ }
+ }
+ @SelfType(A)
+ trait B {
+ }
+ @SelfType(B)
+ trait C {
+ }
+ @CompileStatic
+ @SelfType(C)
+ trait D {
+ def test() {
+ String s = foo
+ m(s) {
+ s.toUpperCase()
}
- println (curr() - t0)
- }'''
+ }
+ }
+ class E implements A, B, C, D { }
+ assert new E().test() == 'fooFOO'
+ '''
+ }
+
+ void testGroovy5444() {
+ assertScript '''
+ def millis = { System.currentTimeMillis() }
+
+ 5.times {
+ @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+ assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
+ })
+ def t0 = millis()
+ 1000.times {
+ "echo"
+ }
+ def elapsed = millis() - t0
+ }
+ '''
}
void testGroovy5487ReturnNull() {