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/05/26 15:02:22 UTC
[groovy] branch master updated: 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 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 84b03c4 GROOVY-10102: trait SelfType: continue checking self type for self types
84b03c4 is described below
commit 84b03c439fc4d5fa73f89210882b62a131588263
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
---
.../codehaus/groovy/transform/trait/Traits.java | 46 ++++++++---------
src/test/groovy/transform/stc/BugsSTCTest.groovy | 57 +++++++++++++++++-----
2 files changed, 69 insertions(+), 34 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 2dfb5e1..8edeb25 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -300,13 +300,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);
}
@@ -314,28 +313,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);
+ }
}
}
}
@@ -343,14 +344,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 && !ClassHelper.isObjectType(superClass)) {
collectSelfTypes(superClass, selfTypes, checkInterfaces, true);
}
}
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index d9ad1c9..0781a77 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -103,6 +103,39 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
''', 'Cannot find matching method <UnionType:C+T>#x'
}
+ // GROOVY-10102
+ void testShouldDetectValidMethodUseWithinTraitWithCompileStaticAndSelfType() {
+ assertScript '''
+ import groovy.transform.*
+
+ 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()
+ }
+ }
+ }
+
+ class E implements A, B, C, D { }
+ assert new E().test() == 'fooFOO'
+ '''
+ }
+
// GROOVY-10106
void testCallStaticOrPrivateMethodInTraitFieldInitializer() {
['private', 'static', 'private static'].each { mods ->
@@ -139,19 +172,19 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
void testGroovy5444() {
assertScript '''
- def curr = { System.currentTimeMillis() }
-
- 5.times {
- @ASTTest(phase=INSTRUCTION_SELECTION, value= {
- assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
- })
- def t0 = curr()
- 100000.times {
- "echo"
- }
- println (curr() - t0)
- }'''
+ 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() {