Repository: incubator-groovy
Updated Branches:
  refs/heads/master 3844f2835 -> 14a3a6700


Fixes and tests for getting AST transforms relating to bean properties to 
validate their includes/excludes lists.


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

Branch: refs/heads/master
Commit: 1a320e92682a779e06bffcb77b24a0dbc3e24771
Parents: 3844f28
Author: John Hurst <john.b.hu...@gmail.com>
Authored: Sun Dec 28 15:17:50 2014 +1300
Committer: Paul King <pa...@asert.com.au>
Committed: Fri May 22 20:17:30 2015 +1000

----------------------------------------------------------------------
 .../groovy/transform/ExternalizeMethods.java    |  2 +-
 .../transform/AbstractASTTransformation.java    | 27 ++++++++++++
 .../transform/AutoCloneASTTransformation.java   |  1 +
 .../EqualsAndHashCodeASTTransformation.java     |  2 +
 .../transform/ImmutableASTTransformation.java   |  1 +
 .../transform/CanonicalTransformTest.groovy     | 46 ++++++++++++++++++++
 .../transform/ImmutableTransformTest.groovy     | 15 +++++++
 7 files changed, 93 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/main/groovy/transform/ExternalizeMethods.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/transform/ExternalizeMethods.java 
b/src/main/groovy/transform/ExternalizeMethods.java
index 01d5073..5ef37a0 100644
--- a/src/main/groovy/transform/ExternalizeMethods.java
+++ b/src/main/groovy/transform/ExternalizeMethods.java
@@ -33,7 +33,7 @@ import java.lang.annotation.Target;
  * The {@code writeExternal()} method writes each property (and optionally 
field) of the class
  * while the {@code readExternal()} method will read each one back in the same 
order.
  * Properties or fields marked as {@code transient} are ignored.
- * This annotation is typically used in conjunction with the {@code 
@ExternalizeMethods} annotation but
+ * This annotation is typically used in conjunction with the {@code 
@ExternalizeVerifier} annotation but
  * most usually not directly but rather via {@code @AutoExternalizable} which 
is a shortcut for both annotations.
  * <p>
  * Example usage:

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
index 36e1e06..c1a97ec 100644
--- a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
@@ -47,6 +47,8 @@ import java.util.List;
 import java.util.Map;
 
 import static groovy.transform.Undefined.isUndefined;
+import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceNonPropertyFieldNames;
+import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInstancePropertyNames;
 
 public abstract class AbstractASTTransformation implements Opcodes, 
ASTTransformation {
     public static final ClassNode RETENTION_CLASSNODE = 
ClassHelper.makeWithoutCaching(Retention.class);
@@ -269,6 +271,31 @@ public abstract class AbstractASTTransformation implements 
Opcodes, ASTTransform
         }
     }
 
+    protected boolean checkPropertyList(ClassNode cNode, List<String> 
propertyNameList, String listName, AnnotationNode anno, String typeName, 
boolean includeFields) {
+        if (propertyNameList == null || propertyNameList.isEmpty()) {
+            return true;
+        }
+        final List<String> pNames = getInstancePropertyNames(cNode);
+        boolean result = true;
+        if (includeFields) {
+            final List<String> fNames = 
getInstanceNonPropertyFieldNames(cNode);
+            for (String pName : propertyNameList) {
+                if (!pNames.contains(pName) && !fNames.contains(pName)) {
+                    addError("Error during " + typeName + " processing: '" + 
listName + "' property or field '" + pName + "' does not exist.", anno);
+                    result = false;
+                }
+            }
+        } else {
+            for (String pName : propertyNameList) {
+                if (!pNames.contains(pName)) {
+                    addError("Error during " + typeName + " processing: '" + 
listName + "' property '" + pName + "' does not exist.", anno);
+                    result = false;
+                }
+            }
+        }
+        return result;
+    }
+
     /**
      * @deprecated use GenericsUtils#nonGeneric
      */

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
index f32a1ee..ba9d877 100644
--- a/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
@@ -84,6 +84,7 @@ public class AutoCloneASTTransformation extends 
AbstractASTTransformation {
             boolean includeFields = memberHasValue(anno, "includeFields", 
true);
             AutoCloneStyle style = getStyle(anno, "style");
             List<String> excludes = getMemberList(anno, "excludes");
+            if (!checkPropertyList(cNode, excludes, "excludes", anno, 
MY_TYPE_NAME, includeFields)) return;
             List<FieldNode> list = getInstancePropertyFields(cNode);
             if (includeFields) {
                 list.addAll(getInstanceNonPropertyFields(cNode));

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/main/org/codehaus/groovy/transform/EqualsAndHashCodeASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/EqualsAndHashCodeASTTransformation.java
 
b/src/main/org/codehaus/groovy/transform/EqualsAndHashCodeASTTransformation.java
index d1a46b5..4857ebe 100644
--- 
a/src/main/org/codehaus/groovy/transform/EqualsAndHashCodeASTTransformation.java
+++ 
b/src/main/org/codehaus/groovy/transform/EqualsAndHashCodeASTTransformation.java
@@ -74,6 +74,8 @@ public class EqualsAndHashCodeASTTransformation extends 
AbstractASTTransformatio
             List<String> excludes = getMemberList(anno, "excludes");
             List<String> includes = getMemberList(anno, "includes");
             if (!checkIncludeExclude(anno, excludes, includes, MY_TYPE_NAME)) 
return;
+            if (!checkPropertyList(cNode, includes, "includes", anno, 
MY_TYPE_NAME, includeFields)) return;
+            if (!checkPropertyList(cNode, excludes, "excludes", anno, 
MY_TYPE_NAME, includeFields)) return;
             createHashCode(cNode, cacheHashCode, includeFields, callSuper, 
excludes, includes);
             createEquals(cNode, includeFields, callSuper, useCanEqual, 
excludes, includes);
         }

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java 
b/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
index 6257192..d06e8a5 100644
--- a/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
@@ -146,6 +146,7 @@ public class ImmutableASTTransformation extends 
AbstractASTTransformation {
             ClassNode cNode = (ClassNode) parent;
             String cName = cNode.getName();
             if (!checkNotInterface(cNode, MY_TYPE_NAME)) return;
+            if (!checkPropertyList(cNode, knownImmutables, "knownImmutables", 
node, MY_TYPE_NAME, false)) return;
             makeClassFinal(cNode);
 
             final List<PropertyNode> pList = getInstanceProperties(cNode);

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/test/org/codehaus/groovy/transform/CanonicalTransformTest.groovy
----------------------------------------------------------------------
diff --git 
a/src/test/org/codehaus/groovy/transform/CanonicalTransformTest.groovy 
b/src/test/org/codehaus/groovy/transform/CanonicalTransformTest.groovy
index 944b103..04710c5 100644
--- a/src/test/org/codehaus/groovy/transform/CanonicalTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/CanonicalTransformTest.groovy
@@ -594,4 +594,50 @@ class CanonicalTransformTest extends GroovyShellTestCase {
         """
     }
 
+    // GROOVY-7227
+    void testIncludesAndExcludesTogetherResultsInError() {
+        def message = shouldFail {
+            evaluate("""
+                 import groovy.transform.Canonical
+                 @Canonical(includes='surName', excludes='surName')
+                 class Person {
+                     String surName
+                 }
+                 new Person(surName: "Doe").toString()
+             """)
+        }
+        assert message.contains("Error during @Canonical processing: Only one 
of 'includes' and 'excludes' should be supplied not both.")
+    }
+
+    // GROOVY-7227
+    void testIncludesWithInvalidPropertyNameResultsInError() {
+        def message = shouldFail {
+            evaluate("""
+                 import groovy.transform.Canonical
+                 @Canonical(includes='sirName')
+                 class Person {
+                     String surName
+                 }
+                 new Person(surName: "Doe").toString()
+             """)
+        }
+        assert message.contains("Error during @Canonical processing: 
'includes' property 'sirName' does not exist.")
+    }
+
+    // GROOVY-7227
+    void testExcludesWithInvalidPropertyNameResultsInError() {
+        def message = shouldFail {
+            evaluate("""
+                 import groovy.transform.Canonical
+                 @Canonical(excludes='sirName')
+                 class Person {
+                     String firstName
+                     String surName
+                 }
+                 new Person(firstName: "John", surName: "Doe").toString()
+             """)
+        }
+        assert message.contains("Error during @Canonical processing: 
'excludes' property 'sirName' does not exist.")
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1a320e92/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
----------------------------------------------------------------------
diff --git 
a/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy 
b/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
index 1d03e2b..3c19842 100644
--- a/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
@@ -903,6 +903,21 @@ class ImmutableTransformTest extends GroovyShellTestCase {
         assert result.first == [ 'tim', 'tim' ]
     }
 
+    // GROOVY-7227
+    void testKnownImmutablesWithInvalidPropertyNameResultsInError() {
+        def message = shouldFail {
+            evaluate """
+               import groovy.transform.Immutable
+               @Immutable(knownImmutables=['sirName'])
+               class Person {
+                   String surName
+               }
+               new Person(surName: "Doe")
+           """
+        }
+        assert message.contains("Error during @Immutable processing: 
'knownImmutables' property 'sirName' does not exist.")
+    }
+
     // GROOVY-7162
     void testImmutableWithSuperClass() {
         assertScript '''

Reply via email to