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 65b2f1b  Fixes for multiple issues with Bindings and Bindables. Closes 
#114
65b2f1b is described below

commit 65b2f1b9c3476ccb3b7b509b052025bd153504b4
Author: greg-dove <[email protected]>
AuthorDate: Tue Mar 3 10:44:02 2020 +1300

    Fixes for multiple issues with Bindings and Bindables. Closes #114
---
 .../internal/codegen/js/jx/AccessorEmitter.java    |  41 ++++----
 .../codegen/js/jx/MemberAccessEmitter.java         |  46 +++++++++
 .../codegen/mxml/royale/MXMLRoyaleEmitter.java     |   2 +-
 .../internal/as/codegen/BindableHelper.java        | 103 ++++++++++++++++++++-
 .../as/codegen/ClassDirectiveProcessor.java        |  80 ++++++++--------
 .../codegen/databinding/BindingCodeGenUtils.java   |  80 +++++++++++-----
 .../databinding/MXMLBindingDirectiveHelper.java    |   5 +-
 .../internal/definitions/DefinitionBase.java       |  20 ++--
 .../internal/definitions/VariableDefinition.java   |   9 ++
 .../internal/parsing/mxml/MXMLScopeBuilder.java    |   1 +
 .../compiler/internal/tree/as/VariableNode.java    |  16 +++-
 11 files changed, 302 insertions(+), 101 deletions(-)

diff --git 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
index 2b0ab7c..e5a5998 100644
--- 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
+++ 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
@@ -35,7 +35,7 @@ import 
org.apache.royale.compiler.definitions.IFunctionDefinition;
 import org.apache.royale.compiler.definitions.INamespaceDefinition;
 import org.apache.royale.compiler.definitions.IParameterDefinition;
 import org.apache.royale.compiler.definitions.ITypeDefinition;
-import org.apache.royale.compiler.definitions.metadata.IMetaTag;
+import org.apache.royale.compiler.internal.as.codegen.BindableHelper;
 import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
 import 
org.apache.royale.compiler.internal.codegen.js.JSSessionModel.PropertyNodes;
@@ -163,6 +163,8 @@ public class AccessorEmitter extends JSSubEmitter implements
                        }
                        if (setterNode != null)
                        {
+                                               boolean isClassBindable = 
BindableHelper.isClassCodeGenBindable(definition);
+
                                boolean isBindable = false;                
                                IAccessorDefinition setterDef = 
(IAccessorDefinition)setterNode.getDefinition();
                                IAccessorDefinition getterDef = null;
@@ -170,34 +172,25 @@ public class AccessorEmitter extends JSSubEmitter 
implements
                                        getterDef = 
(IAccessorDefinition)getterNode.getDefinition();
                                if ((getterDef != null && 
(setterDef.isBindable() || getterDef.isBindable())))
                                {
+                                                       boolean 
foundExplicitBindableTag = false;
                                        if (setterDef.isBindable())
                                        {
-                                               IMetaTag[] tags = 
setterDef.getMetaTagsByName("Bindable");
-                                               if (tags.length > 1)
-                                               isBindable = true;
-                                               else if (tags.length == 1)
-                                               {
-                                                       if 
(tags[0].getAllAttributes().length == 0)
-                                                               isBindable = 
true;
-                                               }
-                                               if (tags.length == 0 ) {
-                                                       isBindable = 
definition.isBindable();// if the class itself is marked as Bindable
-                                                               }
+
+                                                               isBindable = 
BindableHelper.isCodeGenBindableMember(setterDef, isClassBindable);
+                                                               
foundExplicitBindableTag = BindableHelper.hasExplicitBindable(setterDef);
                                        }
-                                       else if (getterDef.isBindable())
+                                       if (getterDef.isBindable())
                                        {
-                                               IMetaTag[] tags = 
getterDef.getMetaTagsByName("Bindable");
-                                               if (tags.length > 1)
-                                               isBindable = true;
-                                               else if (tags.length == 1)
-                                               {
-                                                       if 
(tags[0].getAllAttributes().length == 0)
-                                                               isBindable = 
true;
-                                               }
-                                                               if (tags.length 
== 0 ) {
-                                                                       
isBindable = definition.isBindable();// if the class itself is marked as 
Bindable
-                                                               }
+
+                                                               isBindable = 
isBindable || BindableHelper.isCodeGenBindableMember(getterDef, 
isClassBindable);
+                                                               
foundExplicitBindableTag = foundExplicitBindableTag || 
BindableHelper.hasExplicitBindable(getterDef);
+
                                        }
+
+                                                       if (isClassBindable) {
+                                                               //if we 
'foundExplicitBindableTag' such as [Bindable(event='someEvent')], then nothing 
else matters, even another [Bindable] tag is ignored (Flex)
+                                                               isBindable = 
!foundExplicitBindableTag;
+                                                       }
                                }
                            writeNewline();
                            writeNewline();
diff --git 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
index b4a8271..51d45b5 100644
--- 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
+++ 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
@@ -29,6 +29,7 @@ import org.apache.royale.compiler.definitions.*;
 import org.apache.royale.compiler.definitions.IDefinition;
 import org.apache.royale.compiler.definitions.INamespaceDefinition;
 import org.apache.royale.compiler.definitions.IPackageDefinition;
+import 
org.apache.royale.compiler.definitions.references.IResolvedQualifiersReference;
 import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
@@ -40,6 +41,7 @@ import 
org.apache.royale.compiler.internal.codegen.js.jx.BinaryOperatorEmitter.D
 import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
 import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
 import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.royale.compiler.internal.definitions.VariableDefinition;
 import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
 import org.apache.royale.compiler.internal.scopes.FunctionScope;
 import org.apache.royale.compiler.internal.semantics.SemanticUtils;
@@ -48,6 +50,7 @@ import org.apache.royale.compiler.projects.ICompilerProject;
 import org.apache.royale.compiler.tree.ASTNodeID;
 import org.apache.royale.compiler.tree.as.*;
 import org.apache.royale.compiler.tree.as.IOperatorNode.OperatorType;
+import org.apache.royale.compiler.tree.mxml.IMXMLSingleDataBindingNode;
 import org.apache.royale.compiler.utils.ASNodeUtils;
 
 import java.util.ArrayList;
@@ -428,6 +431,13 @@ public class MemberAccessEmitter extends JSSubEmitter 
implements
                                needClosure = !isStatic && parentNodeId != 
ASTNodeID.FunctionCallID &&
                                                        parentNodeId != 
ASTNodeID.MemberAccessExpressionID &&
                                                        parentNodeId != 
ASTNodeID.ArrayIndexExpressionID;
+
+                               //If binding getterFunctions ever need 
closures, this seems to be where it would be done (so far not needed, @todo 
review and remove this when certain)
+                               /*if (!needClosure && !isStatic && parentNodeId 
== ASTNodeID.FunctionCallID) {
+                                       if (node.getParent().getParent() 
instanceof IMXMLSingleDataBindingNode) {
+                                               needClosure = true;
+                                       }
+                               }*/
                
                                if (needClosure
                                                && getEmitter().getDocEmitter() 
instanceof JSRoyaleDocEmitter
@@ -458,6 +468,42 @@ public class MemberAccessEmitter extends JSSubEmitter 
implements
                 {
                     dynamicAccessUnknownMembers = 
fjsProject.config.getJsDynamicAccessUnknownMembers();
                 }
+                if (!dynamicAccessUnknownMembers) {
+                       //for <fx:Object declarations in mxml, we need to do 
this by default, because initialization values are set this way already, as are 
destination bindings, for example.
+                                       IIdentifierNode checkNode = null;
+                                       if (leftNode instanceof 
IIdentifierNode) {
+                                               //we might be dealing with the 
direct child member access of an fx:Object
+                                               checkNode = (IIdentifierNode) 
leftNode;
+                                       } else {
+                                               if (leftNode instanceof 
MemberAccessExpressionNode) {
+                                                       //if we are nested, 
check upwards for topmost Identifier node and verify that it is mxml variable 
of type Object, verifying that we are considered 'untyped' along the way
+                                                       
MemberAccessExpressionNode mae = (MemberAccessExpressionNode) leftNode;
+                                                       while (mae != null) {
+                                                               if 
(mae.getRightOperandNode().resolve(getProject()) == null) {
+                                                                       if 
(mae.getLeftOperandNode() instanceof IIdentifierNode) {
+                                                                               
checkNode = (IIdentifierNode) mae.getLeftOperandNode();
+                                                                               
break;
+                                                                       } else 
if (mae.getLeftOperandNode() instanceof MemberAccessExpressionNode) {
+                                                                               
mae = (MemberAccessExpressionNode) mae.getLeftOperandNode();
+                                                                       } else {
+                                                                               
mae = null;
+                                                                       }
+                                                               } else mae = 
null;
+                                                       }
+                                               }
+                                       }
+
+                                       if (checkNode != null &&
+                                                       
checkNode.resolve(getProject()) instanceof VariableDefinition) {
+                                               VariableDefinition varDef = 
((VariableDefinition) (checkNode.resolve(getProject())));
+                                               if (varDef.isMXMLDeclared()) {
+                                                       IDefinition type = 
varDef.resolveType(getProject());
+                                                       if (type instanceof 
IClassDefinition && 
type.equals(getProject().getBuiltinType(IASLanguageConstants.BuiltinType.OBJECT)))
 {
+                                                               
dynamicAccessUnknownMembers = true;
+                                                       }
+                                               }
+                                       }
+                               }
             }
                        if (dynamicAccessUnknownMembers && rightNode instanceof 
IIdentifierNode)
                        {
diff --git 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
index 7cd6d24..47162b7 100644
--- 
a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
+++ 
b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
@@ -2956,7 +2956,7 @@ public class MXMLRoyaleEmitter extends MXMLEmitter 
implements
        if (!makingSimpleArray)
        {
             MXMLDescriptorSpecifier ps = getCurrentDescriptor("ps");
-            if (ps.hasObject)
+            if (ps.hasObject || ps.parent == null) //('ps.parent == null' was 
added to allow a top level fx:Object definition, they were not being output 
without that)
             {
                emitInstance(node);
                return;
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
index 4bb45a7..299bb41 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
@@ -31,6 +31,8 @@ import org.apache.royale.abc.visitors.ITraitVisitor;
 import org.apache.royale.abc.visitors.ITraitsVisitor;
 import org.apache.royale.compiler.common.DependencyType;
 import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.definitions.IAccessorDefinition;
+import org.apache.royale.compiler.definitions.IClassDefinition;
 import org.apache.royale.compiler.definitions.IDefinition;
 import org.apache.royale.compiler.definitions.metadata.IMetaTag;
 import org.apache.royale.compiler.internal.abc.FunctionGeneratorHelper;
@@ -73,16 +75,115 @@ import static org.apache.royale.abc.ABCConstants.TRAIT_Var;
  */
 public class BindableHelper
 {
+
+    /**
+     * Check to see if a class definition is Bindable (for bindable code-gen)
+     * @param classDefinition the Class definition to check
+     * @return true if the definition has [Bindable]
+     */
+    public static boolean isClassCodeGenBindable(IClassDefinition 
classDefinition) {
+        IMetaTag[] metaTags = classDefinition.getAllMetaTags();
+        boolean isBindable = false;
+        for (IMetaTag metaTag : metaTags)
+        {
+            if (isCodeGenBindable(metaTag)) {
+                //if there is a single [Bindable] tag, then others are 
ignored, and the class is considered Bindable
+                isBindable = true;
+                break;
+            }
+        }
+        return isBindable;
+    }
+
     /**
      * Check to see if the metaTag is a codegen style [Bindable] tag (without 
any event names specified)
-     * @param metaTag
+     * @param memberDef the definition to check
+     * @param isClassBindable whether the containing class is [Bindable]
      * @return true if the tag is [Bindable]
      */
+    public static boolean isCodeGenBindableMember(IDefinition memberDef, 
boolean isClassBindable) {
+        boolean memberHasCodeGenBindable = false;
+        boolean memberHasExplicitBindable = false;
+        boolean resolved = false;
+        IMetaTag[] metaTags = memberDef.getAllMetaTags();
+        for (IMetaTag metaTag : metaTags)
+        {
+            if (!memberHasCodeGenBindable) {
+                memberHasCodeGenBindable = isCodeGenBindable(metaTag);
+                if (memberHasCodeGenBindable) continue;
+            }
+            if (!memberHasExplicitBindable) {
+                memberHasExplicitBindable = isExplicitBindable(metaTag);
+            }
+        }
+
+        if (isClassBindable) {
+            //if a getter/setter member has at least one explicit Bindable tag 
, then no code-gen is applied, even if it is also has a 'codegen' [Bindable] tag
+           if (memberDef instanceof IAccessorDefinition) {
+                resolved = !memberHasExplicitBindable;
+            } else {
+               //if it is a variable member, extra [Bindable] tags, including 
explicit Bindable(event='something') tags are ignored (at least for code-gen)
+               resolved = true; // @todo avoid checking at all in the above 
loop for this case
+           }
+        } else {
+            //in this case other explicit Bindable tags are ignored, a 
[Bindable] is sufficient @todo avoid checking for 'memberHasExplicitBindable' 
in the above loop for this case
+            resolved = memberHasCodeGenBindable;
+        }
+        return resolved;
+    }
+
+    public static boolean hasExplicitBindable(IDefinition definition) {
+       boolean hasExplicitBindableTag = false;
+       if (definition != null) {
+           IMetaTag[] metaTags = definition.getAllMetaTags();
+           for (IMetaTag metaTag : metaTags)
+           {
+               if (isExplicitBindable(metaTag)) {
+                   hasExplicitBindableTag = true;
+                   break;
+               }
+           }
+       }
+       return hasExplicitBindableTag;
+    }
+
+
+    public static boolean hasCodegenBindable(IDefinition definition) {
+        boolean hasCodegenBindableTag = false;
+        if (definition != null) {
+            IMetaTag[] metaTags = definition.getAllMetaTags();
+            for (IMetaTag metaTag : metaTags)
+            {
+                if (isCodeGenBindable(metaTag)) {
+                    hasCodegenBindableTag = true;
+                    break;
+                }
+            }
+        }
+        return hasCodegenBindableTag;
+    }
+
+    /**
+     * Check to see if the metaTag is a codegen style [Bindable] tag (without 
any event names specified)
+     * @param metaTag the MetaTag to check
+     * @return true if the MetaTag is [Bindable]
+     */
     public static boolean isCodeGenBindable(IMetaTag metaTag) {
         return metaTag != null
                 && metaTag.getTagName().equals(BINDABLE)
                 && metaTag.getAllAttributes().length == 0;
     }
+    /**
+     * Check to see if the metaTag is an explicit [Bindable] tag (with some 
attributes, such as event='someEvent' specified)
+     * @param metaTag the MetaTag to check
+     * @return true if the MetaTag is [Bindable('something')]
+     */
+    public static boolean isExplicitBindable(IMetaTag metaTag) {
+        return metaTag != null
+                && metaTag.getTagName().equals(BINDABLE)
+                && metaTag.getAllAttributes().length > 0;
+    }
+
 
     /**
      * A convenience method to get the next full node after all the Metadata 
tags, for when
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
index 82cfa05..2f45c11 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
@@ -744,7 +744,7 @@ class ClassDirectiveProcessor extends DirectiveProcessor
             if (!definition.isContingentNeeded(classScope.getProject()))
                 continue;
 
-            assert (definition instanceof VariableDefinition) : "The code 
generator only supports contigent variable definitions";
+            assert (definition instanceof VariableDefinition) : "The code 
generator only supports contingent variable definitions";
             
             final IDefinitionNode node = definition.getNode();
             declareVariable((VariableNode) node, 
(VariableDefinition)definition, definition.isStatic(),
@@ -779,46 +779,42 @@ class ClassDirectiveProcessor extends DirectiveProcessor
         ICompilerProject project = classScope.getProject();
         ASTUtil.processFunctionNode(func, project);
         boolean isBindable = false;
-
         if (funcDef instanceof AccessorDefinition)
         {
-            boolean isClassBindable = false;
-            IMetaTag[] metaTags = getClassDefinition().getAllMetaTags();
-            for (IMetaTag metaTag : metaTags)
-            {
-                if (BindableHelper.isCodeGenBindable(metaTag)) {
-                    isClassBindable = true;
-                    break;
-                }
-            }
+            boolean isClassBindable = 
BindableHelper.isClassCodeGenBindable(getClassDefinition());
+
             AccessorDefinition definitionWithBindable = null;
+            boolean foundExplicitBindableTag = false;
 
-            metaTags = funcDef.getAllMetaTags();
-            for (IMetaTag metaTag : metaTags)
-            {
-                if (BindableHelper.isCodeGenBindable(metaTag)) {
-                    isBindable = true;
-                    definitionWithBindable = (AccessorDefinition)funcDef;
-                    break;
-                }
+            isBindable = BindableHelper.isCodeGenBindableMember(funcDef, 
isClassBindable);
+            if (isBindable) {
+                definitionWithBindable = (AccessorDefinition) funcDef;
             }
+            foundExplicitBindableTag = 
BindableHelper.hasExplicitBindable(funcDef);
+
             AccessorDefinition otherDef =
                     
((AccessorDefinition)funcDef).resolveCorrespondingAccessor(classScope.getProject());
-            if (!isBindable)
+            if (!isBindable && !foundExplicitBindableTag)
             {
                 if (otherDef != null && 
otherDef.getContainingScope().equals(funcDef.getContainingScope()))
                 {
-                    metaTags = otherDef.getAllMetaTags();
-                    for (IMetaTag metaTag : metaTags)
-                    {
-                        if (BindableHelper.isCodeGenBindable(metaTag)) {
-                            isBindable = true;
-                            definitionWithBindable = otherDef;
-                            break;
-                        }
+                    isBindable = 
BindableHelper.isCodeGenBindableMember(otherDef, isClassBindable);
+                    if (isBindable) {
+                        definitionWithBindable = otherDef;
+                    }
+                    foundExplicitBindableTag = 
BindableHelper.hasExplicitBindable(otherDef);
+                    //if a) class is Bindable, and b)there is a [Bindable] 
tag, and c) there is also a [Bindable(eventName)] tag
+                    //then we can retain the [Bindable] codegen and reset 
foundExplicitBinding to false (assumption, check in flex)
+                    if (isClassBindable && isBindable && 
foundExplicitBindableTag) {
+                        foundExplicitBindableTag = false; //we will ignore it 
and keep codegen as well
                     }
                 }
             }
+            if (isBindable && otherDef == null) {
+                //no other definition
+                isBindable = false;
+                //warning if explicit [Bindable] ?
+            }
 
             if (isBindable
                     && otherDef instanceof ISetterDefinition
@@ -828,24 +824,32 @@ class ClassDirectiveProcessor extends DirectiveProcessor
                 classScope.addProblem(new 
BindableGetterCodeGenProblem((IGetterDefinition) funcDef));
             }
             if (isClassBindable) {
+                //add a warning if redundant local 'codegen' [Bindable] tag
+                if (BindableHelper.hasCodegenBindable(definitionWithBindable)) 
{
+                    classScope.addProblem(new RedundantBindableTagProblem(
+                            
BindableHelper.getProblemReportingNode(definitionWithBindable)
+                    ));
+                }
                 if (isBindable) {
-                    if (definitionWithBindable == funcDef) { //if we don't do 
this, we will end up with two reports
-                        classScope.addProblem(new RedundantBindableTagProblem(
-                                
BindableHelper.getProblemReportingNode(definitionWithBindable)
-                        ));
-                    }
-                } else {
-                    isBindable = true;
+                    if (!foundExplicitBindableTag && 
BindableHelper.hasExplicitBindable(otherDef)) foundExplicitBindableTag = true;
+                }
+                if (foundExplicitBindableTag) {
+                    //logic:
+                    //when class is [Bindable],
+                    //if either getter/setter member has at least one explicit 
Bindable tag (Bindable(event='something'))
+                    //then no code-gen is applied,
+                    //even if one of them also has a local 'codegen' 
[Bindable] tag
+                    isBindable = false;
                 }
             }
         }
-        
+
         functionSemanticChecks(func);
 
         Name funcName = funcDef.getMName(classScope.getProject());
         Name bindableName = null;
         boolean wasOverride = false;
-        //we only mutate the setter definitions, leave getters as-is
+        //from here on we are only interested in the setter definitions, leave 
getters as-is
         isBindable = isBindable && funcDef instanceof ISetterDefinition;
         if (isBindable)
         {
@@ -1471,7 +1475,7 @@ class ClassDirectiveProcessor extends DirectiveProcessor
                 this.cinitInsns.addAll(cgResult);
             else
                 this.iinitInsns.addAll(cgResult);
-            }
+        }
     }
     
     /**
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
index 250e351..b4c6614 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
@@ -37,14 +37,16 @@ import org.apache.royale.abc.visitors.IABCVisitor;
 import org.apache.royale.compiler.constants.IASLanguageConstants;
 import org.apache.royale.compiler.definitions.INamespaceDefinition;
 import org.apache.royale.compiler.internal.abc.FunctionGeneratorHelper;
+import org.apache.royale.compiler.internal.as.codegen.CmcEmitter;
 import org.apache.royale.compiler.internal.as.codegen.CodeGeneratorManager;
 import org.apache.royale.compiler.internal.as.codegen.LexicalScope;
 import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
 import org.apache.royale.compiler.internal.projects.RoyaleProject;
 import org.apache.royale.compiler.internal.scopes.ASScope;
-import org.apache.royale.compiler.internal.tree.as.LiteralNode;
+import org.apache.royale.compiler.internal.tree.as.*;
 import org.apache.royale.compiler.mxml.IMXMLTypeConstants;
 import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.tree.as.IASNode;
 import org.apache.royale.compiler.tree.as.IExpressionNode;
 
 /**
@@ -376,11 +378,12 @@ public class BindingCodeGenUtils
             String functionName,
             List<String> eventNames,
             List<BindingInfo> bindingInfo,
-            IExpressionNode[] params)
+            IExpressionNode[] params,
+            LexicalScope lexicalScope)
     {
         
         log(insns, "enter makeFunctionWatchercg");
-       
+
         Name watcherClassName = project.getFunctionReturnWatcherClassName();
         insns.addInstruction(OP_findpropstrict, watcherClassName);
         // stack: mx.binding.FunctionReturnWatcher
@@ -404,7 +407,7 @@ public class BindingCodeGenUtils
         // stack: this, functionName, watcher class
         
         // arg3: parameterFunction
-        makeParameterFunction(emitter, insns, params);
+        makeParameterFunction(emitter, insns, params, lexicalScope);
         
         // arg4: events
         boolean isStyle = makeEventNameArray(insns, eventNames);
@@ -450,7 +453,7 @@ public class BindingCodeGenUtils
     
     // version 2: just throw
     
-    public static void makeParameterFunction(IABCVisitor emitter, 
InstructionList ret, IExpressionNode[] params)
+    public static void makeParameterFunction(IABCVisitor emitter, 
InstructionList ret, IExpressionNode[] params, LexicalScope lexicalScope)
     {
        
         //----------- step 1: build up a method info for the function
@@ -471,26 +474,53 @@ public class BindingCodeGenUtils
            
         parameterFunctionBody.addInstruction(OP_getlocal0);
         parameterFunctionBody.addInstruction(OP_pushscope);
-        
-        if (params.length == 1 && params[0] instanceof LiteralNode)
-        {
-            parameterFunctionBody.addInstruction(OP_pushstring, 
((LiteralNode)params[0]).getValue());
-            
-            parameterFunctionBody.addInstruction(OP_newarray, 1);
-            parameterFunctionBody.addInstruction(OP_returnvalue);            
-        }
-        else
-        {
-            parameterFunctionBody.addInstruction(OP_findpropstrict, 
IMXMLTypeConstants.NAME_ARGUMENTERROR);
-    
-            // Make a new ArugmentError with correct ID
-            parameterFunctionBody.addInstruction(OP_pushstring, "unimp param 
func");
-            parameterFunctionBody.pushNumericConstant(1069);
-            parameterFunctionBody.addInstruction(OP_constructprop,  
-                    new Object[] {  IMXMLTypeConstants.NAME_ARGUMENTERROR, 2 
});     
-            // stack : ArgumentError
-               
-            parameterFunctionBody.addInstruction(OP_throw);   
+
+        if (params.length == 0) {
+            //it is a function call with no params
+            parameterFunctionBody.addInstruction(OP_newarray, 0);
+            parameterFunctionBody.addInstruction(OP_returnvalue);
+        } else {
+
+            //create a temporary ArrayLiteralNode
+            ArrayLiteralNode arrayLit = new ArrayLiteralNode();
+
+            for (IASNode param: params) {
+                ContainerNode parent = (ContainerNode)param.getParent();
+                //make the array literal think it has the param as a child
+                arrayLit.getContentsNode().addItem((NodeBase)param);
+                //(tricky) now reset the parent of the param, avoid errors 
with ASScope access during traversal,
+                //we only really want the downward traversal from the 
ArrayLiteralNode as the root, we don't want any sense
+                //that it is *actually* a parent, because it is not ASScope 
aware.
+                ((NodeBase) param).setParent(parent);
+                if (arrayLit.getSourcePath()==null) {
+                    //give the synthetic node a location to avoid an error 
elsewhere
+                    //setting the source path here will prevent an assertion 
failure in a future call to SemanticUtils.getFileName(iNode) if
+                    //asserts are enabled for the compiler runtime (at the 
time of writing, ant was and maven was not)
+                    arrayLit.setSourceLocation(param);
+                } else {
+                   arrayLit.endAfter(param);
+                }
+            }
+
+            //generate the instruction list for the Arrayliteral
+            InstructionList list = 
lexicalScope.getGenerator().generateInstructions(arrayLit, 
CmcEmitter.__array_literal_NT, lexicalScope);
+            if (list != null && !list.isEmpty()) {
+                //output the array literal and return it
+                parameterFunctionBody.addAll(list);
+                parameterFunctionBody.addInstruction(OP_returnvalue);
+            } else {
+                //sanity check, this is the original legacy fail approach 
@todo review this, hopefully it can be removed if it never happens in practice
+                parameterFunctionBody.addInstruction(OP_findpropstrict, 
IMXMLTypeConstants.NAME_ARGUMENTERROR);
+
+                // Make a new ArugmentError with correct ID
+                parameterFunctionBody.addInstruction(OP_pushstring, "unimp 
param func");
+                parameterFunctionBody.pushNumericConstant(1069);
+                parameterFunctionBody.addInstruction(OP_constructprop,
+                        new Object[] {  IMXMLTypeConstants.NAME_ARGUMENTERROR, 
2 });
+                // stack : ArgumentError
+
+                parameterFunctionBody.addInstruction(OP_throw);
+            }
         }
         
         // now generate the function
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
index 7ea4cc4..a5a2fe6 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
@@ -288,7 +288,7 @@ public class MXMLBindingDirectiveHelper
            
             ret.addInstruction(OP_pushstring, 
functionWatcherInfo.getFunctionName());
             InstructionList paramFunction = new InstructionList();
-            BindingCodeGenUtils.makeParameterFunction(emitter, paramFunction, 
functionWatcherInfo.params);
+            BindingCodeGenUtils.makeParameterFunction(emitter, paramFunction, 
functionWatcherInfo.params, host.getInstanceScope());
             ret.addAll(paramFunction);
             outputEventNames(ret, functionWatcherInfo.getEventNames());
             outputBindings(ret, functionWatcherInfo.getBindings());
@@ -916,7 +916,8 @@ public class MXMLBindingDirectiveHelper
                     functionWatcherInfo.getFunctionName(),
                     functionWatcherInfo.getEventNames(),
                     functionWatcherInfo.getBindings(),
-                    functionWatcherInfo.params);
+                    functionWatcherInfo.params,
+                    host.getInstanceScope());
         }
         else if ((type == WatcherType.STATIC_PROPERTY) || (type == 
WatcherType.PROPERTY))
         {
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
index 41da6b2..c822686 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
@@ -1348,17 +1348,23 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
         boolean bindable = isBindableLocally();
         if (!bindable)
         {
-            IDefinition containing = getParent();
-            if (containing instanceof IClassDefinition
-                    && this.getNamespaceReference() == 
NamespaceDefinition.getPublicNamespaceDefinition())
-            {
-                DefinitionBase containingBase = (DefinitionBase)containing;
-                bindable = containingBase.isBindableLocally();
-            }
+           bindable = isClassBindable();
         }
         return bindable;
     }
 
+    public boolean isClassBindable() {
+        boolean classBindable = false;
+        IDefinition containing = getParent();
+        if (containing instanceof IClassDefinition
+                && this.getNamespaceReference() == 
NamespaceDefinition.getPublicNamespaceDefinition())
+        {
+            DefinitionBase containingBase = (DefinitionBase)containing;
+            classBindable = containingBase.isBindableLocally();
+        }
+        return classBindable;
+    }
+
     /**
      * @return a collection of Bindable event names, if any were specified in
      * the metadata, as well as any inherited from the class
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
index a465894..2f8a1e9 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
@@ -136,6 +136,15 @@ public class VariableDefinition extends DefinitionBase 
implements IVariableDefin
         return dt;
     }
 
+    private boolean mxmlDeclared = false;
+    public void setMxmlDeclared(){
+        mxmlDeclared = true;
+    }
+
+    public boolean isMXMLDeclared() {
+        return mxmlDeclared;
+    }
+
     @Override
     public IVariableNode getNode()
     {
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
index a2af339..74b308d 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
@@ -772,6 +772,7 @@ public class MXMLScopeBuilder
         variableDefinition.setTypeReference(typeRef);
         variableDefinition.setNameLocation(idAttribute.getValueStart(), 
idAttribute.getValueEnd());
         variableDefinition.setBindable();
+        variableDefinition.setMxmlDeclared();
         currentClassScope.addDefinition(variableDefinition);
     }
     
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
index 8deb160..23c8ed4 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
@@ -27,6 +27,7 @@ import org.apache.royale.compiler.common.ASImportTarget;
 import org.apache.royale.compiler.common.IImportTarget;
 import org.apache.royale.compiler.definitions.IDefinition;
 import 
org.apache.royale.compiler.definitions.IVariableDefinition.VariableClassification;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
 import org.apache.royale.compiler.tree.ASTNodeID;
 import org.apache.royale.compiler.tree.as.IASNode;
 import org.apache.royale.compiler.tree.as.ICommonClassNode;
@@ -76,14 +77,23 @@ public class VariableNode extends BaseVariableNode
     {
         ASTNodeID nodeID = ASTNodeID.VariableID;
 
-        IDefinition varDef = this.getDefinition();
+        DefinitionBase varDef = this.getDefinition();
         if (varDef != null && varDef.isBindable())
         {
             // Bindable vars with a user-specified event class work the same 
as normal variables
             // the user is responsible for dispatching the event.
-            List<String> eventNames = varDef.getBindableEventNames();
-            if (eventNames.size() == 0)
+
+            //note: the above statement was inconsistent with Flex if the 
class itself is also marked [Bindable]
+            //in that case, binding is related to both codegen events and the 
specified event.
+            if (varDef.isClassBindable()) {
+                //we know that isBindable() must be because of the class 
[Bindable], regardless of any specific eventNames
                 nodeID = ASTNodeID.BindableVariableID;
+            } else {
+                //as original, only consider to be [Bindable] if eventNames is 
empty:
+                List<String> eventNames = varDef.getBindableEventNames();
+                if (eventNames.size() == 0)
+                    nodeID = ASTNodeID.BindableVariableID;
+            }
         }
 
         return nodeID;

Reply via email to