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 2024/01/05 22:10:47 UTC
(groovy) branch GROOVY_4_0_X updated: GROOVY-8854: write `T.m(p)` as `this.m($static$self,p)` not `$self.m(p)`
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new e0a2db64d3 GROOVY-8854: write `T.m(p)` as `this.m($static$self,p)` not `$self.m(p)`
e0a2db64d3 is described below
commit e0a2db64d3eca236b6e0d34d358e1ebb021123db
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jan 5 15:36:46 2024 -0600
GROOVY-8854: write `T.m(p)` as `this.m($static$self,p)` not `$self.m(p)`
GROOVY-7191, GROOVY-7322, GROOVY-11267
4_0_X backport
---
.../transform/stc/TraitTypeCheckingExtension.java | 119 +--
.../groovy/transform/trait/TraitComposer.java | 6 +-
.../transform/trait/TraitReceiverTransformer.java | 29 +-
.../classgen/asm/sc/bugs/Groovy7322Bug.groovy | 64 --
.../groovy/transform/traitx/Groovy7255Bug.groovy | 40 -
.../traitx/TraitASTTransformationTest.groovy | 1047 ++++++++++++--------
.../traitx/TraitWithClosureOrLambda.groovy | 26 +
7 files changed, 702 insertions(+), 629 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java b/src/main/java/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java
index 87a9483cb9..cb0e316409 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java
@@ -25,125 +25,72 @@ import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.MethodCall;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.transform.trait.TraitASTTransformation;
import org.codehaus.groovy.transform.trait.Traits;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.LinkedHashSet;
import java.util.List;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isClassClassNodeWrappingConcreteType;
/**
- * A type checking extension that will take care of handling errors which are specific to traits. In particular, it will
- * handle the "super" method calls within a trait.
+ * An extension that handles field, super and static method calls within a trait.
*
* @since 2.3.0
*/
public class TraitTypeCheckingExtension extends AbstractTypeCheckingExtension {
- private static final List<MethodNode> NOTFOUND = Collections.emptyList();
- /**
- * Builds a type checking extension relying on a Groovy script (type checking DSL).
- *
- * @param typeCheckingVisitor the type checking visitor
- */
public TraitTypeCheckingExtension(final StaticTypeCheckingVisitor typeCheckingVisitor) {
super(typeCheckingVisitor);
}
- @Override
- public void setup() {
- }
-
@Override
public List<MethodNode> handleMissingMethod(final ClassNode receiver, final String name, final ArgumentListExpression argumentList, final ClassNode[] argumentTypes, final MethodCall call) {
String[] decomposed = Traits.decomposeSuperCallName(name);
if (decomposed != null) {
- return convertToDynamicCall(call, receiver, decomposed, argumentTypes);
- }
- if (call instanceof MethodCallExpression) {
- MethodCallExpression mce = (MethodCallExpression) call;
- if (mce.getReceiver() instanceof VariableExpression) {
- VariableExpression var = (VariableExpression) mce.getReceiver();
+ String traitName = decomposed[0], methodName = decomposed[1];
+ List<ClassNode> implementedTraits = Traits.findTraits(receiver);
- // GROOVY-7322
- // static method call in trait?
- ClassNode type = null;
- if (isStaticTraitReceiver(receiver, var)) {
- type = receiver.getGenericsTypes()[0].getType();
- } else if (isThisTraitReceiver(var)) {
- type = receiver;
- }
- if (Traits.isTrait(type) && !(type instanceof UnionTypeClassNode)) {
- List<ClassNode> candidates = new ArrayList<ClassNode>();
- candidates.add(type);
- while (!candidates.isEmpty()) {
- ClassNode next = candidates.remove(0);
- if (!Traits.isTrait(next)) continue;
- ClassNode helper = Traits.findHelper(next);
- Parameter[] params = new Parameter[argumentTypes.length + 1];
- params[0] = new Parameter(ClassHelper.CLASS_Type.getPlainNodeReference(), "staticSelf");
- for (int i = 1; i < params.length; i++) {
- params[i] = new Parameter(argumentTypes[i-1], "p" + i);
- }
- MethodNode method = helper.getDeclaredMethod(name, params);
- if (method != null) {
- return Collections.singletonList(makeDynamic(call, method.getReturnType()));
- }
- // GROOVY-8272 support inherited static methods
- candidates.addAll(Arrays.asList(next.getInterfaces()));
- }
+ ClassNode nextTrait = null;
+ for (int i = 0; i < implementedTraits.size() - 1; i += 1) {
+ ClassNode implementedTrait = implementedTraits.get(i);
+ if (implementedTrait.getName().equals(traitName)) {
+ nextTrait = implementedTraits.get(i + 1);
}
}
- ClassNode dynamic = mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
- if (dynamic!=null) {
- return Collections.singletonList(makeDynamic(call, dynamic));
+ ClassNode returnType = ClassHelper.OBJECT_TYPE;
+ if (nextTrait != null) {
+ List<MethodNode> candidates = typeCheckingVisitor.findMethod(nextTrait, methodName, argumentTypes);
+ if (candidates.size() == 1) {
+ returnType = candidates.get(0).getReturnType();
+ }
}
+
+ return Collections.singletonList(makeDynamic(call, returnType));
}
- return NOTFOUND;
- }
- private static boolean isStaticTraitReceiver(final ClassNode receiver, final VariableExpression var) {
- return Traits.STATIC_THIS_OBJECT.equals(var.getName()) && isClassClassNodeWrappingConcreteType(receiver);
- }
+ if (call instanceof MethodCallExpression) {
+ MethodCallExpression mce = (MethodCallExpression) call;
+ ClassNode dynamic = mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
+ if (dynamic != null) return Collections.singletonList(makeDynamic(call, dynamic));
- private static boolean isThisTraitReceiver(final VariableExpression var) {
- return Traits.THIS_OBJECT.equals(var.getName());
- }
+ // GROOVY-7322, GROOVY-8272, GROOVY-8587, GROOVY-8854: trait: this.m($static$self)
+ ClassNode targetClass = isClassClassNodeWrappingConcreteType(receiver)? receiver.getGenericsTypes()[0].getType(): receiver;
+ if (Traits.isTrait(targetClass.getOuterClass()) && argumentTypes.length > 0 && ClassHelper.isClassType(argumentTypes[0])) {
+ Parameter[] signature = java.util.Arrays.stream(argumentTypes).map(t -> new Parameter(t,"")).toArray(Parameter[]::new);
+ List<ClassNode> traits = Traits.findTraits(targetClass.getOuterClass());
+ traits.remove(targetClass.getOuterClass());
- private List<MethodNode> convertToDynamicCall(MethodCall call, ClassNode receiver, String[] decomposed, ClassNode[] argumentTypes) {
- String traitName = decomposed[0];
- String name = decomposed[1];
- LinkedHashSet<ClassNode> traitsAsList = Traits.collectAllInterfacesReverseOrder(receiver, new LinkedHashSet<ClassNode>());
- ClassNode[] implementedTraits = traitsAsList.toArray(ClassNode.EMPTY_ARRAY);
- ClassNode nextTrait = null;
- for (int i = 0; i < implementedTraits.length - 1; i++) {
- ClassNode implementedTrait = implementedTraits[i];
- if (implementedTrait.getName().equals(traitName)) {
- nextTrait = implementedTraits[i + 1];
+ for (ClassNode trait : traits) { // check super trait for static method
+ MethodNode method = Traits.findHelper(trait).getDeclaredMethod(name, signature);
+ if (method != null && method.isStatic()) {
+ return Collections.singletonList(makeDynamic(call, method.getReturnType()));
+ }
+ }
}
}
- ClassNode[] newArgs = new ClassNode[argumentTypes.length];
- System.arraycopy(argumentTypes, 0, newArgs, 0, newArgs.length);
- ClassNode inferredReturnType = inferTraitMethodReturnType(nextTrait, name, newArgs);
-
- return Collections.singletonList(makeDynamic(call, inferredReturnType));
- }
- private ClassNode inferTraitMethodReturnType(ClassNode nextTrait, String methodName, ClassNode[] paramTypes) {
- ClassNode result = ClassHelper.OBJECT_TYPE;
- if (nextTrait != null) {
- List<MethodNode> candidates = typeCheckingVisitor.findMethod(nextTrait, methodName, paramTypes);
- if (candidates.size() == 1) {
- result = candidates.get(0).getReturnType();
- }
- }
- return result;
+ return Collections.emptyList();
}
-
}
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
index e13142502e..9520f59665 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -130,7 +130,7 @@ public abstract class TraitComposer {
ClassNode staticFieldHelperClassNode = helpers.getStaticFieldHelper();
Map<String, ClassNode> genericsSpec = GenericsUtils.createGenericsSpec(trait, GenericsUtils.createGenericsSpec(cNode));
- for (MethodNode methodNode : helperClassNode.getAllDeclaredMethods()) {
+ for (MethodNode methodNode : helperClassNode.getMethods()) {
String name = methodNode.getName();
Parameter[] helperMethodParams = methodNode.getParameters();
int nParams = helperMethodParams.length;
@@ -180,7 +180,7 @@ public abstract class TraitComposer {
// implementation of methods
List<MethodNode> declaredMethods = new LinkedList<>();
int pos = 0; // keep direct getters at start but in declaration order
- for (MethodNode declaredMethod : fieldHelperClassNode.getAllDeclaredMethods()) {
+ for (MethodNode declaredMethod : fieldHelperClassNode.getMethods()) {
if (declaredMethod.getName().endsWith(Traits.DIRECT_GETTER_SUFFIX)) {
declaredMethods.add(pos++, declaredMethod);
} else {
@@ -189,7 +189,7 @@ public abstract class TraitComposer {
}
if (staticFieldHelperClassNode != null) {
- for (MethodNode declaredMethod : staticFieldHelperClassNode.getAllDeclaredMethods()) {
+ for (MethodNode declaredMethod : staticFieldHelperClassNode.getMethods()) {
if (declaredMethod.getName().endsWith(Traits.DIRECT_GETTER_SUFFIX)) {
declaredMethods.add(pos++, declaredMethod);
} else {
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
index 51efa1e7ca..8ccff4a9f4 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -99,13 +99,28 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
ClassNode weavedType = weaved.getOriginType();
if (exp instanceof BinaryExpression) {
return transformBinaryExpression((BinaryExpression) exp, weavedType);
+ } else if (exp instanceof MethodCallExpression) {
+ MethodCallExpression mce = (MethodCallExpression) exp;
+ String obj = mce.getObjectExpression().getText();
+ if (mce.isImplicitThis() || "this".equals(obj)) {
+ return transformMethodCallOnThis(mce); // this.m(p) --> this.m($self, p)
+ } else if ("super".equals(obj)) {
+ return transformSuperMethodCall(mce); // super.m(p) --> $self.Ttrait$super$m(p)
+ }
} else if (exp instanceof StaticMethodCallExpression) {
StaticMethodCallExpression call = (StaticMethodCallExpression) exp;
if (call.getOwnerType().equals(traitClass)) {
+ // GROOVY-7191, GROOVY-8272, GROOVY-8854, GROOVY-10312: T.m(p) --> this.m($static$self, p)
+ Expression staticSelf = varX(weaved);
+ if (!ClassHelper.isClassType(weavedType)) {
+ staticSelf = callX(staticSelf, "getClass");
+ ((MethodCallExpression) staticSelf).setImplicitThis(false);
+ staticSelf = castX(ClassHelper.CLASS_Type.getPlainNodeReference(), staticSelf);
+ }
MethodCallExpression mce = callX(
- varX(weaved),
+ varX("this"),
call.getMethod(),
- transform(call.getArguments())
+ createArgumentList(staticSelf, call.getArguments())
);
mce.setSafe(false);
mce.setSpreadSafe(false);
@@ -113,14 +128,6 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
mce.setSourcePosition(exp);
return mce;
}
- } else if (exp instanceof MethodCallExpression) {
- MethodCallExpression mce = (MethodCallExpression) exp;
- String obj = mce.getObjectExpression().getText();
- if (mce.isImplicitThis() || "this".equals(obj)) {
- return transformMethodCallOnThis(mce);
- } else if ("super".equals(obj)) {
- return transformSuperMethodCall(mce);
- }
} else if (exp instanceof FieldExpression) {
FieldNode fn = ((FieldExpression) exp).getField();
return transformFieldReference(exp, fn, fn.isStatic());
@@ -311,7 +318,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
newCall.setImplicitThis(false);
newCall.setSafe(false);
} else {
- ArgumentListExpression newArgs = createArgumentList(methodNode.isStatic() ? asClass(varX("this")) : weaved, arguments);
+ ArgumentListExpression newArgs = createArgumentList(methodNode.isStatic() ? asClass(thisExpr) : weaved, arguments);
newCall = callX(inClosure ? classX(traitHelperClass) : thisExpr, methodName, newArgs);
newCall.setImplicitThis(true);
newCall.setSafe(call.isSafe());
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7322Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7322Bug.groovy
deleted file mode 100644
index 628b965930..0000000000
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7322Bug.groovy
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 org.codehaus.groovy.classgen.asm.sc.bugs
-
-import groovy.transform.stc.StaticTypeCheckingTestCase
-import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
-
-class Groovy7322Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
- void testCallStaticTraitMethodFromTraitItself() {
- assertScript '''
- trait SomeTrait {
-
- static someMethod() {
- List theNames = getNames()
- theNames
- }
-
- static List getNames() {
- ['Jeff', 'Betsy', 'Jake', 'Zack']
- }
- }
-
- class SomeClass implements SomeTrait {}
- assert SomeClass.someMethod() == ['Jeff', 'Betsy', 'Jake', 'Zack']
- '''
- }
-
- // GROOVY-7191
- void testCallStaticMethodFromInstanceMethodInTrait() {
- assertScript '''
- trait SomeTrait {
- static int someStaticMethod(){ 1 }
-
- int someInstanceMethod() {
- someStaticMethod()
- }
- }
- class SomeClass implements SomeTrait {}
- def o = new SomeClass()
- assert o.someInstanceMethod() == 1
- '''
- }
-
-}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7255Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7255Bug.groovy
deleted file mode 100644
index 7984486bf7..0000000000
--- a/src/test/org/codehaus/groovy/transform/traitx/Groovy7255Bug.groovy
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.codehaus.groovy.transform.traitx
-
-import groovy.test.GroovyTestCase
-
-class Groovy7255Bug extends GroovyTestCase {
- void testShouldAllowSettingStaticFieldInTraitUsingCompileStatic() {
- assertScript '''
-@groovy.transform.CompileStatic
-trait SomeTrait {
- static List stuff = [1,2,3]
-
- static void initStuff(List l) {
- stuff = stuff + l
- }
-}
-
-class A implements SomeTrait {}
-A.initStuff([4,5,6])
-assert A.stuff == [1,2,3,4,5,6]
-'''
- }
-}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 264dc9728a..07f48aff62 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -18,6 +18,7 @@
*/
package org.codehaus.groovy.transform.traitx
+import groovy.test.NotYetImplemented
import groovy.transform.SelfType
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.expr.ClassExpression
@@ -221,8 +222,9 @@ final class TraitASTTransformationTest {
void setLabel3(String val) { this.@name = val }
String getName() { name }
}
+ class Person implements Named {
+ }
- class Person implements Named {}
def p = new Person()
assert p.name == null
p.setLabel('label')
@@ -280,6 +282,7 @@ final class TraitASTTransformationTest {
})
class Bob implements Foo {
}
+
def b = new Bob()
assert b.sum(1) == 1
b.index = 5
@@ -295,11 +298,11 @@ final class TraitASTTransformationTest {
private String msg = 'foo'
abstract String bar()
public String foo() { bar()+msg }
-
}
-
@CompileStatic
- class A implements Foo { String bar() {'bar'}}
+ class A implements Foo {
+ String bar() {'bar'}
+ }
assert new A().foo() == 'barfoo'
'''
@@ -401,100 +404,6 @@ final class TraitASTTransformationTest {
'''
}
- @Test
- void testClassImplementingTraitWithSameMethod() {
- assertScript shell, '''
- trait A {
- int foo() { 1 }
- }
- trait B {
- int foo() { 2 }
- }
- class AB implements A,B {
- }
- def x = new AB()
- assert x.foo() == 2 // default order, B is first
- '''
-
- assertScript shell, '''
- trait A {
- int foo() { 1 }
- }
- trait B {
- int foo() { 2 }
- }
- class AB implements B,A {
- }
- def x = new AB()
- assert x.foo() == 1 // default order, A is first
- '''
-
- assertScript shell, '''
- trait A {
- int foo() { 1 }
- }
- trait B {
- int foo() { 2 }
- }
- class AB implements A,B {
- int foo() {
- A.super.foo() // explicit use of A
- }
- }
- def x = new AB()
- assert x.foo() == 1
- '''
-
- assertScript shell, '''
- trait A {
- int foo() { 1 }
- }
- trait B {
- int foo() { 2 }
- }
- class AB implements A,B {
- int foo() {
- A.super.foo() // explicit take of A
- }
- }
- def x = new AB()
- assert x.foo() == 1
- '''
-
- // make sure it is compatible with @CompileStatic
- assertScript shell, '''
- trait A {
- int foo() { 1 }
- }
- trait B {
- int foo() { 2 }
- }
- @CompileStatic
- class AB implements A,B {
- int foo() {
- B.super.foo()
- }
- }
- def x = new AB()
- assert x.foo() == 2
- '''
-
- // GROOVY-10144
- assertScript shell, '''
- trait T {
- def m() { 'T' }
- }
- class C implements T {
- @Override
- def m() {
- 'C' + T.super.m()
- }
- }
- String result = new C().m()
- assert result == 'CT'
- '''
- }
-
@Test
void testTraitWithGenerics1() {
for (mode in ['','@TypeChecked','@CompileStatic']) {
@@ -537,7 +446,8 @@ final class TraitASTTransformationTest {
}
}
- @Test // GROOVY-9760
+ // GROOVY-9760
+ @Test
void testTraitWithGenerics3() {
for (mode in ['','@TypeChecked','@CompileStatic']) {
assertScript shell, """
@@ -557,7 +467,8 @@ final class TraitASTTransformationTest {
}
}
- @Test // GROOVY-11012
+ // GROOVY-11012
+ @Test
void testTraitWithGenerics4() {
for (mode in ['','@TypeChecked','@CompileStatic']) {
assertScript shell, """
@@ -953,7 +864,9 @@ final class TraitASTTransformationTest {
String blah() { message }
void update(String msg ) { message = msg}
}
- class Foo implements TestTrait{}
+ class Foo implements TestTrait {
+ }
+
def foo = new Foo()
assert foo.message == 'Hello'
assert foo.blah() == 'Hello'
@@ -970,7 +883,9 @@ final class TraitASTTransformationTest {
void update(String msg ) { message = msg}
}
@CompileStatic
- class Foo implements TestTrait{}
+ class Foo implements TestTrait {
+ }
+
@CompileStatic
void test() {
def foo = new Foo()
@@ -983,7 +898,162 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9255
+ @Test
+ void testTraitMethodOverloadAndOverride() {
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B {
+ int foo() { 2 }
+ }
+ class AB implements A,B {
+ }
+
+ def x = new AB()
+ assert x.foo() == 2 // default order, B is first
+ '''
+
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B {
+ int foo() { 2 }
+ }
+ class BA implements B,A {
+ }
+
+ def x = new BA()
+ assert x.foo() == 1 // default order, A is first
+ '''
+
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B {
+ int foo() { 2 }
+ }
+ class AB implements A,B {
+ int foo() {
+ A.super.foo() // explicit delegation to A
+ }
+ }
+
+ def x = new AB()
+ assert x.foo() == 1
+ '''
+
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B {
+ int foo() { 2 }
+ }
+ class AB implements A,B {
+ int foo() {
+ A.super.foo() // explicit delegation to A
+ }
+ }
+
+ def x = new AB()
+ assert x.foo() == 1
+ '''
+
+ // make sure it is compatible with @CompileStatic
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B {
+ int foo() { 2 }
+ }
+ @CompileStatic
+ class AB implements A,B {
+ int foo() {
+ B.super.foo()
+ }
+ }
+
+ def x = new AB()
+ assert x.foo() == 2
+ '''
+
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B extends A {
+ int foo() {
+ A.super.foo() * 2
+ }
+ }
+ class C implements B {
+ }
+
+ def c = new C()
+ assert c.foo() == 2
+ '''
+
+ assertScript shell, '''
+ @CompileStatic
+ trait A {
+ int foo() { 1 }
+ }
+ @CompileStatic
+ trait B extends A {
+ int foo() {
+ A.super.foo() * 2
+ }
+ }
+ class C implements B {
+ }
+
+ def c = new C()
+ assert c.foo() == 2
+ '''
+
+ // GROOVY-10144
+ assertScript shell, '''
+ trait T {
+ def m() { 'T' }
+ }
+ class C implements T {
+ @Override
+ def m() {
+ 'C' + T.super.m()
+ }
+ }
+ String result = new C().m()
+ assert result == 'CT'
+ '''
+ }
+
+ // GROOVY-8587
+ @Test @NotYetImplemented
+ void testTraitSuperSuperMethod() {
+ assertScript shell, '''
+ trait A {
+ int foo() { 1 }
+ }
+ trait B extends A {
+ }
+ class C implements B {
+ @Override
+ int foo() {
+ B.super.foo() * 2
+ }
+ }
+
+ def c = new C()
+ assert c.foo() == 2
+ '''
+ }
+
+ // GROOVY-9255
+ @Test
void testTraitSuperPropertyGet() {
assertScript shell, '''
trait T {
@@ -1034,7 +1104,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9672
+ // GROOVY-9672
+ @Test
void testTraitSuperPropertyGetStatic() {
assertScript shell, '''
trait T {
@@ -1157,7 +1228,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9672
+ // GROOVY-9672
+ @Test
void testTraitSuperPropertySetStatic() {
assertScript shell, '''
trait T {
@@ -1214,7 +1286,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9673
+ // GROOVY-9673
+ @Test
void testTraitSuperPropertySetWithOverloads() {
assertScript shell, '''
trait T {
@@ -1251,7 +1324,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9672
+ // GROOVY-9672
+ @Test
void testTraitSuperCallStatic() {
assertScript shell, '''
trait A {
@@ -1269,40 +1343,8 @@ final class TraitASTTransformationTest {
'''
}
+ // GROOVY-9256
@Test
- void testTraitSuperCallWhenExtendingAnotherTrait() {
- assertScript shell, '''
- trait Foo {
- int foo() { 1 }
- }
- trait Bar extends Foo {
- int foo() {
- 2*Foo.super.foo()
- }
- }
- class Baz implements Bar {}
- def b = new Baz()
- assert b.foo() == 2
- '''
-
- assertScript shell, '''
- @CompileStatic
- trait Foo {
- int foo() { 1 }
- }
- @CompileStatic
- trait Bar extends Foo {
- int foo() {
- 2*Foo.super.foo()
- }
- }
- class Baz implements Bar {}
- def b = new Baz()
- assert b.foo() == 2
- '''
- }
-
- @Test // GROOVY-9256
void testTraitSuperCallWithinClosure() {
assertScript shell, '''
trait T {
@@ -1503,7 +1545,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8243
+ // GROOVY-8243
+ @Test
void testSAMCoercion5() {
assertScript shell, '''
trait T {
@@ -1521,7 +1564,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8244
+ // GROOVY-8244
+ @Test
void testSAMCoercion6() {
assertScript shell, '''
trait T {
@@ -1582,117 +1626,109 @@ final class TraitASTTransformationTest {
trait Trait1 { private int v = 111; int getValueFromTrait1() { v } }
trait Trait2 { private int v = 222; int getValueFromTrait2() { v } }
class Impl implements Trait1,Trait2 {}
+
def t = new Impl()
assert t.valueFromTrait1 == 111
assert t.valueFromTrait2 == 222
'''
}
+ // GROOVY-7213, GROOVY-8859
@Test
void testPrivateMethodInTrait() {
- assertScript shell, '''
- trait DoingSecretThings {
- private String secret() { 'secret' }
- String foo() { secret() }
- }
- class Foo implements DoingSecretThings {}
- def foo = new Foo()
- assert foo.foo() == 'secret'
- '''
- }
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait T {
+ private String secret() { 'secret' }
+ String foo() { secret() }
+ }
+ $mode
+ class C implements T {
+ }
- @Test
- void testPrivateMethodInTraitAccessingPrivateField() {
- assertScript shell, '''
- trait DoingSecretThings {
- private int x = 0
- private int secret() { x+=1; x }
- int foo() { secret() }
- }
- class Foo implements DoingSecretThings {}
- def foo = new Foo()
- assert foo.foo() == 1
- '''
- }
+ assert new C().foo() == 'secret'
+ """
- @Test
- void testPrivateMethodInTraitWithCompileStatic() {
- assertScript shell, '''
- @CompileStatic
- trait DoingSecretThings {
- private String secret() { 'secret' }
- String foo() { secret() }
- }
- class Foo implements DoingSecretThings {}
- def foo = new Foo()
- assert foo.foo() == 'secret'
- '''
- }
+ shouldFail shell, """
+ $mode
+ trait T {
+ public String bar() {
+ 'public'
+ }
+ private String baz() {
+ 'private'
+ }
+ }
+ $mode
+ class C implements T {
+ def foo() {
+ bar() + baz()
+ }
+ }
- @Test
- void testPrivateMethodInTraitAccessingPrivateFieldCompileStatic() {
- assertScript shell, '''
- @CompileStatic
- trait DoingSecretThings {
- private int x = 0
- private int secret() { x+=1; x }
- int foo() { secret() }
- }
- class Foo implements DoingSecretThings {}
- def foo = new Foo()
- assert foo.foo() == 1
- assert foo.foo() == 2
- '''
+ assert new C().foo() == 'publicprivate'
+ """
+ }
}
@Test
- void testNoShadowingPrivateMethodInTraitAccessingPrivateFieldCompileStatic() {
- assertScript shell, '''
- @CompileStatic
- trait DoingSecretThings {
- private int x = 0
- private int secret() { x+=1; x }
- int foo() { secret() }
- }
- class Foo implements DoingSecretThings {
- int secret() { 666 }
- }
- def foo = new Foo()
- assert foo.foo() == 1
- assert foo.foo() == 2
- '''
+ void testPrivateMethodInTraitAccessingPrivateField() {
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait T {
+ private int x = 0
+ private int secret() { x += 1 }
+ int foo() { secret() }
+ }
+ $mode
+ class C implements T {
+ }
+
+ def c = new C()
+ assert c.foo() == 1
+ assert c.foo() == 2
+ """
+ }
}
@Test
- void testNoShadowingPrivateMethodInTraitAccessingPrivateField() {
- assertScript shell, '''
- trait DoingSecretThings {
- private int x = 0
- private int secret() { x+=1; x }
- int foo() { secret() }
- }
- class Foo implements DoingSecretThings {
- int secret() { 666 }
- }
- def foo = new Foo()
- assert foo.foo() == 1
- assert foo.foo() == 2
- '''
+ void testPrivateMethodInTraitAccessingPrivateFieldNoShadowing() {
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait T {
+ private int x = 0
+ private int secret() { x += 1 }
+ int foo() { secret() }
+ }
+ $mode
+ class C implements T {
+ int secret() { 666 }
+ }
+
+ def c = new C()
+ assert c.foo() == 1
+ assert c.foo() == 2
+ """
+ }
}
@Test
void testMixPrivatePublicMethodsOfSameName() {
def err = shouldFail shell, '''
- trait DoingSecretThings {
+ trait T {
private String secret(String s) { s.toUpperCase() }
String secret() { 'public' }
String foo() { secret('secret') }
}
- class Foo implements DoingSecretThings {}
- def foo = new Foo()
- assert foo.foo() == 'SECRET'
- '''
+ class C implements T {
+ }
+ def c = new C()
+ assert c.foo() == 'SECRET'
+ '''
assert err =~ 'Mixing private and public/protected methods of the same name causes multimethods to be disabled'
}
@@ -1703,13 +1739,14 @@ final class TraitASTTransformationTest {
void foo() { println 'A' }
}
trait B extends A {
- void bar() { println 'B' }
+ void bar() { println 'B' }
}
-
interface C extends B {
void baz()
}
- abstract class D implements C {}
+ abstract class D implements C {
+ }
+
def d = { println 'BAZ' } as D
d.foo()
d.bar()
@@ -1721,7 +1758,7 @@ final class TraitASTTransformationTest {
void testTraitWithDelegate() {
assertScript shell, '''
trait ListTrait<T> {
- private @Delegate ArrayList<T> list = new ArrayList<T>()
+ private @Delegate List<T> list = new ArrayList<T>()
}
class Person implements ListTrait<String> {
void foo() {
@@ -1734,7 +1771,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-7288
+ // GROOVY-7288
+ @Test
void testClassWithTraitDelegate() {
assertScript shell, '''
trait T {
@@ -1754,7 +1792,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9739
+ // GROOVY-9739
+ @Test
void testTraitExtendsTraitWithDelegate() {
assertScript shell, '''
class Main implements ClientSupport {
@@ -1785,7 +1824,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9901
+ // GROOVY-9901
+ @Test
void testTraitWithMemozied() {
assertScript shell, '''
trait Foo {
@@ -1828,7 +1868,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-10553
+ // GROOVY-10553
+ @Test
void testAnnotationShouldBeCarriedOver2() {
assertScript shell, '''
import java.lang.annotation.*
@@ -1870,88 +1911,197 @@ final class TraitASTTransformationTest {
@Test
void testTraitStaticMethod() {
- assertScript shell, '''
- trait StaticProvider {
- static String foo() { 'static method' }
- }
- class Foo implements StaticProvider {}
- assert Foo.foo() == 'static method'
- '''
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait T {
+ static String foo() { 'static method' }
+ }
+ $mode
+ class C implements T {
+ }
+ $mode
+ class D extends C {
+ }
- assertScript shell, '''
- trait StaticProvider {
- static String foo() { bar() }
- static String bar() { 'static method' }
- }
- class Foo implements StaticProvider {}
- assert Foo.foo() == 'static method'
- '''
+ assert C.foo() == 'static method'
+ assert D.foo() == 'static method'
+ assert new C().foo() == 'static method'
+ assert new D().foo() == 'static method'
+ """
+
+ // GROOVY-7322
+ assertScript shell, """
+ $mode
+ trait T {
+ static String bar() { 'static method' }
+ static String foo() { bar() }
+ }
+ $mode
+ class C implements T {
+ }
+ $mode
+ class D extends C {
+ }
+
+ assert C.foo() == 'static method'
+ assert D.foo() == 'static method'
+ assert new C().foo() == 'static method'
+ assert new D().foo() == 'static method'
+ """
+
+ // GROOVY-7191
+ assertScript shell, """
+ $mode
+ trait T {
+ static Number bar() { 1 }
+ Number foo() { bar() }
+ }
+ $mode
+ class C implements T {
+ }
+ $mode
+ class D extends C {
+ }
+
+ assert new C().foo() == 1
+ assert new D().foo() == 1
+ """
+
+ // GROOVY-8854
+ assertScript shell, """
+ $mode
+ trait T {
+ boolean passes
+ void audit() {
+ if (checkCondition()) {
+ passes = true
+ }
+ }
+ private static boolean checkCondition() {
+ true
+ }
+ }
+ $mode
+ class C implements T {
+ String name
+ }
+ $mode
+ class D extends C {
+ }
+
+ def c = new C(name:'name')
+ c.audit(); assert c.passes
+
+ def d = new D(name:'name')
+ d.audit(); assert d.passes
+ """
+ }
}
@Test
void testTraitStaticField() {
- assertScript shell, '''
- trait StaticFieldProvider {
- public static int VAL = 123
- }
- class Foo implements StaticFieldProvider {}
- assert Foo.StaticFieldProvider__VAL == 123
- '''
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait T {
+ public static int VAL = 123
+ }
+ $mode
+ class C implements T {
+ }
- assertScript shell, '''
- trait StaticFieldProvider {
- public static int VAL = 123
- public static void update(int x) { VAL = x }
- }
- class Foo implements StaticFieldProvider {}
- assert Foo.StaticFieldProvider__VAL == 123
- Foo.update(456)
- assert Foo.StaticFieldProvider__VAL == 456
- '''
+ assert C.T__VAL == 123
+ """
+
+ assertScript shell, """
+ $mode
+ trait T {
+ public static int VAL = 123
+ public static void update(int x) { VAL = x }
+ }
+ $mode
+ class C implements T {
+ }
+
+ assert C.T__VAL == 123
+ C.update(456)
+ assert C.T__VAL == 456
+ """
+ }
}
@Test
void testTraitStaticProperty() {
- assertScript shell, '''
- trait StaticPropertyProvider {
- static int VAL = 123
- public static void update(int x) { VAL = x }
- }
- class Foo implements StaticPropertyProvider {
- }
- assert Foo.VAL == 123
- Foo.update(456)
- assert Foo.VAL == 456
- '''
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait T {
+ static int VAL = 123
+ public static void update(int x) { VAL = x }
+ }
+ $mode
+ class C implements T {
+ }
- assertScript shell, '''
- trait T {
- static p = 1
- }
- class C implements T {
- static m() {
- setP(2)
- setP(getP() + 1)
- return getP()
+ assert C.VAL == 123
+ C.update(456)
+ assert C.VAL == 456
+ """
+
+ // GROOVY-7255
+ assertScript shell, """
+ $mode
+ trait T {
+ static List stuff = [1,2,3]
+
+ static initStuff(List list) {
+ stuff = stuff + list
+ }
+ }
+ $mode
+ class C implements T {
}
- }
- assert C.m() == 3
- '''
- // GROOVY-9678
- assertScript shell, '''
- trait T {
- static p = 1
- }
- class C implements T {
- static m() {
- p = 2
- p += 1
- return p
+ C.initStuff([4,5,6])
+ assert C.stuff == [1,2,3,4,5,6]
+ """
+
+ assertScript shell, """
+ $mode
+ trait T {
+ static int p = 1
}
- }
- assert C.m() == 3
- '''
+ $mode
+ class C implements T {
+ static int m() {
+ setP(2)
+ setP(getP() + 1)
+ return getP()
+ }
+ }
+
+ assert C.m() == 3
+ """
+
+ // GROOVY-9678
+ assertScript shell, """
+ $mode
+ trait T {
+ static int p = 1
+ }
+ $mode
+ class C implements T {
+ static int m() {
+ p = 2
+ p += 1
+ return p
+ }
+ }
+
+ assert C.m() == 3
+ """
+ }
}
@Test
@@ -2052,9 +2202,9 @@ final class TraitASTTransformationTest {
'''
}
+ // GROOVY-6672
@Test
void testTraitShouldNotBeAllowedToExtendInterface() {
- // GROOVY-6672
def err = shouldFail shell, '''
trait Foo extends Serializable {}
Foo x = null
@@ -2207,7 +2357,8 @@ final class TraitASTTransformationTest {
assert err =~ 'Prefix expressions on trait fields/properties are not supported in traits'
}
- @Test // GROOVY-6691
+ // GROOVY-6691
+ @Test
void testTraitImplementingGenericSuperTrait() {
assertScript shell, '''
class App {}
@@ -2609,7 +2760,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-6708
+ // GROOVY-6708
+ @Test
void testCovariantReturnTypeWithGenericsInheritance() {
assertScript shell, '''
trait Top<X> {
@@ -2695,7 +2847,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-7058
+ // GROOVY-7058
+ @Test
void testShouldNotThrowNPEBecauseOfIncompleteGenericsTypeInformation() {
assertScript shell, '''
class Project { Task task(String name, Map args) {} }
@@ -2714,7 +2867,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-7123
+ // GROOVY-7123
+ @Test
void testHelperSetterShouldNotReturnVoid() {
assertScript shell, '''
trait A {
@@ -2770,7 +2924,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-10767
+ // GROOVY-10767
+ @Test
void testSimpleSelfTypeInSubTrait2() {
assertScript shell, '''
trait A {
@@ -2962,7 +3117,8 @@ final class TraitASTTransformationTest {
}
}
- @Test // GROOVY-10521
+ // GROOVY-10521
+ @Test
void testVariadicMethodOfPrecompiledTrait() {
assertScript shell, """import org.codehaus.groovy.ast.*
class CT implements ${T10521.name} {
@@ -2978,7 +3134,7 @@ final class TraitASTTransformationTest {
"""
assertScript shell, """
- @Grab('org.spockframework:spock-core:2.2-M3-groovy-4.0')
+ @Grab('org.spockframework:spock-core:2.4-M1-groovy-4.0')
@GrabExclude('org.apache.groovy:*')
import spock.lang.Specification
@@ -2995,7 +3151,8 @@ final class TraitASTTransformationTest {
"""
}
- @Test // GROOVY-7287
+ // GROOVY-7287
+ @Test
void testTraitWithMethodLevelGenericsShadowing1() {
assertScript shell, '''
trait Configurable<ConfigObject> {
@@ -3042,7 +3199,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-7287
+ // GROOVY-7287
+ @Test
void testTraitWithMethodLevelGenericsShadowing2() {
assertScript shell, '''
trait SomeTrait {
@@ -3066,7 +3224,8 @@ final class TraitASTTransformationTest {
}
}
- @Test // GROOVY-7297
+ // GROOVY-7297
+ @Test
void testMethodLevelGenericsFromPrecompiledClass() {
assertScript shell, """
class C implements ${T7297.name} {
@@ -3077,7 +3236,8 @@ final class TraitASTTransformationTest {
"""
}
- @Test // GROOVY-9763
+ // GROOVY-9763
+ @Test
void testTraitWithStaticMethodGenericsSC() {
assertScript shell, '''
trait T {
@@ -3095,7 +3255,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8281
+ // GROOVY-8281
+ @Test
void testFinalFieldsDependency() {
assertScript shell, '''
trait MyTrait {
@@ -3110,7 +3271,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8282
+ // GROOVY-8282
+ @Test
void testBareNamedArgumentPrivateMethodCall() {
assertScript shell, '''
trait BugReproduction {
@@ -3128,7 +3290,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8730
+ // GROOVY-8730
+ @Test
void testAbstractMethodsNotNeededInHelperClass() {
assertScript shell, '''
import static groovy.test.GroovyAssert.shouldFail
@@ -3147,32 +3310,37 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8731
+ // GROOVY-8731
+ @Test
void testStaticMethodsIgnoredWhenExistingInstanceMethodsFound() {
- assertScript shell, '''
- trait StaticFooBarBaz {
- static int foo() { 100 }
- static int baz() { 200 }
- static int bar() { 300 }
- }
-
- trait InstanceBar {
- int bar() { -10 }
- }
-
- class FooBarBaz implements StaticFooBarBaz, InstanceBar {
- int baz() { -20 }
- }
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait StaticFooBarBaz {
+ static int foo() { 100 }
+ static int baz() { 200 }
+ static int bar() { 300 }
+ }
+ $mode
+ trait InstanceBar {
+ int bar() { -10 }
+ }
+ $mode
+ class FooBarBaz implements StaticFooBarBaz, InstanceBar {
+ int baz() { -20 }
+ }
- assert FooBarBaz.foo() == 100
- new FooBarBaz().with {
- assert bar() == -10
- assert baz() == -20
- }
- '''
+ assert FooBarBaz.foo() == 100
+ new FooBarBaz().with {
+ assert bar() == -10
+ assert baz() == -20
+ }
+ """
+ }
}
- @Test // GROOVY-6716
+ // GROOVY-6716
+ @Test
void testAnonymousInnerClassStyleTraitUsage() {
assertScript shell, '''
interface Foo { def foo() }
@@ -3189,7 +3357,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8722
+ // GROOVY-8722
+ @Test
void testFinalModifierSupport() {
assertScript shell, '''
import static java.lang.reflect.Modifier.isFinal
@@ -3244,7 +3413,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8880
+ // GROOVY-8880
+ @Test
void testTraitWithInitBlock() {
assertScript shell, '''
trait MyTrait {
@@ -3264,7 +3434,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8880
+ // GROOVY-8880
+ @Test
void testTraitWithStaticInitBlock() {
assertScript shell, '''
trait MyTrait {
@@ -3282,7 +3453,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8892
+ // GROOVY-8892
+ @Test
void testTraitWithStaticInitBlockWithAndWithoutProps() {
assertScript shell, '''
class Counter {
@@ -3306,108 +3478,127 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8954
- void testTraitWithPropertyAlsoFromInterfaceSC() {
- assertScript shell, '''
- interface DomainProp {
- boolean isNullable()
- }
-
- abstract class OrderedProp implements DomainProp { }
-
- trait Nullable {
- boolean nullable = true
- }
-
- @CompileStatic
- abstract class CustomProp extends OrderedProp implements Nullable { }
+ // GROOVY-8954
+ @Test
+ void testTraitWithPropertyAlsoFromInterface() {
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ interface DomainProp {
+ boolean isNullable()
+ }
+ $mode
+ abstract class OrderedProp implements DomainProp {
+ }
+ $mode
+ trait Nullable {
+ boolean nullable = true
+ }
+ $mode
+ abstract class CustomProp extends OrderedProp implements Nullable {
+ }
- assert new CustomProp() {}
- '''
+ assert new CustomProp() {}
+ """
+ }
}
- @Test // GROOVY-8272
+ // GROOVY-8272
+ @Test @NotYetImplemented
void testTraitAccessToInheritedStaticMethods() {
- assertScript shell, '''
- @CompileStatic
- trait Foo {
- static String go() {
- 'Go!'
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait Foo {
+ static String go() {
+ 'Go!'
+ }
}
- }
-
- @CompileStatic
- trait Bar extends Foo {
- String doIt() {
- go().toUpperCase()
+ $mode
+ trait Bar extends Foo {
+ String test() {
+ go().toUpperCase()
+ }
+ }
+ $mode
+ class Main implements Bar {
}
- }
-
- class Main implements Bar {}
- assert new Main().doIt() == 'GO!'
- '''
+ assert new Main().test() == 'GO!'
+ """
+ }
}
- @Test // GROOVY-10312
+ // GROOVY-10312
+ @Test @NotYetImplemented
void testTraitAccessToInheritedStaticMethods2() {
- assertScript shell, '''
- trait Foo {
- static String staticMethod(String string) {
- return string
- }
- }
- trait Bar extends Foo {
- static String staticMethodWithDefaultArgument(String string = 'works') {
- staticMethod(string) // MissingMethodException
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ trait Foo {
+ static String staticMethod(String string) {
+ return string
+ }
}
- }
-
- class Main implements Bar {
- static test1() {
- String result = staticMethodWithDefaultArgument()
- assert result == 'works'
+ $mode
+ trait Bar extends Foo {
+ static String staticMethodWithDefaultArgument(String string = 'works') {
+ staticMethod(string) // MissingMethodException
+ }
}
- void test2() {
- String result = staticMethodWithDefaultArgument()
- assert result == 'works'
+ $mode
+ class Main implements Bar {
+ static test1() {
+ String result = staticMethodWithDefaultArgument()
+ assert result == 'works'
+ }
+ void test2() {
+ String result = staticMethodWithDefaultArgument()
+ assert result == 'works'
+ }
}
- }
- Main.test1()
- new Main().test2()
- '''
+ Main.test1()
+ new Main().test2()
+ """
+ }
}
- @Test // GROOVY-10312
+ // GROOVY-10312
+ @Test
void testTraitAccessToInheritedStaticMethods3() {
- assertScript shell, '''
- interface Foo {
- public static final String BANG = '!'
- }
- trait Bar implements Foo {
- static String staticMethodWithDefaultArgument(String string = 'works') {
- string + BANG
+ for (mode in ['','@TypeChecked','@CompileStatic']) {
+ assertScript shell, """
+ $mode
+ interface Foo {
+ public static final String BANG = '!'
}
- }
-
- class Main implements Bar {
- static test1() {
- String result = staticMethodWithDefaultArgument()
- assert result == 'works!'
+ $mode
+ trait Bar implements Foo {
+ static String staticMethodWithDefaultArgument(String string = 'works') {
+ string + BANG
+ }
}
- void test2() {
- String result = staticMethodWithDefaultArgument()
- assert result == 'works!'
+ $mode
+ class Main implements Bar {
+ static test1() {
+ String result = staticMethodWithDefaultArgument()
+ assert result == 'works!'
+ }
+ void test2() {
+ String result = staticMethodWithDefaultArgument()
+ assert result == 'works!'
+ }
}
- }
- Main.test1()
- new Main().test2()
- '''
+ Main.test1()
+ new Main().test2()
+ """
+ }
}
- @Test // GROOVY-9386
+ // GROOVY-9386
+ @Test
void testTraitPropertyInitializedByTap() {
assertScript shell, '''
class P {
@@ -3426,7 +3617,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9386
+ // GROOVY-9386
+ @Test
void testTraitPropertyInitializedByWith() {
assertScript shell, '''
class P {
@@ -3445,7 +3637,8 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-8000
+ // GROOVY-8000
+ @Test
void testTraitMultiLevelGenerics() {
assertScript shell, '''
trait TopTrait<X> { X getSomeThing() {}
@@ -3474,17 +3667,20 @@ final class TraitASTTransformationTest {
'''
}
- @Test // GROOVY-9660
+ // GROOVY-9660
+ @Test
void testAsGenericsParam() {
assertScript shell, '''
trait Data {}
class TestData implements Data {}
class AbstractData<D extends Data>{ D data }
+
new AbstractData<TestData>()
'''
}
// GROOVY-10598
+ @Test
void testAssignOperators() {
assertScript shell, '''
trait T {
@@ -3498,6 +3694,7 @@ final class TraitASTTransformationTest {
def var = null
}
}
+
new C().test()
'''
}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitWithClosureOrLambda.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitWithClosureOrLambda.groovy
index 7bc42106cf..50a98f7450 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitWithClosureOrLambda.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitWithClosureOrLambda.groovy
@@ -384,4 +384,30 @@ final class TraitWithClosureOrLambda {
assert new C().f(8) == 18
'''
}
+
+ // GROOVY-11267
+ @Test
+ void testInvokeTraitStaticMethodFromTraitClosure() {
+ assertScript shell, '''
+ trait T {
+ @groovy.transform.CompileDynamic
+ static one() {
+ def me = this
+ two('good') + ' ' +
+ 'bad '.with { me.two(it) } +
+ 'ugly'.with { two(it) }
+ }
+ static two(String s) {
+ three(s)
+ }
+ static three(String s) {
+ return s
+ }
+ }
+ class C implements T {
+ }
+
+ assert C.one() == 'good bad ugly'
+ '''
+ }
}