MapConstructor should have an includeSuperFields annotation attribute plus some 
refactoring


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

Branch: refs/heads/GROOVY_2_6_X
Commit: 4be8c777537b8775eb82f840c9ae1e8d31f43f34
Parents: 3ad9a0e
Author: paulk <pa...@asert.com.au>
Authored: Sun Jan 28 17:00:13 2018 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Wed Jan 31 22:40:31 2018 +1000

----------------------------------------------------------------------
 .../groovy/groovy/transform/MapConstructor.java |  5 ++
 .../java/org/codehaus/groovy/ast/FieldNode.java |  7 +++
 .../codehaus/groovy/ast/tools/GeneralUtils.java | 21 +++++---
 .../MapConstructorASTTransformation.java        | 54 +++++++++-----------
 .../TupleConstructorASTTransformation.java      |  4 +-
 5 files changed, 52 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/4be8c777/src/main/groovy/groovy/transform/MapConstructor.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/MapConstructor.java 
b/src/main/groovy/groovy/transform/MapConstructor.java
index ccd127a..55dee78 100644
--- a/src/main/groovy/groovy/transform/MapConstructor.java
+++ b/src/main/groovy/groovy/transform/MapConstructor.java
@@ -111,6 +111,11 @@ public @interface MapConstructor {
     boolean includeSuperProperties() default false;
 
     /**
+     * Include fields from super classes in the constructor.
+     */
+    boolean includeSuperFields() default false;
+
+    /**
      * Whether to include all properties (as per the JavaBean spec) in the 
generated constructor.
      * When true, Groovy treats any explicitly created setXxx() methods as 
property setters as per the JavaBean
      * specification.

http://git-wip-us.apache.org/repos/asf/groovy/blob/4be8c777/src/main/java/org/codehaus/groovy/ast/FieldNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/FieldNode.java 
b/src/main/java/org/codehaus/groovy/ast/FieldNode.java
index d38f4f4..33e15c3 100644
--- a/src/main/java/org/codehaus/groovy/ast/FieldNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/FieldNode.java
@@ -143,6 +143,13 @@ public class FieldNode extends AnnotatedNode implements 
Opcodes, Variable, Groov
         return (modifiers & ACC_PROTECTED) != 0;
     }
 
+   /**
+     * @return true if the field is private
+     */
+    public boolean isPrivate() {
+        return (modifiers & ACC_PRIVATE) != 0;
+    }
+
     /**
      * @param owner The owner to set.
      */

http://git-wip-us.apache.org/repos/asf/groovy/blob/4be8c777/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
index 807ea7d..4c55515 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -466,16 +466,16 @@ public class GeneralUtils {
         return result;
     }
 
-    public static List<PropertyNode> getAllProperties(Set<String> names, 
ClassNode cNode, boolean includeProperties, boolean includeFields, boolean 
allProperties, boolean traverseSuperClasses) {
-        return getAllProperties(names, cNode, cNode, includeProperties, 
includeFields, allProperties, traverseSuperClasses);
+    public static List<PropertyNode> getAllProperties(Set<String> names, 
ClassNode cNode, boolean includeProperties, boolean includeFields, boolean 
allProperties, boolean traverseSuperClasses, boolean skipReadonly) {
+        return getAllProperties(names, cNode, cNode, includeProperties, 
includeFields, allProperties, traverseSuperClasses, skipReadonly);
     }
 
-    private static List<PropertyNode> getAllProperties(Set<String> names, 
ClassNode origType, ClassNode cNode, boolean includeProperties, boolean 
includeFields, boolean allProperties, boolean traverseSuperClasses) {
+    public static List<PropertyNode> getAllProperties(Set<String> names, 
ClassNode origType, ClassNode cNode, boolean includeProperties, boolean 
includeFields, boolean allProperties, boolean traverseSuperClasses, boolean 
skipReadonly) {
         final List<PropertyNode> result;
         if (cNode == ClassHelper.OBJECT_TYPE || !traverseSuperClasses) {
             result = new ArrayList<PropertyNode>();
         } else {
-            result = getAllProperties(names, origType, cNode.getSuperClass(), 
includeProperties, includeFields, allProperties, true);
+            result = getAllProperties(names, origType, cNode.getSuperClass(), 
includeProperties, includeFields, allProperties, true, skipReadonly);
         }
         if (includeProperties) {
             for (PropertyNode pNode : cNode.getProperties()) {
@@ -490,10 +490,17 @@ public class GeneralUtils {
         }
         if (includeFields) {
             for (FieldNode fNode : cNode.getFields()) {
-                if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == 
null && !names.contains(fNode.getName())) {
-                    result.add(new PropertyNode(fNode, fNode.getModifiers(), 
null, null));
-                    names.add(fNode.getName());
+                if (fNode.isStatic() || cNode.getProperty(fNode.getName()) != 
null || names.contains(fNode.getName())) {
+                    continue;
                 }
+                if (fNode.isPrivate() && !cNode.equals(origType)) {
+                    continue;
+                }
+                if (fNode.isFinal() && fNode.getInitialExpression() != null && 
skipReadonly) {
+                    continue;
+                }
+                result.add(new PropertyNode(fNode, fNode.getModifiers(), null, 
null));
+                names.add(fNode.getName());
             }
         }
         return result;

http://git-wip-us.apache.org/repos/asf/groovy/blob/4be8c777/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
 
b/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
index b6407d3..fb2f94b 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
@@ -41,8 +41,10 @@ import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.apache.groovy.ast.tools.ClassNodeUtils.hasNoArgConstructor;
 import static org.codehaus.groovy.ast.ClassHelper.make;
@@ -54,10 +56,8 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
 import static 
org.codehaus.groovy.ast.tools.GeneralUtils.copyStatementsWithSuperAdjustment;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
-import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceNonPropertyFields;
-import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInstancePropertyFields;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllProperties;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
-import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getSuperPropertyFields;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ifS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.notNullX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
@@ -76,9 +76,6 @@ public class MapConstructorASTTransformation extends 
AbstractASTTransformation {
     static final ClassNode MY_TYPE = make(MY_CLASS);
     static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
     private static final ClassNode MAP_TYPE = makeWithoutCaching(Map.class, 
false);
-//    private static final ClassNode IMMUTABLE_CLASS_TYPE = 
makeWithoutCaching(KnownImmutable.class, false);
-//    private static final ClassNode IMMUTABLE_BASE_TYPE = 
makeWithoutCaching(ImmutableBase.class, false);
-//    private static final ClassNode CHECK_METHOD_TYPE = 
make(ImmutableASTTransformation.class);
 
     public void visit(ASTNode[] nodes, SourceUnit source) {
         init(nodes, source);
@@ -92,6 +89,7 @@ public class MapConstructorASTTransformation extends 
AbstractASTTransformation {
             boolean includeFields = memberHasValue(anno, "includeFields", 
true);
             boolean includeProperties = !memberHasValue(anno, 
"includeProperties", false);
             boolean includeSuperProperties = memberHasValue(anno, 
"includeSuperProperties", true);
+            boolean includeSuperFields = memberHasValue(anno, 
"includeSuperFields", true);
             boolean useSetters = memberHasValue(anno, "useSetters", true);
             boolean allProperties = memberHasValue(anno, "allProperties", 
true);
             boolean noArg = memberHasValue(anno, "noArg", true);
@@ -116,7 +114,7 @@ public class MapConstructorASTTransformation extends 
AbstractASTTransformation {
                 return;
             }
 
-            createConstructors(this, cNode, includeFields, includeProperties, 
includeSuperProperties, useSetters, noArg, allNames, allProperties, 
makeImmutable, excludes, includes, (ClosureExpression) pre, (ClosureExpression) 
post, source);
+            createConstructors(this, cNode, includeFields, includeProperties, 
includeSuperProperties, includeSuperFields, useSetters, noArg, allNames, 
allProperties, makeImmutable, excludes, includes, (ClosureExpression) pre, 
(ClosureExpression) post, source);
 
             if (pre != null) {
                 anno.setMember("pre", new ClosureExpression(new Parameter[0], 
EmptyStatement.INSTANCE));
@@ -127,37 +125,33 @@ public class MapConstructorASTTransformation extends 
AbstractASTTransformation {
         }
     }
 
-    private static void createConstructors(AbstractASTTransformation xform, 
ClassNode cNode, boolean includeFields, boolean includeProperties, boolean 
includeSuperProperties, boolean useSetters, boolean noArg, boolean allNames, 
boolean allProperties, boolean makeImmutable, List<String> excludes, 
List<String> includes, ClosureExpression pre, ClosureExpression post, 
SourceUnit source) {
+    private static void createConstructors(AbstractASTTransformation xform, 
ClassNode cNode, boolean includeFields, boolean includeProperties, boolean 
includeSuperProperties, boolean includeSuperFields, boolean useSetters, boolean 
noArg, boolean allNames, boolean allProperties, boolean makeImmutable, 
List<String> excludes, List<String> includes, ClosureExpression pre, 
ClosureExpression post, SourceUnit source) {
         List<ConstructorNode> constructors = cNode.getDeclaredConstructors();
         boolean foundEmpty = constructors.size() == 1 && 
constructors.get(0).getFirstStatement() == null;
         // HACK: JavaStubGenerator could have snuck in a constructor we don't 
want
         if (foundEmpty) constructors.remove(0);
 
-        // TODO remove duplicated code from alternative paths below
+        Set<String> names = new HashSet<String>();
+        List<PropertyNode> superList;
+        if (includeSuperProperties || includeSuperFields) {
+            superList = getAllProperties(names, cNode, cNode.getSuperClass(), 
includeSuperProperties, includeSuperFields, allProperties, true, true);
+        } else {
+            superList = new ArrayList<PropertyNode>();
+        }
+        List<PropertyNode> list = getAllProperties(names, cNode, true, 
includeFields, allProperties, false, true);
+
         if (makeImmutable) {
-            List<PropertyNode> list = 
ImmutableASTTransformation.getProperties(cNode, includeSuperProperties, 
allProperties);
-            boolean specialHashMapCase = 
ImmutableASTTransformation.isSpecialHashMapCase(list);
+            boolean specialHashMapCase = 
(ImmutableASTTransformation.isSpecialHashMapCase(list) && superList.isEmpty()) 
||
+                    
(ImmutableASTTransformation.isSpecialHashMapCase(superList) && list.isEmpty());
+            superList.addAll(list);
             if (specialHashMapCase) {
-                ImmutableASTTransformation.createConstructorMapSpecial(cNode, 
list);
+                ImmutableASTTransformation.createConstructorMapSpecial(cNode, 
superList);
             } else {
-                ImmutableASTTransformation.createConstructorMap(xform, cNode, 
list);
+                ImmutableASTTransformation.createConstructorMap(xform, cNode, 
superList);
             }
             return;
         }
 
-        List<FieldNode> superList = new ArrayList<FieldNode>();
-        if (includeSuperProperties) {
-            superList.addAll(getSuperPropertyFields(cNode.getSuperClass()));
-        }
-
-        List<FieldNode> list = new ArrayList<FieldNode>();
-        if (includeProperties) {
-            list.addAll(getInstancePropertyFields(cNode));
-        }
-        if (includeFields) {
-            list.addAll(getInstanceNonPropertyFields(cNode));
-        }
-
         Parameter map = param(MAP_TYPE, "args");
         final BlockStatement body = new BlockStatement();
         ClassCodeExpressionTransformer transformer = 
makeMapTypedArgsTransformer();
@@ -166,13 +160,13 @@ public class MapConstructorASTTransformation extends 
AbstractASTTransformation {
             copyStatementsWithSuperAdjustment(transformed, body);
         }
         final BlockStatement inner = new BlockStatement();
-        for (FieldNode fNode : superList) {
-            String name = fNode.getName();
+        for (PropertyNode pNode : superList) {
+            String name = pNode.getName();
             if (shouldSkip(name, excludes, includes, allNames)) continue;
             assignField(useSetters, map, inner, name);
         }
-        for (FieldNode fNode : list) {
-            String name = fNode.getName();
+        for (PropertyNode pNode : list) {
+            String name = pNode.getName();
             if (shouldSkip(name, excludes, includes, allNames)) continue;
             assignField(useSetters, map, inner, name);
         }

http://git-wip-us.apache.org/repos/asf/groovy/blob/4be8c777/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
 
b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
index 7cefac6..ec6a4c0 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
@@ -179,12 +179,12 @@ public class TupleConstructorASTTransformation extends 
AbstractASTTransformation
         Set<String> names = new HashSet<String>();
         List<PropertyNode> superList;
         if (includeSuperProperties || includeSuperFields) {
-            superList = getAllProperties(names, cNode.getSuperClass(), 
includeSuperProperties, includeSuperFields, allProperties, true);
+            superList = getAllProperties(names, cNode.getSuperClass(), 
includeSuperProperties, includeSuperFields, allProperties, true, true);
         } else {
             superList = new ArrayList<PropertyNode>();
         }
 
-        List<PropertyNode> list = getAllProperties(names, cNode, true, 
includeFields, allProperties, false);
+        List<PropertyNode> list = getAllProperties(names, cNode, true, 
includeFields, allProperties, false, true);
 
         if (makeImmutable) {
             boolean specialHashMapCase = 
(ImmutableASTTransformation.isSpecialHashMapCase(list) && superList.isEmpty()) 
||

Reply via email to