Repository: groovy
Updated Branches:
  refs/heads/master e9e7724da -> 9d2b7fd21


GROOVY-8011: @ToString if used with includes='prop1,prop2' could allow the 
pseudo prop name 'super' as an alternative to using the includeSuper flag 
(closes #467)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/9d2b7fd2
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/9d2b7fd2
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/9d2b7fd2

Branch: refs/heads/master
Commit: 9d2b7fd219ff4ce11a6e75a2c530923f8293844b
Parents: e9e7724
Author: paulk <pa...@asert.com.au>
Authored: Thu Dec 1 14:55:20 2016 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Fri Dec 2 04:34:09 2016 +1000

----------------------------------------------------------------------
 src/main/groovy/transform/ToString.java         | 15 +++----
 .../transform/ToStringASTTransformation.java    | 42 +++++++++++++++-----
 .../transform/ToStringTransformTest.groovy      | 21 ++++++++++
 3 files changed, 61 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/9d2b7fd2/src/main/groovy/transform/ToString.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/transform/ToString.java 
b/src/main/groovy/transform/ToString.java
index c1e2145..9fc4627 100644
--- a/src/main/groovy/transform/ToString.java
+++ b/src/main/groovy/transform/ToString.java
@@ -273,6 +273,7 @@ public @interface ToString {
      * can be used in addition to an array (using Groovy's literal list 
notation) of String values.
      * The default value is a special marker value indicating that no includes 
are defined; all fields and/or properties
      * are included if 'includes' remains undefined and 'excludes' is 
explicitly or implicitly an empty list.
+     * The special name 'super' can be used instead of using the 
'includeSuper' flag.
      */
     String[] includes() default {Undefined.STRING};
 
@@ -328,11 +329,11 @@ public @interface ToString {
      */
     boolean cache() default false;
 
-    /**
-     * Whether to include all fields and/or properties in the generated 
toString, including those with names that
-     * are considered internal.
-     *
-     * @since 2.5.0
-     */
-    boolean allNames() default false;
+    /**
+     * Whether to include all fields and/or properties in the generated 
toString, including those with names that
+     * are considered internal.
+     *
+     * @since 2.5.0
+     */
+    boolean allNames() default false;
 }

http://git-wip-us.apache.org/repos/asf/groovy/blob/9d2b7fd2/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
index 5040414..3cba4a5 100644
--- a/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
@@ -37,6 +37,7 @@ import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.tools.BeanUtils;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 
@@ -70,20 +71,23 @@ public class ToStringASTTransformation extends 
AbstractASTTransformation {
             boolean includeSuper = memberHasValue(anno, "includeSuper", true);
             boolean includeSuperProperties = memberHasValue(anno, 
"includeSuperProperties", true);
             boolean cacheToString = memberHasValue(anno, "cache", true);
+            List<String> excludes = getMemberStringList(anno, "excludes");
+            List<String> includes = getMemberStringList(anno, "includes");
+            if (includes != null && includes.contains("super")) {
+                includeSuper = true;
+            }
             if (includeSuper && 
cNode.getSuperClass().getName().equals("java.lang.Object")) {
                 addError("Error during " + MY_TYPE_NAME + " processing: 
includeSuper=true but '" + cNode.getName() + "' has no super class.", anno);
             }
             boolean includeNames = memberHasValue(anno, "includeNames", true);
             boolean includeFields = memberHasValue(anno, "includeFields", 
true);
-            List<String> excludes = getMemberStringList(anno, "excludes");
-            List<String> includes = getMemberStringList(anno, "includes");
             boolean ignoreNulls = memberHasValue(anno, "ignoreNulls", true);
             boolean includePackage = !memberHasValue(anno, "includePackage", 
false);
             boolean allProperties = !memberHasValue(anno, "allProperties", 
false);
             boolean allNames = memberHasValue(anno, "allNames", true);
 
             if (!checkIncludeExcludeUndefinedAware(anno, excludes, includes, 
MY_TYPE_NAME)) return;
-            if (!checkPropertyList(cNode, includes, "includes", anno, 
MY_TYPE_NAME, includeFields)) return;
+            if (!checkPropertyList(cNode, includes != null ? 
DefaultGroovyMethods.minus(includes, "super") : null, "includes", anno, 
MY_TYPE_NAME, includeFields)) return;
             if (!checkPropertyList(cNode, excludes, "excludes", anno, 
MY_TYPE_NAME, includeFields)) return;
             createToString(cNode, includeSuper, includeFields, excludes, 
includes, includeNames, ignoreNulls, includePackage, cacheToString, 
includeSuperProperties, allProperties, allNames);
         }
@@ -137,10 +141,23 @@ public class ToStringASTTransformation extends 
AbstractASTTransformation {
                 ClassHelper.STRING_TYPE, Parameter.EMPTY_ARRAY, 
ClassNode.EMPTY_ARRAY, body));
     }
 
+    private static class ToStringElement {
+        ToStringElement(Expression value, String name, boolean canBeSelf) {
+            this.value = value;
+            this.name = name;
+            this.canBeSelf = canBeSelf;
+        }
+
+        Expression value;
+        String name;
+        boolean canBeSelf;
+    }
+
     private static Expression calculateToStringStatements(ClassNode cNode, 
boolean includeSuper, boolean includeFields, List<String> excludes, 
List<String> includes, boolean includeNames, boolean ignoreNulls, boolean 
includePackage, boolean includeSuperProperties, boolean allProperties, 
BlockStatement body, boolean allNames) {
         // def _result = new StringBuilder()
         final Expression result = varX("_result");
         body.addStatement(declS(result, ctorX(STRINGBUILDER_TYPE)));
+        List<ToStringElement> elements = new ArrayList<ToStringElement>();
 
         // def $toStringFirst = true
         final VariableExpression first = varX("$toStringFirst");
@@ -155,7 +172,7 @@ public class ToStringASTTransformation extends 
AbstractASTTransformation {
         for (PropertyNode pNode : pList) {
             if (shouldSkip(pNode.getName(), excludes, includes, allNames)) 
continue;
             Expression getter = getterThisX(cNode, pNode);
-            appendValue(cNode, body, result, first, getter, 
pNode.getOriginType(), pNode.getName(), includeNames, ignoreNulls);
+            elements.add(new ToStringElement(getter, pNode.getName(), 
canBeSelf(cNode, pNode.getOriginType())));
         }
 
         // append fields if needed
@@ -164,16 +181,18 @@ public class ToStringASTTransformation extends 
AbstractASTTransformation {
             fList.addAll(getInstanceNonPropertyFields(cNode));
             for (FieldNode fNode : fList) {
                 if (shouldSkip(fNode.getName(), excludes, includes, allNames)) 
continue;
-                appendValue(cNode, body, result, first, varX(fNode), 
fNode.getType(), fNode.getName(), includeNames, ignoreNulls);
+                elements.add(new ToStringElement(varX(fNode), fNode.getName(), 
canBeSelf(cNode, fNode.getType())));
             }
         }
 
         // append super if needed
         if (includeSuper) {
-            appendCommaIfNotFirst(body, result, first);
-            appendPrefix(body, result, "super", includeNames);
             // not through MOP to avoid infinite recursion
-            body.addStatement(appendS(result, callSuperX("toString")));
+            elements.add(new ToStringElement(callSuperX("toString"), "super", 
false));
+        }
+
+        for (ToStringElement el : elements) {
+            appendValue(body, result, first, el.value, el.name, includeNames, 
ignoreNulls, el.canBeSelf);
         }
 
         // wrap up
@@ -183,12 +202,11 @@ public class ToStringASTTransformation extends 
AbstractASTTransformation {
         return toString;
     }
 
-    private static void appendValue(ClassNode cNode, BlockStatement body, 
Expression result, VariableExpression first, Expression value, ClassNode 
valueType, String name, boolean includeNames, boolean ignoreNulls) {
+    private static void appendValue(BlockStatement body, Expression result, 
VariableExpression first, Expression value, String name, boolean includeNames, 
boolean ignoreNulls, boolean canBeSelf) {
         final BlockStatement thenBlock = new BlockStatement();
         final Statement appendValue = ignoreNulls ? ifS(notNullX(value), 
thenBlock) : thenBlock;
         appendCommaIfNotFirst(thenBlock, result, first);
         appendPrefix(thenBlock, result, name, includeNames);
-        boolean canBeSelf = 
StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(valueType, cNode);
         if (canBeSelf) {
             thenBlock.addStatement(ifElseS(
                     sameX(value, new VariableExpression("this")),
@@ -201,6 +219,10 @@ public class ToStringASTTransformation extends 
AbstractASTTransformation {
         body.addStatement(appendValue);
     }
 
+    private static boolean canBeSelf(ClassNode cNode, ClassNode valueType) {
+        return 
StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(valueType, cNode);
+    }
+
     private static void appendCommaIfNotFirst(BlockStatement body, Expression 
result, VariableExpression first) {
         // if ($toStringFirst) $toStringFirst = false else result.append(", ")
         body.addStatement(ifElseS(

http://git-wip-us.apache.org/repos/asf/groovy/blob/9d2b7fd2/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
----------------------------------------------------------------------
diff --git 
a/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy 
b/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
index 7f28237..18f5d10 100644
--- a/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
@@ -448,4 +448,25 @@ class ToStringTransformTest extends GroovyShellTestCase {
         '''
     }
 
+    void testIncludesWithSuper_Groovy8011() {
+        def toString = evaluate("""
+            import groovy.transform.*
+
+            @ToString
+            class Foo {
+                String baz = 'baz'
+            }
+
+            @ToString(includes='super,num,blah', includeNames=true)
+            class Bar extends Foo {
+                String blah = 'blah'
+                int num = 42
+            }
+
+            new Bar().toString()
+        """)
+
+        assert toString.contains('super:Foo(baz)')
+    }
+
 }

Reply via email to