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

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git


The following commit(s) were added to refs/heads/develop by this push:
     new 03264a5  Fix for additional issue raised in comments of #185, closes 
#185 a) Fix for Proxy based coercion in for-each loop targets ('as' coercions 
and Class-with-parentheses coercions) additional fixes: b) Fix for function 
call Proxy return types (simple identifier calls or member access expression 
calls) c) Fix for possible null reference in the Proxy-typed iteration target
03264a5 is described below

commit 03264a5d1575bad28090b3468495004f3d0a0a7c
Author: greg-dove <[email protected]>
AuthorDate: Fri Jun 18 14:57:32 2021 +1200

    Fix for additional issue raised in comments of #185, closes #185
    a) Fix for Proxy based coercion in for-each loop targets ('as' coercions 
and Class-with-parentheses coercions)
    additional fixes:
    b) Fix for function call Proxy return types (simple identifier calls or 
member access expression calls)
    c) Fix for possible null reference in the Proxy-typed iteration target
---
 .../codegen/js/jx/BinaryOperatorEmitter.java       |  1 +
 .../internal/codegen/js/jx/ForEachEmitter.java     | 69 ++++++++++++++++++++--
 .../codegen/js/royale/TestRoyaleGlobalClasses.java |  2 +-
 3 files changed, 65 insertions(+), 7 deletions(-)

diff --git 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
index 02c7f49..e5a1ab2 100644
--- 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
+++ 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
@@ -610,6 +610,7 @@ public class BinaryOperatorEmitter extends JSSubEmitter 
implements
                                else if (node.getNodeID() == ASTNodeID.Op_InID 
&&
                                                
((JSRoyaleEmitter)getEmitter()).isProxy(node.getRightOperandNode()))
                                {
+                                       //@todo: add loop target null safety 
(see changes in ForEachEmitter)
                                        write(".propertyNames()");
                                }
                        }
diff --git 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
index 46fc13a..071a481 100644
--- 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
+++ 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ForEachEmitter.java
@@ -22,17 +22,18 @@ package org.apache.royale.compiler.internal.codegen.js.jx;
 import org.apache.royale.compiler.codegen.ISubEmitter;
 import org.apache.royale.compiler.codegen.js.IJSEmitter;
 import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.definitions.IClassDefinition;
 import org.apache.royale.compiler.definitions.IDefinition;
 import org.apache.royale.compiler.definitions.IFunctionDefinition;
 import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
 import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
 import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
+import org.apache.royale.compiler.internal.projects.RoyaleProject;
 import org.apache.royale.compiler.internal.semantics.SemanticUtils;
 import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
 import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
 import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
 import org.apache.royale.compiler.scopes.IDefinitionSet;
 import org.apache.royale.compiler.tree.ASTNodeID;
 import org.apache.royale.compiler.tree.as.*;
@@ -111,7 +112,7 @@ public class ForEachEmitter extends JSSubEmitter implements
                }
             if (((JSRoyaleEmitter)getEmitter()).isProxy((IdentifierNode)obj))
             {
-                write(".propertyNames()");
+                emitNullSafeProxyTarget(targetName);
                 isProxy = true;
             }
         }
@@ -133,7 +134,7 @@ public class ForEachEmitter extends JSSubEmitter implements
             }
             if 
(((JSRoyaleEmitter)getEmitter()).isProxy((IMemberAccessExpressionNode)obj))
             {
-                write(".propertyNames()");
+                emitNullSafeProxyTarget(targetName);
                 isProxy = true;
             }
         }
@@ -147,7 +148,17 @@ public class ForEachEmitter extends JSSubEmitter implements
                        {
                     write(".elementNames()");
                     isXML = true;
-                       }
+                       } else {
+                    IClassDefinition asTarget = (IClassDefinition) 
((IdentifierNode) asChild).resolve(getProject());
+                    if (asTarget != null) {
+                        //check ancestry for proxy
+                        RoyaleProject project = (RoyaleProject) getProject();
+                        if (asTarget.isInstanceOf(project.getProxyBaseClass(), 
project)){
+                            emitNullSafeProxyTarget(targetName);
+                            isProxy = true;
+                        }
+                    }
+                }
                }
         }
         else if (obj.getNodeID() == ASTNodeID.FunctionCallID)
@@ -161,7 +172,23 @@ public class ForEachEmitter extends JSSubEmitter implements
                        {
                     write(".elementNames()");
                     isXML = true;
-                       }                       
+                       } else {
+                           IDefinition funcNameDef = 
funcName.resolve(getProject());
+                    //if it is IClassDefinition, then it is a type cast, 
otherwise...
+                           if (funcNameDef instanceof IFunctionDefinition) {
+                        //then it is a regular function call, so check the 
return type, and use that for the IClassDefinition type check:
+                        funcNameDef = 
((IFunctionDefinition)funcNameDef).resolveReturnType(getProject());
+                    }
+                           if (funcNameDef instanceof IClassDefinition) {
+                               //this is a a hard cast
+                        //check ancestry for proxy
+                        RoyaleProject project = (RoyaleProject) getProject();
+                        if (((IClassDefinition) 
funcNameDef).isInstanceOf(project.getProxyBaseClass(), project)){
+                            emitNullSafeProxyTarget(targetName);
+                            isProxy = true;
+                        }
+                    }
+                }
                } else if (funcName instanceof IMemberAccessExpressionNode) {
                 IFunctionDefinition funcDef = (IFunctionDefinition) 
((IMemberAccessExpressionNode) 
funcName).getRightOperandNode().resolve(getProject());
                 if (funcDef == null) {
@@ -196,7 +223,16 @@ public class ForEachEmitter extends JSSubEmitter implements
                     // It is probably rare and ill-advised, but it definitely 
won't work well in javascript currently for those classes, for example.
 
                 } else {
-                    isXML = 
SemanticUtils.isXMLish(funcDef.resolveReturnType(getProject()), getProject());
+                    IClassDefinition returnType = (IClassDefinition) 
funcDef.resolveReturnType(getProject());
+                    isXML = SemanticUtils.isXMLish(returnType, getProject());
+                    if (!isXML) {
+                        //check for Proxy
+                        RoyaleProject project = (RoyaleProject) getProject();
+                        if 
(returnType.isInstanceOf(project.getProxyBaseClass(), project)){
+                            emitNullSafeProxyTarget(targetName);
+                            isProxy = true;
+                        }
+                    }
                 }
                 if (isXML) {
                     write(".elementNames()");
@@ -260,4 +296,25 @@ public class ForEachEmitter extends JSSubEmitter implements
         writeNewline();
     }
 
+    void emitNullSafeProxyTarget(String targetName) {
+        //output the null-safe target expression:
+        // for something:Object in targetName && targetName.propertyNames()
+        write(ASEmitterTokens.SPACE);
+        writeToken(ASEmitterTokens.LOGICAL_AND);
+        write(targetName);
+        write(".propertyNames()");
+    }
+
+    //@todo, check XML also at some point, maybe switch to the following
+    /*
+    void emitNullSafeXMLishTarget(String targetName) {
+        //output the null-safe target expression:
+        // for something:Object in targetName && targetName.propertyNames()
+        write(ASEmitterTokens.SPACE);
+        writeToken(ASEmitterTokens.LOGICAL_AND);
+        write(targetName);
+        write(".elementNames()");
+    }
+    */
+
 }
diff --git 
a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
 
b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
index c045348..d93c34e 100644
--- 
a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
+++ 
b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
@@ -1565,7 +1565,7 @@ public class TestRoyaleGlobalClasses extends 
TestGoogGlobalClasses
                 "import custom.TestProxy; public class B {public function b() 
{ var a:TestProxy = new TestProxy();for each (var p:String in a) var i:int = 
p.length; }}",
                 IForLoopNode.class, WRAP_LEVEL_PACKAGE, true);
         asBlockWalker.visitForLoop(node);
-        assertOut("var foreachiter0_target = a;\nfor (var foreachiter0 in 
foreachiter0_target.propertyNames()) \n{\nvar p = 
foreachiter0_target.getProperty(foreachiter0);\n\n  var /** @type {number} */ i 
= (p.length) >> 0;}\n");
+        assertOut("var foreachiter0_target = a;\nfor (var foreachiter0 in 
foreachiter0_target && foreachiter0_target.propertyNames()) \n{\nvar p = 
foreachiter0_target.getProperty(foreachiter0);\n\n  var /** @type {number} */ i 
= (p.length) >> 0;}\n");
     }
     
     @Test

Reply via email to