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/11/14 19:29:01 UTC

[groovy] branch master updated: improve `getText()` and `toString()` of method and closure

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 cf2f77f  improve `getText()` and `toString()` of method and closure
cf2f77f is described below

commit cf2f77fb033a10d36c4db3a7ff07a2b04631afcf
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Nov 14 13:11:01 2021 -0600

    improve `getText()` and `toString()` of method and closure
---
 .../apache/groovy/ast/tools/MethodNodeUtils.java   | 11 +--
 .../org/codehaus/groovy/ast/AstToTextHelper.java   | 81 ++++++++++------------
 .../java/org/codehaus/groovy/ast/MethodNode.java   | 31 +++++----
 .../groovy/ast/expr/ClosureExpression.java         | 53 +++++++-------
 .../org/codehaus/groovy/ast/MethodNodeTest.groovy  | 73 ++++++++++---------
 .../groovy/ast/expr/ClosureExpressionTest.groovy   | 38 ++++++----
 .../{Groovy6650Bug.groovy => Groovy6650.groovy}    | 43 ++++++------
 7 files changed, 175 insertions(+), 155 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java b/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
index 5b4b346..00b639d 100644
--- a/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
@@ -59,17 +59,18 @@ public class MethodNodeUtils {
      * @return the method node's descriptor
      */
     public static String methodDescriptor(final MethodNode mNode) {
-        StringBuilder sb = new StringBuilder(mNode.getName().length() + mNode.getParameters().length * 10);
+        Parameter[] parameters = mNode.getParameters();
+        int nParameters = parameters == null ? 0 : parameters.length;
+        StringBuilder sb = new StringBuilder(mNode.getName().length() * 2 + nParameters * 10);
         sb.append(mNode.getReturnType().getName());
         sb.append(' ');
         sb.append(mNode.getName());
         sb.append('(');
-        for (int i = 0; i < mNode.getParameters().length; i++) {
+        for (int i = 0; i < nParameters; i += 1) {
             if (i > 0) {
                 sb.append(", ");
             }
-            Parameter p = mNode.getParameters()[i];
-            sb.append(ClassNodeUtils.formatTypeName(p.getType()));
+            sb.append(parameters[i].getType().getName());
         }
         sb.append(')');
         return sb.toString();
@@ -140,7 +141,7 @@ public class MethodNodeUtils {
     public static boolean isGetterCandidate(MethodNode m) {
         Parameter[] parameters = m.getParameters();
         return m.isPublic() && !m.isStatic() && !m.isAbstract()
-                && (null == parameters || 0 == parameters.length)
+                && (parameters == null || parameters.length == 0)
                 && !ClassHelper.VOID_TYPE.equals(m.getReturnType());
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java b/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
index 80dde3f..601166f 100644
--- a/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
@@ -19,92 +19,85 @@
 package org.codehaus.groovy.ast;
 
 import java.lang.reflect.Modifier;
+import java.util.StringJoiner;
 
 /**
  * Helper class for converting AST into text.
  */
 public class AstToTextHelper {
 
-    public static String getClassText(ClassNode node) {
+    public static String getClassText(final ClassNode node) {
         if (node == null) return "<unknown>";
-        if (node.getName() == null) return "<unknown>";
-        return node.getName();
+        return node.toString(false);
     }
 
-    public static String getParameterText(Parameter node) {
+    public static String getParameterText(final Parameter node) {
         if (node == null) return "<unknown>";
 
-        String name = node.getName() == null ? "<unknown>" : node.getName();
+        String name = node.getName();
+        if (name == null) name = "<unknown>";
         String type = getClassText(node.getType());
-        if (node.getInitialExpression() != null) {
-            return type + " " + name + " = " + node.getInitialExpression().getText();
+
+        String text = type + " " + name;
+        if (node.hasInitialExpression()) {
+            text += " = " + node.getInitialExpression().getText();
         }
-        return type + " " + name;
+        return text;
     }
 
-    public static String getParametersText(Parameter[] parameters) {
-        if (parameters == null) return "";
-        if (parameters.length == 0) return "";
-        StringBuilder result = new StringBuilder();
-        int max = parameters.length;
-        for (int x = 0; x < max; x++) {
-            result.append(getParameterText(parameters[x]));
-            if (x < (max - 1)) {
-                result.append(", ");
-            }
+    public static String getParametersText(final Parameter[] parameters) {
+        if (parameters == null || parameters.length == 0) return "";
+        StringJoiner result = new StringJoiner(", ");
+        for (Parameter parameter : parameters) {
+            result.add(getParameterText(parameter));
         }
         return result.toString();
     }
 
-    public static String getThrowsClauseText(ClassNode[] exceptions) {
-        if (exceptions == null) return "";
-        if (exceptions.length == 0) return "";
-        StringBuilder result = new StringBuilder("throws ");
-        int max = exceptions.length;
-        for (int x = 0; x < max; x++) {
-            result.append(getClassText(exceptions[x]));
-            if (x < (max - 1)) {
-                result.append(", "); 
-            }
+    public static String getThrowsClauseText(final ClassNode[] exceptions) {
+        if (exceptions == null || exceptions.length == 0) return "";
+        StringJoiner result = new StringJoiner(", ");
+        for (ClassNode exception : exceptions) {
+            result.add(getClassText(exception));
         }
-        return result.toString(); 
+        return " throws " + result.toString();
     }
 
-    public static String getModifiersText(int modifiers) {
-        StringBuilder result = new StringBuilder();
+    public static String getModifiersText(final int modifiers) {
+        StringJoiner result = new StringJoiner(" ");
         if (Modifier.isPrivate(modifiers)) {
-            result.append("private ");
+            result.add("private");
         }
         if (Modifier.isProtected(modifiers)) {
-            result.append("protected ");
+            result.add("protected");
         }
         if (Modifier.isPublic(modifiers)) {
-            result.append("public ");
+            result.add("public");
         }
         if (Modifier.isStatic(modifiers)) {
-            result.append("static ");
+            result.add("static");
         }
         if (Modifier.isAbstract(modifiers)) {
-            result.append("abstract ");
+            result.add("abstract");
         }
         if (Modifier.isFinal(modifiers)) {
-            result.append("final ");
+            result.add("final");
         }
         if (Modifier.isInterface(modifiers)) {
-            result.append("interface ");
+            result.add("interface");
         }
         if (Modifier.isNative(modifiers)) {
-            result.append("native ");
+            result.add("native");
         }
         if (Modifier.isSynchronized(modifiers)) {
-            result.append("synchronized ");
+            result.add("synchronized");
         }
         if (Modifier.isTransient(modifiers)) {
-            result.append("transient ");
+            result.add("transient");
         }
         if (Modifier.isVolatile(modifiers)) {
-            result.append("volatile ");
+            result.add("volatile");
         }
-        return result.toString().trim();
+        return result.toString();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/MethodNode.java b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
index af4a26e..844dede 100644
--- a/src/main/java/org/codehaus/groovy/ast/MethodNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
@@ -18,7 +18,6 @@
  */
 package org.codehaus.groovy.ast;
 
-import org.apache.groovy.ast.tools.MethodNodeUtils;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 
@@ -26,6 +25,9 @@ import java.lang.reflect.Modifier;
 import java.util.List;
 import java.util.Optional;
 
+import static org.apache.groovy.ast.tools.ClassNodeUtils.formatTypeName;
+import static org.apache.groovy.ast.tools.MethodNodeUtils.methodDescriptor;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.toGenericTypesString;
 import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
 import static org.objectweb.asm.Opcodes.ACC_FINAL;
 import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
@@ -79,7 +81,7 @@ public class MethodNode extends AnnotatedNode {
      */
     public String getTypeDescriptor() {
         if (typeDescriptor == null) {
-            typeDescriptor = MethodNodeUtils.methodDescriptor(this);
+            typeDescriptor = methodDescriptor(this);
         }
         return typeDescriptor;
     }
@@ -276,23 +278,26 @@ public class MethodNode extends AnnotatedNode {
         this.syntheticPublic = syntheticPublic;
     }
 
-    /**
-     * Provides a nicely formatted string of the method definition. For simplicity, generic types on some of the elements
-     * are not displayed.
-     *
-     * @return string form of node with some generic elements suppressed
-     */
     @Override
     public String getText() {
-        String retType = AstToTextHelper.getClassText(returnType);
-        String exceptionTypes = AstToTextHelper.getThrowsClauseText(exceptions);
-        String params = AstToTextHelper.getParametersText(parameters);
         int mask = this instanceof ConstructorNode ? Modifier.constructorModifiers() : Modifier.methodModifiers();
-        return AstToTextHelper.getModifiersText(modifiers & mask) + " " + retType + " " + name + "(" + params + ") " + exceptionTypes + " { ... }";
+        return new StringBuilder(AstToTextHelper.getModifiersText(getModifiers() & mask))
+            .append(' ')
+            .append(toGenericTypesString(getGenericsTypes()))
+            .append(AstToTextHelper.getClassText(getReturnType()))
+            .append(' ')
+            .append(getName())
+            .append('(')
+            .append(AstToTextHelper.getParametersText(getParameters()))
+            .append(')')
+            .append(AstToTextHelper.getThrowsClauseText(getExceptions()))
+            .append(" { ... }")
+            .toString();
     }
 
     @Override
     public String toString() {
-        return super.toString() + "[" + getDeclaringClass().getName() + "#" + getTypeDescriptor() + "]";
+        ClassNode declaringClass = getDeclaringClass();
+        return super.toString() + "[" + getTypeDescriptor() + (declaringClass == null ? "" : " from " + formatTypeName(declaringClass)) + "]";
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java
index d47d07a..00842b4 100644
--- a/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java
@@ -18,13 +18,14 @@
  */
 package org.codehaus.groovy.ast.expr;
 
-import org.codehaus.groovy.ast.AstToTextHelper;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.GroovyCodeVisitor;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.VariableScope;
 import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.runtime.InvokerHelper;
+
+import static org.codehaus.groovy.ast.AstToTextHelper.getParametersText;
+import static org.codehaus.groovy.ast.tools.ClosureUtils.hasImplicitParameter;
 
 /**
  * Represents a closure expression such as <pre>{ statement }</pre>
@@ -36,27 +37,12 @@ public class ClosureExpression extends Expression {
     private Statement code;
     private VariableScope variableScope;
 
-    public ClosureExpression(Parameter[] parameters, Statement code) {
+    public ClosureExpression(final Parameter[] parameters, final Statement code) {
         this.parameters = parameters;
         this.code = code;
         setType(ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
     }
 
-    @Override
-    public void visit(GroovyCodeVisitor visitor) {
-        visitor.visitClosureExpression(this);
-    }
-
-    @Override
-    public Expression transformExpression(ExpressionTransformer transformer) {
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + InvokerHelper.toString(parameters) + "{ " + code + " }";
-    }
-
     /**
      * This gets the code statement of the closure. You can read this method to find out what actions
      * the closure is going to perform.
@@ -73,7 +59,7 @@ public class ClosureExpression extends Expression {
      *
      * @param code the new Statement
      */
-    public void setCode(Statement code) {
+    public void setCode(final Statement code) {
         this.code = code;
     }
 
@@ -95,17 +81,32 @@ public class ClosureExpression extends Expression {
         return variableScope;
     }
 
-    public void setVariableScope(VariableScope variableScope) {
+    public void setVariableScope(final VariableScope variableScope) {
         this.variableScope = variableScope;
     }
 
     @Override
     public String getText() {
-        String paramText = AstToTextHelper.getParametersText(parameters);
-        if (paramText.length() > 0) {
-            return "{ " + paramText + " -> ... }";
-        } else {
-            return "{ -> ... }";
-        }
+        return toString("...");
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + this.toString(code == null ? "<null>" : code.toString());
+    }
+
+    private String toString(final String bodyText) {
+        if (hasImplicitParameter(this)) return "{ " + bodyText + " }";
+        return "{ " + getParametersText(parameters) + " -> " + bodyText + " }";
+    }
+
+    @Override
+    public Expression transformExpression(final ExpressionTransformer transformer) {
+        return this;
+    }
+
+    @Override
+    public void visit(final GroovyCodeVisitor visitor) {
+        visitor.visitClosureExpression(this);
     }
 }
diff --git a/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy b/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy
index 0abbbab..d7bbade 100644
--- a/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy
@@ -19,55 +19,64 @@
 package org.codehaus.groovy.ast
 
 import org.codehaus.groovy.ast.builder.AstBuilder
-import org.codehaus.groovy.ast.stmt.BlockStatement
-import org.objectweb.asm.Opcodes
-
-import junit.framework.TestCase
 import org.codehaus.groovy.control.CompilePhase
+import org.junit.Test
 
-/**
- * Tests the VariableExpressionNode
- */
-class MethodNodeTest extends TestCase implements Opcodes {
+final class MethodNodeTest {
 
-    void testGetTextSimple() {
-        def ast = new AstBuilder().buildFromString CompilePhase.SEMANTIC_ANALYSIS, false, '''
+    private static ClassNode fromString(String source) {
+        new AstBuilder().buildFromString(CompilePhase.SEMANTIC_ANALYSIS, false, source)[1]
+    }
 
-        def myMethod() {
-        }
-'''
-        assert ast[1].@methods.get('myMethod')[0].text ==
-                    'public java.lang.Object myMethod()  { ... }'
+    @Test
+    void testGetText1() {
+        String result = fromString('def method(){}').getMethod('method').text
+        assert result == 'public java.lang.Object method() { ... }'
+    }
+
+    @Test
+    void testGetText2() {
+        def script = fromString '''
+            private static final <T extends Number> T method(String p1, int p2 = 1) throws Exception, IOException { }
+        '''
+        String result = script.getMethods('method')[0].text
+        assert result == 'private static final <T extends java.lang.Number> T method(java.lang.String p1, int p2 = 1) throws java.lang.Exception, java.io.IOException { ... }'
     }
 
-    void testGetTextAdvanced() {
-        def ast = new AstBuilder().buildFromString CompilePhase.SEMANTIC_ANALYSIS, false, '''
+    @Test
+    void testToString() {
+        String result = new MethodNode('foo', 0, null, null, null, null)
+        assert result.endsWith('[java.lang.Object foo()]')
 
-        private static final <T> T myMethod(String p1, int p2 = 1) throws Exception, IOException {
+        Parameter[] params = [new Parameter(ClassHelper.int_TYPE, 'i'), new Parameter(ClassHelper.int_TYPE.makeArray(), 'j')]
+        result = new MethodNode('foo', 0, ClassHelper.STRING_TYPE.makeArray(), params, null, null).tap {
+            declaringClass = ClassHelper.OBJECT_TYPE
         }
-'''
-        assert ast[1].@methods.get('myMethod')[0].text ==
-                    'private static final java.lang.Object myMethod(java.lang.String p1, int p2 = 1) throws java.lang.Exception, java.io.IOException { ... }'
+        assert result.endsWith('[Ljava.lang.String; foo(int, [I) from java.lang.Object]')
     }
 
-    void testIsDynamicReturnTypeExplicitObject() {
-        def methodNode = new MethodNode('foo', ACC_PUBLIC, new ClassNode(Object.class), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement())
-        assert !methodNode.isDynamicReturnType()
+    @Test
+    void testIsDynamicReturnType1() {
+        def methodNode = new MethodNode('foo', 0, ClassHelper.dynamicType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null)
+        assert methodNode.isDynamicReturnType()
     }
 
-    void testIsDynamicReturnTypeDYNAMIC_TYPE() {
-        MethodNode methodNode = new MethodNode('foo', ACC_PUBLIC, ClassHelper.dynamicType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement())
-        assert methodNode.isDynamicReturnType()
+    @Test
+    void testIsDynamicReturnType2() {
+        def methodNode = new MethodNode('foo', 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null)
+        assert !methodNode.isDynamicReturnType()
     }
 
-    void testIsDynamicReturnTypeVoid() {
-        MethodNode methodNode = new MethodNode('foo', ACC_PUBLIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement())
+    @Test
+    void testIsDynamicReturnType3() {
+        def methodNode = new MethodNode('foo', 0, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null)
         assert !methodNode.isDynamicReturnType()
     }
 
-    void testIsDynamicReturnTypeNull() {
-        MethodNode methodNode = new MethodNode('foo', ACC_PUBLIC, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement())
+    @Test
+    void testIsDynamicReturnType4() {
+        def methodNode = new MethodNode('foo', 0, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null)
         assert !methodNode.isDynamicReturnType()
-        assertNotNull(methodNode.getReturnType())
+        assert methodNode.returnType != null
     }
 }
diff --git a/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy b/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy
index ba3a8d5..17efbea 100644
--- a/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy
@@ -18,38 +18,50 @@
  */
 package org.codehaus.groovy.ast.expr
 
-import groovy.test.GroovyTestCase
 import org.codehaus.groovy.ast.builder.AstBuilder
+import org.codehaus.groovy.control.CompilePhase
+import org.junit.Test
 
-class ClosureExpressionTest extends GroovyTestCase {
+final class ClosureExpressionTest {
 
+    private static Expression fromString(String source) {
+        List nodes = new AstBuilder().buildFromString(CompilePhase.SEMANTIC_ANALYSIS, source)
+        nodes[0].statements[0].expression
+    }
+
+    @Test
     void testGetText_Simple() {
-        def expression = buildFromString 'return { it * it }'
-        assert expression.text == '{ -> ... }'
+        def expression = fromString 'return { it * it }'
+        assert expression.text == '{ ... }'
     }
 
+    @Test
     void testGetText_Parameter() {
-        def expression = buildFromString 'return { x -> x * x }'
+        def expression = fromString 'return { x -> x * x }'
         assert expression.text == '{ java.lang.Object x -> ... }'
     }
 
-    void testGetText_MultipleParameters() {
-        def expression = buildFromString 'return { x, y -> x * y }'
+    @Test
+    void testGetText_Parameters() {
+        def expression = fromString 'return { x, y -> x * y }'
         assert expression.text == '{ java.lang.Object x, java.lang.Object y -> ... }'
     }
 
+    @Test
     void testGetText_TypedParameter() {
-        def expression = buildFromString 'return { String x -> x * x }'
+        def expression = fromString 'return { String x -> x * x }'
         assert expression.text == '{ java.lang.String x -> ... }'
     }
 
-    void testGetText_MultipleTypedParameters() {
-        def expression = buildFromString 'return { String x, Integer y -> x * y }'
+    @Test
+    void testGetText_TypedParameters() {
+        def expression = fromString 'return { String x, Integer y -> x * y }'
         assert expression.text == '{ java.lang.String x, java.lang.Integer y -> ... }'
     }
 
-    private Expression buildFromString(String source) {
-        def ast = new AstBuilder().buildFromString(source)
-        ast[0].statements[0].expression
+    @Test
+    void testGetText_ParameterizedType() {
+        def expression = fromString 'return { List<String> x -> }'
+        assert expression.text == '{ java.util.List<java.lang.String> x -> ... }'
     }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6650Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6650.groovy
similarity index 51%
rename from src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6650Bug.groovy
rename to src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6650.groovy
index 4e08e40..7b9e3c1 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6650Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6650.groovy
@@ -22,33 +22,32 @@ package org.codehaus.groovy.classgen.asm.sc.bugs
 import groovy.transform.stc.StaticTypeCheckingTestCase
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
 
-class Groovy6650Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
-    void testShouldChooseVargsMethod() {
-        assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode
+final class Groovy6650 extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
 
-def x = 'a,b,c'.split(',')
-def y = 'd,e,f'.split(',')
+    void testShouldChooseVargsMethod() {
+        assertScript '''
+            import org.codehaus.groovy.ast.MethodNode
 
-@ASTTest(phase=INSTRUCTION_SELECTION,value={
-    def call = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
-    assert call instanceof ExtensionMethodNode
-    def emn = call.extensionMethodNode
-    def typeDesc = emn.typeDescriptor
-    assert typeDesc == '[Ljava.lang.Object; plus(java.lang.Object[], java.lang.Object[])'
-    println emn.typeDescriptor
-})
-String[] result = x + y
-assert result as List == ['a', 'b', 'c', 'd', 'e', 'f']
-'''
+            def x = 'a,b,c'.split(',')
+            def y = 'd,e,f'.split(',')
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                MethodNode target = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
+                assert target instanceof org.codehaus.groovy.transform.stc.ExtensionMethodNode
+                assert target.parameters[0].type == OBJECT_TYPE.makeArray()
+            })
+            String[] result = x + y
+            assert result.toList() == ['a','b','c','d','e','f']
+        '''
     }
 
     void testShouldNotThrowAmbiguousSelectionError() {
-        assertScript '''import org.codehaus.groovy.ast.ClassNode
-import org.codehaus.groovy.ast.MethodNode
+        assertScript '''
+            import org.codehaus.groovy.ast.ClassNode
+            import org.codehaus.groovy.ast.MethodNode
 
-MethodNode methodNode = null
-ClassNode annotation = null
-List annots = methodNode?.getAnnotations(annotation)
-return (annots != null && annots.size() > 0);'''
+            MethodNode methodNode = null; ClassNode annotation = null
+            List annos = methodNode?.getAnnotations(annotation)
+            return (annos != null && !annos.isEmpty())
+        '''
     }
 }