You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/04/07 13:30:52 UTC
[09/50] [abbrv] groovy git commit: groovy 7909 bug
groovy 7909 bug
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/64d4f844
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/64d4f844
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/64d4f844
Branch: refs/heads/parrot
Commit: 64d4f844ce60374749d5f5adb3d4075d7165acc4
Parents: 4382195
Author: zhangbo <zh...@nanchao.org>
Authored: Mon Sep 26 10:29:16 2016 +0800
Committer: paulk <pa...@asert.com.au>
Committed: Wed Mar 8 17:49:59 2017 +1000
----------------------------------------------------------------------
.../trait/SuperCallTraitTransformer.java | 83 ++++++++++++++------
.../transform/trait/TraitASTTransformation.java | 23 +++++-
src/test/groovy/bugs/Groovy7909Bug.groovy | 58 ++++++++++++++
3 files changed, 137 insertions(+), 27 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/64d4f844/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java b/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
index f3d35d8..2972c72 100644
--- a/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
@@ -21,7 +21,9 @@ package org.codehaus.groovy.transform.trait;
import groovy.lang.MetaProperty;
import java.util.List;
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.InnerClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -35,6 +37,11 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.syntax.Types;
+import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+
/**
* This transformer is used to transform calls to <code>SomeTrait.super.foo()</code> into the appropriate trait call.
*
@@ -42,6 +49,7 @@ import org.codehaus.groovy.syntax.Types;
* @since 2.3.0
*/
class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
+ public static final String UNRESOLVED_HELPER_CLASS = "UNRESOLVED_HELPER_CLASS";
private final SourceUnit unit;
SuperCallTraitTransformer(final SourceUnit unit) {
@@ -111,36 +119,63 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
Expression objectExpression = exp.getObjectExpression();
ClassNode traitReceiver = ((PropertyExpression) objectExpression).getObjectExpression().getType();
- TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
- // (SomeTrait.super).foo() --> SomeTrait$Helper.foo(this)
- ClassExpression receiver = new ClassExpression(
- helpers.getHelper()
- );
- ArgumentListExpression newArgs = new ArgumentListExpression();
- Expression arguments = exp.getArguments();
- newArgs.addExpression(new VariableExpression("this"));
- if (arguments instanceof TupleExpression) {
- List<Expression> expressions = ((TupleExpression) arguments).getExpressions();
- for (Expression expression : expressions) {
- newArgs.addExpression(transform(expression));
+ if (traitReceiver != null) {
+ // (SomeTrait.super).foo() --> SomeTrait$Helper.foo(this)
+ ClassExpression receiver = new ClassExpression(
+ getHelper(traitReceiver)
+ );
+ ArgumentListExpression newArgs = new ArgumentListExpression();
+ Expression arguments = exp.getArguments();
+ newArgs.addExpression(new VariableExpression("this"));
+ if (arguments instanceof TupleExpression) {
+ List<Expression> expressions = ((TupleExpression) arguments).getExpressions();
+ for (Expression expression : expressions) {
+ newArgs.addExpression(transform(expression));
+ }
+ } else {
+ newArgs.addExpression(transform(arguments));
}
- } else {
- newArgs.addExpression(transform(arguments));
+ MethodCallExpression result = new MethodCallExpression(
+ receiver,
+ transform(exp.getMethod()),
+ newArgs
+ );
+ result.setImplicitThis(false);
+ result.setSpreadSafe(exp.isSpreadSafe());
+ result.setSafe(exp.isSafe());
+ result.setSourcePosition(exp);
+ return result;
}
- MethodCallExpression result = new MethodCallExpression(
- receiver,
- transform(exp.getMethod()),
- newArgs
- );
- result.setImplicitThis(false);
- result.setSpreadSafe(exp.isSpreadSafe());
- result.setSafe(exp.isSafe());
- result.setSourcePosition(exp);
- return result;
}
return super.transform(exp);
}
+ private ClassNode getHelper(final ClassNode traitReceiver) {
+ if (helperClassNotCreatedYet(traitReceiver)) {
+ // GROOVY-7909 A Helper class in same compilation unit may have not been created when referenced
+ // Here create a symbol as a "placeholder" and it will be resolved later.
+ ClassNode ret = new InnerClassNode(
+ traitReceiver,
+ Traits.helperClassName(traitReceiver),
+ ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC,
+ ClassHelper.OBJECT_TYPE,
+ ClassNode.EMPTY_ARRAY,
+ null
+ ).getPlainNodeReference();
+
+ ret.setRedirect(null);
+ traitReceiver.redirect().setNodeMetaData(UNRESOLVED_HELPER_CLASS, ret);
+ return ret;
+ } else {
+ TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
+ return helpers.getHelper();
+ }
+ }
+
+ private boolean helperClassNotCreatedYet(final ClassNode traitReceiver) {
+ return !traitReceiver.redirect().getInnerClasses().hasNext()
+ && this.unit.getAST().getClasses().contains(traitReceiver.redirect());
+ }
private boolean isTraitSuperPropertyExpression(Expression exp) {
if (exp instanceof PropertyExpression) {
PropertyExpression pexp = (PropertyExpression) exp;
http://git-wip-us.apache.org/repos/asf/groovy/blob/64d4f844/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index da71e9e..053ac42 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -70,6 +70,8 @@ import java.util.Set;
import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
+import static org.codehaus.groovy.transform.trait.SuperCallTraitTransformer.UNRESOLVED_HELPER_CLASS;
+
/**
* Handles generation of code for the @Trait annotation. A class annotated with @Trait will generate, instead: <ul>
* <li>an <i>interface</i> with the same name</li> <li>an utility inner class that will be used by the compiler to
@@ -103,7 +105,21 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
checkExtendsClause(cNode);
generateMethodsWithDefaultArgs(cNode);
replaceExtendsByImplements(cNode);
- createHelperClass(cNode);
+ ClassNode helperClassNode = createHelperClass(cNode);
+ resolveHelperClassIfNecessary(helperClassNode);
+ }
+ }
+
+ private void resolveHelperClassIfNecessary(final ClassNode helperClassNode) {
+ if (helperClassNode == null) {
+ return;
+ }
+ for (ClassNode cNode : unit.getAST().getClasses()) {
+ ClassNode unresolvedHelperNode = cNode.getNodeMetaData(UNRESOLVED_HELPER_CLASS);
+ if (unresolvedHelperNode != null
+ && unresolvedHelperNode.getName().equals(helperClassNode.getName())) {
+ unresolvedHelperNode.setRedirect(helperClassNode);
+ }
}
}
@@ -143,7 +159,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
}
}
- private void createHelperClass(final ClassNode cNode) {
+ private ClassNode createHelperClass(final ClassNode cNode) {
ClassNode helper = new InnerClassNode(
cNode,
Traits.helperClassName(cNode),
@@ -190,7 +206,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
if (!methodNode.isSynthetic() && (methodNode.isProtected() || methodNode.getModifiers()==0)) {
unit.addError(new SyntaxException("Cannot have protected/package private method in a trait (" + cNode.getName() + "#" + methodNode.getTypeDescriptor() + ")",
methodNode.getLineNumber(), methodNode.getColumnNumber()));
- return;
+ return null;
}
helper.addMethod(processMethod(cNode, helper, methodNode, fieldHelper, fieldNames));
if (methodNode.isPrivate() || methodNode.isStatic()) {
@@ -233,6 +249,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
if (fieldHelper!=null) {
resolveScope(fieldHelper);
}
+ return helper;
}
private static MethodNode createInitMethod(final boolean isStatic, final ClassNode cNode, final ClassNode helper) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/64d4f844/src/test/groovy/bugs/Groovy7909Bug.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/bugs/Groovy7909Bug.groovy b/src/test/groovy/bugs/Groovy7909Bug.groovy
new file mode 100644
index 0000000..b1e1f97
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy7909Bug.groovy
@@ -0,0 +1,58 @@
+package groovy.bugs
+
+import gls.CompilableTestSupport
+
+class Groovy7909Bug extends CompilableTestSupport {
+ void testDynamicCompile(){
+ shouldCompile '''
+trait Three implements One, Two {
+ def postMake() {
+ One.super.postMake()
+ Two.super.postMake()
+ println "Three"
+ }
+}
+trait One {
+ def postMake() { println "One"}
+}
+trait Two {
+ def postMake() { println "Two"}
+}
+class Four implements Three {
+ def make() {
+ Three.super.postMake()
+ println "All done?"
+ }
+}
+Four f = new Four()
+f.make()
+ '''
+ }
+ void testStaticCompile(){
+ shouldCompile '''
+@groovy.transform.CompileStatic
+trait Three implements One, Two {
+ def postMake() {
+ One.super.postMake()
+ Two.super.postMake()
+ println "Three"
+ }
+}
+trait One {
+ def postMake() { println "One"}
+}
+trait Two {
+ def postMake() { println "Two"}
+}
+class Four implements Three {
+ def make() {
+ Three.super.postMake()
+ println "All done?"
+ }
+}
+Four f = new Four()
+f.make()
+ '''
+ }
+}
+