You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/11/16 21:43:05 UTC
groovy git commit: GROOVY-8880: Traits - static/instance init blocks
(closes #823)
Repository: groovy
Updated Branches:
refs/heads/master 0eb3d7bd6 -> 55fd0ddaa
GROOVY-8880: Traits - static/instance init blocks (closes #823)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/55fd0dda
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/55fd0dda
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/55fd0dda
Branch: refs/heads/master
Commit: 55fd0ddaa0396dbf84117c6a08a86982ce5fc0d6
Parents: 0eb3d7b
Author: Paul King <pa...@asert.com.au>
Authored: Fri Nov 16 00:20:01 2018 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Sat Nov 17 07:41:58 2018 +1000
----------------------------------------------------------------------
.../transform/trait/TraitASTTransformation.java | 47 +++++++++++++++++++-
.../groovy/transform/trait/TraitComposer.java | 28 +++++++-----
.../traitx/TraitASTTransformationTest.groovy | 37 +++++++++++++++
3 files changed, 98 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/55fd0dda/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index 02c0f08..cd81da6 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -217,6 +217,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
// add methods
List<MethodNode> methods = new ArrayList<MethodNode>(cNode.getMethods());
List<MethodNode> nonPublicAPIMethods = new LinkedList<MethodNode>();
+ List<Statement> staticInitStatements = null;
for (final MethodNode methodNode : methods) {
boolean declared = methodNode.getDeclaringClass() == cNode;
if (declared) {
@@ -226,8 +227,13 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
return null;
}
if (!methodNode.isAbstract()) {
- // add non-abstract methods; abstract methods covered from trait interface
- helper.addMethod(processMethod(cNode, helper, methodNode, fieldHelper, fieldNames));
+ MethodNode newMethod = processMethod(cNode, helper, methodNode, fieldHelper, fieldNames);
+ if (methodNode.getName().equals("<clinit>")) {
+ staticInitStatements = getStatements(newMethod.getCode());
+ } else {
+ // add non-abstract methods; abstract methods covered from trait interface
+ helper.addMethod(newMethod);
+ }
}
if (methodNode.isPrivate() || methodNode.isStatic()) {
nonPublicAPIMethods.add(methodNode);
@@ -245,6 +251,22 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
processField(field, initializer, staticInitializer, fieldHelper, helper, staticFieldHelper, cNode, fieldNames);
}
+ // copy statements from static and instance init blocks
+ if (staticInitStatements != null) {
+ BlockStatement toBlock = getBlockStatement(staticInitializer, staticInitializer.getCode());
+ for (Statement next : staticInitStatements) {
+ toBlock.addStatement(next);
+ }
+ }
+ List<Statement> initStatements = cNode.getObjectInitializerStatements();
+ Statement toCode = initializer.getCode();
+ BlockStatement toBlock = getBlockStatement(initializer, toCode);
+ for (Statement next : initStatements) {
+ Parameter selfParam = createSelfParameter(cNode, false);
+ toBlock.addStatement(processBody(new VariableExpression(selfParam), next, cNode, helper, fieldHelper, fieldNames));
+ }
+ initStatements.clear();
+
// clear properties to avoid generation of methods
cNode.getProperties().clear();
@@ -279,6 +301,27 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
return helper;
}
+ private BlockStatement getBlockStatement(MethodNode targetMethod, Statement code) {
+ BlockStatement toBlock;
+ if (code instanceof BlockStatement) {
+ toBlock = (BlockStatement) code;
+ } else {
+ toBlock = new BlockStatement();
+ toBlock.addStatement(code);
+ targetMethod.setCode(toBlock);
+ }
+ return toBlock;
+ }
+
+ private List<Statement> getStatements(Statement stmt) {
+ if (stmt instanceof BlockStatement) {
+ return ((BlockStatement) stmt).getStatements();
+ }
+ List<Statement> result = new ArrayList<Statement>();
+ result.add(stmt);
+ return result;
+ }
+
private static MethodNode createInitMethod(final boolean isStatic, final ClassNode cNode, final ClassNode helper) {
MethodNode initializer = new MethodNode(
isStatic?Traits.STATIC_INIT_METHOD:Traits.INIT_METHOD,
http://git-wip-us.apache.org/repos/asf/groovy/blob/55fd0dda/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
----------------------------------------------------------------------
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 f7a57f8..70eaba9 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -178,12 +178,6 @@ public abstract class TraitComposer {
createForwarderMethod(trait, cNode, methodNode, originalMethod, helperClassNode, methodGenericsSpec, helperMethodParams, origParams, params, argList, unit);
}
}
- cNode.addObjectInitializerStatements(new ExpressionStatement(
- new MethodCallExpression(
- new ClassExpression(helperClassNode),
- Traits.INIT_METHOD,
- new ArgumentListExpression(new VariableExpression("this")))
- ));
MethodCallExpression staticInitCall = new MethodCallExpression(
new ClassExpression(helperClassNode),
Traits.STATIC_INIT_METHOD,
@@ -276,12 +270,16 @@ public abstract class TraitComposer {
// so instead set within (static) initializer
if (fieldNode.isFinal()) {
String baseName = fieldNode.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
- Expression mce = callX(helperClassNode, baseName + fieldNode.getName(), args(varX("this")));
- Statement stmt = stmt(assignX(varX(fieldNode.getName(), fieldNode.getType()), mce));
- if (isStatic == 0) {
- cNode.addObjectInitializerStatements(stmt);
- } else {
- cNode.addStaticInitializerStatements(Collections.<Statement>singletonList(stmt), false);
+ StaticMethodCallExpression mce = callX(helperClassNode, baseName + fieldNode.getName(), args(varX("this")));
+ if (helperClassNode.hasPossibleStaticMethod(mce.getMethod(), mce.getArguments())) {
+ Statement stmt = stmt(assignX(varX(fieldNode.getName(), fieldNode.getType()), mce));
+ if (isStatic == 0) {
+ cNode.addObjectInitializerStatements(stmt);
+ } else {
+ List<Statement> staticStatements = new ArrayList<Statement>();
+ staticStatements.add(stmt);
+ cNode.addStaticInitializerStatements(staticStatements, true);
+ }
}
}
}
@@ -322,6 +320,12 @@ public abstract class TraitComposer {
cNode.addMethod(impl);
}
}
+ cNode.addObjectInitializerStatements(new ExpressionStatement(
+ new MethodCallExpression(
+ new ClassExpression(helperClassNode),
+ Traits.INIT_METHOD,
+ new ArgumentListExpression(new VariableExpression("this")))
+ ));
}
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/55fd0dda/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 4c3b95e..b20c4c6 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -2607,4 +2607,41 @@ assert c.b() == 2
'''
}
+ //GROOVY-8880
+ void testTraitWithInitBlock() {
+ assertScript '''
+ trait MyTrait {
+ final String first = 'FOO'
+ final String last = 'BAR'
+ String full
+
+ {
+ full = "$first$last"
+ }
+ }
+
+ class MyClass implements MyTrait { }
+
+ def mc = new MyClass()
+ assert mc.full == 'FOOBAR'
+ '''
+ }
+
+ //GROOVY-8880
+ void testTraitWithStaticInitBlock() {
+ assertScript '''
+ trait MyTrait {
+ static final String first = 'FOO'
+ static final String last = 'BAR'
+ static String full
+ static {
+ full = "$first$last"
+ }
+ }
+
+ class MyClass implements MyTrait { }
+
+ assert MyClass.full == 'FOOBAR'
+ '''
+ }
}