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