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 2019/12/11 10:44:38 UTC

[groovy] 03/06: GROOVY-8562: copy metadata instead of recalling checkOrMarkPrivateAccess

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit a5a8d510fd550a97aa40655c58697112e9804ae8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Dec 10 17:10:59 2019 -0600

    GROOVY-8562: copy metadata instead of recalling checkOrMarkPrivateAccess
    
    refactor visitVariableExpression to check accessedVariable in one pass
    
    (cherry picked from commit 5e5bfd8ed2e5bc6ed64126ed10680653bd1f8b78)
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 234 +++++++++------------
 1 file changed, 103 insertions(+), 131 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index cb5dd85..2a8dea3 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -109,7 +109,6 @@ import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.syntax.TokenUtil;
 import org.codehaus.groovy.transform.StaticTypesTransformation;
-import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
 import org.codehaus.groovy.transform.trait.Traits;
 import org.codehaus.groovy.util.ListHashMap;
 import org.objectweb.asm.Opcodes;
@@ -558,114 +557,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    private void checkSuperCallFromClosure(final Expression call, final MethodNode directCallTarget) {
-        if (call instanceof MethodCallExpression && typeCheckingContext.getEnclosingClosure() != null) {
-            Expression objectExpression = ((MethodCallExpression) call).getObjectExpression();
-            if (isSuperExpression(objectExpression)) {
-                ClassNode current = typeCheckingContext.getEnclosingClassNode();
-                current.getNodeMetaData(SUPER_MOP_METHOD_REQUIRED, x -> new LinkedList<>()).add(directCallTarget);
-                call.putNodeMetaData(SUPER_MOP_METHOD_REQUIRED, current);
-            }
-        }
-    }
-
-    /**
-     * Wrap type in Class&lt;&gt; if usingClass==true.
-     */
-    private static ClassNode makeType(final ClassNode cn, final boolean usingClass) {
-        if (usingClass) {
-            ClassNode clazzType = CLASS_Type.getPlainNodeReference();
-            clazzType.setGenericsTypes(new GenericsType[]{new GenericsType(cn)});
-            return clazzType;
-        } else {
-            return cn;
-        }
-    }
-
-    private boolean storeTypeForThis(final VariableExpression vexp) {
-        if (vexp == VariableExpression.THIS_EXPRESSION) return true;
-        if (!vexp.isThisExpression()) return false;
-        ClassNode enclosingClassNode = typeCheckingContext.getEnclosingClassNode();
-        storeType(vexp, makeType(enclosingClassNode, typeCheckingContext.isInStaticContext));
-        return true;
-    }
-
-    private boolean storeTypeForSuper(final VariableExpression vexp) {
-        if (vexp == VariableExpression.SUPER_EXPRESSION) return true;
-        if (!vexp.isSuperExpression()) return false;
-        ClassNode superClassNode = typeCheckingContext.getEnclosingClassNode().getSuperClass();
-        storeType(vexp, makeType(superClassNode, typeCheckingContext.isInStaticContext));
-        return true;
-    }
-
     @Override
     public void visitVariableExpression(final VariableExpression vexp) {
         super.visitVariableExpression(vexp);
-
-        if (storeTypeForThis(vexp)) return;
         if (storeTypeForSuper(vexp)) return;
-        Variable accessedVariable = vexp.getAccessedVariable();
-        if (accessedVariable instanceof PropertyNode) {
-            // we must be careful, because the property node may be of a wrong type:
-            // if a class contains a getter and a setter of different types or
-            // overloaded setters, the type of the property node is arbitrary!
-            if (tryVariableExpressionAsProperty(vexp, vexp.getName())) {
-                BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
-                if (enclosingBinaryExpression != null) {
-                    Expression leftExpression = enclosingBinaryExpression.getLeftExpression();
-                    SetterInfo setterInfo = removeSetterInfo(leftExpression);
-                    if (setterInfo != null) {
-                        Expression rightExpression = enclosingBinaryExpression.getRightExpression();
-                        if (!ensureValidSetter(vexp, leftExpression, rightExpression, setterInfo)) {
-                            return;
-                        }
-                    }
-                }
-            }
-        } else if (accessedVariable instanceof FieldNode) {
-            FieldNode fieldNode = (FieldNode) accessedVariable;
-
-            TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
-            if (enclosingClosure != null) {
-                // GROOVY-8562
-                // when vexp has the same name as a property of the owner,
-                // the IMPLICIT_RECEIVER must be set in case it's the delegate
-                if (tryVariableExpressionAsProperty(vexp, vexp.getName())) {
-                    // IMPLICIT_RECEIVER is handled elsewhere
-                    // however other access needs to be fixed for private access
-                    if (vexp.getNodeMetaData(IMPLICIT_RECEIVER) == null) {
-                        ClassNode owner = vexp.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
-                        if (owner != null) {
-                            FieldNode veFieldNode = owner.getField(vexp.getName());
-                            if (veFieldNode != null) {
-                                fieldNode = veFieldNode;
-                                boolean lhsOfEnclosingAssignment = isLHSOfEnclosingAssignment(vexp);
-                                vexp.setAccessedVariable(fieldNode);
-                                checkOrMarkPrivateAccess(vexp, fieldNode, lhsOfEnclosingAssignment);
-                            }
-                        }
-                    }
-                }
-            }
-
-            ClassNode actualType = findActualTypeByGenericsPlaceholderName(
-                    fieldNode.getOriginType().getUnresolvedName(),
-                    makeDeclaringAndActualGenericsTypeMap(fieldNode.getDeclaringClass(), typeCheckingContext.getEnclosingClassNode())
-            );
-
-            if (actualType != null) {
-                storeType(vexp, actualType);
-                return;
-            }
-        }
+        if (storeTypeForThis(vexp)) return;
+        String name = vexp.getName();
 
         TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
         if (enclosingClosure != null) {
-            switch (vexp.getName()) {
+            switch (name) {
                 case "delegate":
-                    DelegationMetadata md = getDelegationMetadata(enclosingClosure.getClosureExpression());
-                    if (md != null) {
-                        storeType(vexp, md.getType());
+                    DelegationMetadata dm = getDelegationMetadata(enclosingClosure.getClosureExpression());
+                    if (dm != null) {
+                        storeType(vexp, dm.getType());
                         return;
                     }
                     // falls through
@@ -681,49 +586,92 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
         }
 
+        Variable accessedVariable = vexp.getAccessedVariable();
+        VariableExpression localVariableExpression = null;
         if (accessedVariable instanceof DynamicVariable) {
-            // a dynamic variable is either an undeclared variable
-            // or a member of a class used in a 'with'
-            DynamicVariable dyn = (DynamicVariable) accessedVariable;
-            // first, we must check the 'with' context
-            String dynName = dyn.getName();
-            if (tryVariableExpressionAsProperty(vexp, dynName)) return;
+            // a dynamic variable is either a class member used in a 'with' or an undeclared variable
+
+            if (tryVariableExpressionAsProperty(vexp, name)) return;
 
             if (!extension.handleUnresolvedVariableExpression(vexp)) {
-                addStaticTypeError("The variable [" + vexp.getName() + "] is undeclared.", vexp);
+                addStaticTypeError("The variable [" + name + "] is undeclared.", vexp);
             }
-        } else if (enclosingClosure == null) {
-            VariableExpression variable = null;
-            if (accessedVariable instanceof Parameter) {
-                variable = new ParameterVariableExpression((Parameter) accessedVariable);
-            } else if (accessedVariable instanceof VariableExpression) {
-                variable = (VariableExpression) accessedVariable;
-            }
-            if (variable != null) {
-                ClassNode inferredType = getInferredTypeFromTempInfo(variable, variable.getNodeMetaData(INFERRED_TYPE));
-                // instanceof applies, stash away the type, reusing key used elsewhere
-                if (inferredType != null && !inferredType.equals(OBJECT_TYPE)) {
-                    vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
+        } else if (accessedVariable instanceof FieldNode) {
+            if (enclosingClosure != null) {
+                tryVariableExpressionAsProperty(vexp, name);
+            } else {
+                // GROOVY-7691
+                FieldNode fieldNode = (FieldNode) accessedVariable;
+                ClassNode actualType = findActualTypeByGenericsPlaceholderName(
+                        fieldNode.getOriginType().getUnresolvedName(),
+                        makeDeclaringAndActualGenericsTypeMap(fieldNode.getDeclaringClass(), typeCheckingContext.getEnclosingClassNode())
+                );
+                if (actualType != null) {
+                    storeType(vexp, actualType);
+                }
+            }
+        } else if (accessedVariable instanceof PropertyNode) {
+            // we must be careful, because the property node may be of a wrong type:
+            // if a class contains a getter and a setter of different types or
+            // overloaded setters, the type of the property node is arbitrary!
+            if (tryVariableExpressionAsProperty(vexp, name)) {
+                BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
+                if (enclosingBinaryExpression != null) {
+                    Expression leftExpression = enclosingBinaryExpression.getLeftExpression();
+                    SetterInfo setterInfo = removeSetterInfo(leftExpression);
+                    if (setterInfo != null) {
+                        Expression rightExpression = enclosingBinaryExpression.getRightExpression();
+                        if (!ensureValidSetter(vexp, leftExpression, rightExpression, setterInfo)) {
+                            return;
+                        }
+                    }
                 }
             }
+        } else if (accessedVariable instanceof Parameter) {
+            if (enclosingClosure == null) {
+                localVariableExpression = new ParameterVariableExpression((Parameter) accessedVariable);
+            }
+        } else if (accessedVariable instanceof VariableExpression) {
+            if (enclosingClosure == null) {
+                localVariableExpression = (VariableExpression) accessedVariable;
+            }
+        }
+
+        if (localVariableExpression != null) {
+            ClassNode inferredType = localVariableExpression.getNodeMetaData(INFERRED_TYPE);
+            inferredType = getInferredTypeFromTempInfo(localVariableExpression, inferredType);
+            if (inferredType != null && !inferredType.equals(OBJECT_TYPE)) {
+                vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
+            }
         }
     }
 
+    private boolean storeTypeForSuper(final VariableExpression vexp) {
+        if (vexp == VariableExpression.SUPER_EXPRESSION) return true;
+        if (!vexp.isSuperExpression()) return false;
+        ClassNode superClassNode = typeCheckingContext.getEnclosingClassNode().getSuperClass();
+        storeType(vexp, makeType(superClassNode, typeCheckingContext.isInStaticContext));
+        return true;
+    }
+
+    private boolean storeTypeForThis(final VariableExpression vexp) {
+        if (vexp == VariableExpression.THIS_EXPRESSION) return true;
+        if (!vexp.isThisExpression()) return false;
+        ClassNode enclosingClassNode = typeCheckingContext.getEnclosingClassNode();
+        storeType(vexp, makeType(enclosingClassNode, typeCheckingContext.isInStaticContext));
+        return true;
+    }
+
     private boolean tryVariableExpressionAsProperty(final VariableExpression vexp, final String dynName) {
         PropertyExpression pexp = thisPropX(true, dynName);
         if (visitPropertyExpressionSilent(pexp, vexp)) {
-            ClassNode propertyType = getType(pexp);
-            pexp.removeNodeMetaData(INFERRED_TYPE);
-
             vexp.copyNodeMetaData(pexp.getObjectExpression());
-            Object val = pexp.getNodeMetaData(READONLY_PROPERTY);
-            if (val != null) vexp.putNodeMetaData(READONLY_PROPERTY, val);
-            val = pexp.getNodeMetaData(IMPLICIT_RECEIVER);
-            if (val != null) vexp.putNodeMetaData(IMPLICIT_RECEIVER, val);
-            val = pexp.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
-            if (val != null) vexp.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, val);
-
-            storeType(vexp, propertyType);
+            for (Object key : new Object[]{IMPLICIT_RECEIVER, READONLY_PROPERTY, PV_FIELDS_ACCESS, PV_FIELDS_MUTATION, DECLARATION_INFERRED_TYPE, DIRECT_METHOD_CALL_TARGET}) {
+                Object val = pexp.getNodeMetaData(key);
+                if (val != null) vexp.putNodeMetaData(key, val);
+            }
+            vexp.removeNodeMetaData(INFERRED_TYPE);
+            storeType(vexp, getType(pexp));
             return true;
         }
         return false;
@@ -3752,6 +3700,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         extension.onMethodSelection(call, directMethodCallCandidate);
     }
 
+    private void checkSuperCallFromClosure(final Expression call, final MethodNode directCallTarget) {
+        if (call instanceof MethodCallExpression && typeCheckingContext.getEnclosingClosure() != null) {
+            Expression objectExpression = ((MethodCallExpression) call).getObjectExpression();
+            if (isSuperExpression(objectExpression)) {
+                ClassNode current = typeCheckingContext.getEnclosingClassNode();
+                current.getNodeMetaData(SUPER_MOP_METHOD_REQUIRED, x -> new LinkedList<>()).add(directCallTarget);
+                call.putNodeMetaData(SUPER_MOP_METHOD_REQUIRED, current);
+            }
+        }
+    }
+
     protected boolean isClosureCall(final String name, final Expression objectExpression, final Expression arguments) {
         if (objectExpression instanceof ClosureExpression && ("call".equals(name) || "doCall".equals(name))) return true;
         if (isThisExpression(objectExpression)) {
@@ -4937,6 +4896,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     /**
+     * Wrap type in Class&lt;&gt; if usingClass==true.
+     */
+    private static ClassNode makeType(final ClassNode cn, final boolean usingClass) {
+        if (usingClass) {
+            ClassNode clazzType = CLASS_Type.getPlainNodeReference();
+            clazzType.setGenericsTypes(new GenericsType[]{new GenericsType(cn)});
+            return clazzType;
+        } else {
+            return cn;
+        }
+    }
+
+    /**
      * Stores the inferred return type of a closure or a method. We are using a separate key to store
      * inferred return type because the inferred type of a closure is {@link Closure}, which is different
      * from the inferred type of the code of the closure.