Package flex2.compiler.as3

Source Code of flex2.compiler.as3.SyntaxTreeEvaluator$RemoteClassRequiresAlias

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package flex2.compiler.as3;

import flash.swf.tools.as3.EvaluatorAdapter;
import flex2.compiler.CompilationUnit;
import flex2.compiler.CompilerContext;
import flex2.compiler.Source;
import flex2.compiler.SymbolTable;
import flex2.compiler.as3.binding.ClassInfo;
import flex2.compiler.as3.binding.TypeAnalyzer;
import flex2.compiler.as3.reflect.MetaData;
import flex2.compiler.as3.reflect.NodeMagic;
import flex2.compiler.io.FileUtil;
import flex2.compiler.mxml.lang.FrameworkDefs;
import flex2.compiler.mxml.lang.StandardDefs;
import flex2.compiler.mxml.rep.VariableDeclaration;
import flex2.compiler.util.CompilerMessage;
import flex2.compiler.util.NameFormatter;
import flex2.compiler.util.ThreadLocalToolkit;
import macromedia.asc.parser.*;
import macromedia.asc.semantics.Value;
import macromedia.asc.util.Context;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashSet;

/*
* TODO validate metadata syntax here
* TODO names to constants
*/
/**
* This class handles processing and validating Flex specific metadata.
*
* @author Clement Wong
*/
public class SyntaxTreeEvaluator extends EvaluatorAdapter
{
    public SyntaxTreeEvaluator(CompilationUnit unit)
    {
        this.unit = unit;
        this.standardDefs = unit.getStandardDefs();
    }

    private final CompilationUnit unit;
    private final StandardDefs standardDefs;

  //  traversal state
    private String currentClassName = "";
    private ClassDefinitionNode currentClassNode = null;
//    private ProgramNode currentProgramNode = null;
    private PackageDefinitionNode lastPackageNode = null;
    private boolean seenConstructor = false;
    private Map<String, FunctionDefinitionNode> functionMap;

    public Value evaluate(Context cx, PackageDefinitionNode node)
    {
        if (lastPackageNode == node)
            lastPackageNode = null;
        else
            lastPackageNode = null;
        return super.evaluate(cx, node);
    }

    /**
     * init current classname and seen-constructor state, for multiple-constructor test
     */
    public Value evaluate(Context cx, ClassDefinitionNode node)
    {
        ClassDefinitionNode prev = currentClassNode;
        try
        {
            assert currentClassName.equals("") : "nested classdef in SyntaxTreeEvaluator (outer='" + currentClassName + "')";
            currentClassName = NodeMagic.getUnqualifiedClassName(node);
            currentClassNode = node;
            seenConstructor = false;
            functionMap = new HashMap<String, FunctionDefinitionNode>();

            super.evaluate(cx, node);
        }
        finally
        {
            currentClassNode = prev;
            currentClassName = "";
            seenConstructor = false;
            functionMap = null;
        }

        return null;
    }

    private FunctionDefinitionNode cur_func = null;

    /**
     * check for presence of multiple constructor definitions. Happens if constructor has been defined in <Script/>
     * CAUTION: this logic depends on the ordering of generated and <Script/> code in the InterfaceDef.vm -
     * script is assumed to *follow* generated code (or at least, the generated constructor). If that ordering
     * changes, <strong>this must be modified accordingly (save early location, etc.)</strong>.
     */
    public Value evaluate(Context cx, FunctionDefinitionNode node)
    {
        FunctionDefinitionNode old = cur_func;
        cur_func = node;
        super.evaluate(cx, node);
        cur_func = old;

        if (NodeMagic.getFunctionName(node).equals(currentClassName))
        {
            if (seenConstructor)
            {
                cx.localizedError2(
                        cx.input.origin,
                        node.pos(),
                        new MultipleConstructorDefs());

            }
            else
            {
                seenConstructor = true;
            }
        }
        else
        {
            String functionName = NodeMagic.getFunctionName(node);
            if ((functionMap != null) && (functionName != null))
            {
                switch (node.name.kind)
                {
                case Tokens.GET_TOKEN:
                    FunctionDefinitionNode setter = functionMap.get(functionName);
                    if (setter != null)
                    {
                        processAccessorMetaData(cx, node, setter);
                    }
                    else
                    {
                        functionMap.put(functionName, node);
                    }
                    break;
                case Tokens.SET_TOKEN:
                    FunctionDefinitionNode getter = functionMap.get(functionName);
                    if (getter != null)
                    {
                        processAccessorMetaData(cx, getter, node);
                    }
                    else
                    {
                        functionMap.put(functionName, node);
                    }
                    break;
                default:
                    break;
                }
            }
        }

        return null;
    }

    public Value evaluate(Context cx, IncludeDirectiveNode node)
    {
        super.evaluate(cx, node);

        unit.getSource().addFileInclude(FileUtil.getCanonicalPath(node.filespec.value));

        return null;
    }

    public Value evaluate(Context cx, MetaDataNode node)
    {
        if (node.data != null)
        {
            macromedia.asc.parser.MetaDataEvaluator mde = new macromedia.asc.parser.MetaDataEvaluator();
            node.evaluate(cx, mde);
        }

        unit.metadata.add(node);

        if (NodeMagic.isClassDefinition(node))
        {
            if (StandardDefs.MD_RESOURCEBUNDLE.equals(node.getId()))
            {
                processResourceBundle(cx, node, true);
            }
            else if (StandardDefs.MD_SWF.equals(node.getId()))
            {
                unit.swfMetaData = new MetaData(node);
            }
            else if (StandardDefs.MD_FRAME.equals(node.getId()))
            {
                processFrameMetaData(node);
            }
            else if (StandardDefs.MD_ACCESSIBILITYCLASS.equals(node.getId()))
            {
                processAccessibilityClassMetaData(cx, node);
            }
            else if (StandardDefs.MD_REMOTECLASS.equals(node.getId()))
            {
                processRemoteClassMetaData(cx, node);
            }
            else if (StandardDefs.MD_REQUIRESLICENSE.equals(node.getId()))
            {
                processLicenseMetaData(cx, node);
            }
            else if (StandardDefs.MD_MIXIN.equals(node.getId()))
            {
                unit.mixins.add( NodeMagic.retrieveClassName( node ) );
            }
            else if (StandardDefs.MD_ICONFILE.equals(node.getId()))
            {
                processIconFileMetaData(cx, node);
            }
            else if (StandardDefs.MD_EVENT.equals(node.getId()))
            {
                processEventMetaData(node);
            }
            else if (StandardDefs.MD_EFFECT.equals(node.getId()))
            {
                processEffectTriggerMetaData(node);
            }
            else if (StandardDefs.MD_HOSTCOMPONENT.equals(node.getId()))
            {
                processHostComponentMetaData(cx, node);
            }
            else if (StandardDefs.MD_SKINSTATE.equals(node.getId()))
            {
                processSkinStateMetaData(cx, node);
            }
        }
        else
        {
            if (StandardDefs.MD_RESOURCEBUNDLE.equals(node.getId()))
            {
                processResourceBundle(cx, node, false);
            }
            else if (StandardDefs.MD_ARRAYELEMENTTYPE.equals(node.getId()))
            {
                processArrayElementTypeMetaData(cx, node);
            }
            else if (StandardDefs.MD_INSTANCETYPE.equals(node.getId()))
            {
                processInstanceTypeMetaData(cx, node);
            }
            else if (StandardDefs.MD_PERCENTPROXY.equals(node.getId()))
            {
                processPercentProxyMetaData(cx, node);
            }
            else if (StandardDefs.MD_SKINPART.equals(node.getId()))
            {
                processSkinPartMetaData(cx, node);
            }
        }

        return null;
    }

    private boolean isFlexMetaData(String metaData)
    {
        boolean result = false;

        if (metaData.equals(StandardDefs.MD_ACCESSIBILITYCLASS) ||
            metaData.equals(StandardDefs.MD_ARRAYELEMENTTYPE) ||
            metaData.equals(StandardDefs.MD_BINDABLE) ||
            metaData.equals(StandardDefs.MD_CHANGEEVENT) ||
            metaData.equals(StandardDefs.MD_COLLAPSEWHITESPACE) ||
            metaData.equals(StandardDefs.MD_DEFAULTPROPERTY) ||
            metaData.equals(StandardDefs.MD_DEPRECATED) ||
            metaData.equals(StandardDefs.MD_EFFECT) ||
            metaData.equals(StandardDefs.MD_EMBED) ||
            metaData.equals(StandardDefs.MD_EVENT) ||
            metaData.equals(StandardDefs.MD_FRAME) ||
            metaData.equals(StandardDefs.MD_HOSTCOMPONENT) ||
            metaData.equals(StandardDefs.MD_ICONFILE) ||
            metaData.equals(StandardDefs.MD_INSPECTABLE) ||
            metaData.equals(StandardDefs.MD_INSTANCETYPE) ||
            metaData.equals(StandardDefs.MD_MANAGED) ||
            metaData.equals(StandardDefs.MD_MIXIN) ||
            metaData.equals(StandardDefs.MD_NONCOMMITTINGCHANGEEVENT) ||
            metaData.equals(StandardDefs.MD_PERCENTPROXY) ||
            metaData.equals(StandardDefs.MD_REQUIRESLICENSE) ||
            metaData.equals(StandardDefs.MD_REMOTECLASS) ||
            metaData.equals(StandardDefs.MD_RESOURCEBUNDLE) ||
            metaData.equals(StandardDefs.MD_STYLE) ||
            metaData.equals(StandardDefs.MD_SWF) ||
            metaData.equals(StandardDefs.MD_TRANSIENT))
        {
            result = true;
        }

        return result;
    }

    private void processAccessorMetaData(Context cx, FunctionDefinitionNode getter,
                                         FunctionDefinitionNode setter)
    {
        List getterMetaDataList = NodeMagic.getMetaData(getter);
        List setterMetaDataList = NodeMagic.getMetaData(setter);

        Iterator getterMetaDataIterator = getterMetaDataList.iterator();

        while ( getterMetaDataIterator.hasNext() )
        {
            MetaDataNode getterMetaDataNode = (MetaDataNode) getterMetaDataIterator.next();
            if (! (getterMetaDataNode instanceof DocCommentNode))
            {
                Iterator setterMetaDataIterator = setterMetaDataList.iterator();
                while ( setterMetaDataIterator.hasNext() )
                {
          //  NOTE: MetaDataNode gives no way of iterating over name/value param pairs,
          //  so we have no way to determine whether param lists are or aren't equal.
          //  Since there are many legal cases of multiple metadata names (e.g. ChangeEvent, etc.)
          //  all we can really test, in the absence of a way of getting at the complete
          //   param list, is 0-arg metadata.
                    MetaDataNode setterMetaDataNode = (MetaDataNode) setterMetaDataIterator.next();
                    if (! (setterMetaDataNode instanceof DocCommentNode))
                    {
                        if (getterMetaDataNode.getId().equals(setterMetaDataNode.getId()) &&
                                isFlexMetaData(setterMetaDataNode.getId()) &&
                                getterMetaDataNode.count() == 0 && setterMetaDataNode.count() == 0)
                        {
                            String functionName = NodeMagic.getFunctionName(setter);
                            // Change this to an error once mx/rpc/soap/mxml/WebService removes
                            // the duplicate Deprecated metadata on serviceName.
                            cx.localizedWarning2(setterMetaDataNode.pos(),
                                    new DuplicateMetaData(currentClassName,
                                            functionName,
                                            setterMetaDataNode.getId()));
                        }
                }
            }
            }
        }
    }

    /**
     *
     */
    private void processInstanceTypeMetaData(Context cx, MetaDataNode node)
    {
        if (node.count() == 1)
        {
            unit.expressions.add(NameFormatter.toMultiName(node.getValue(0)));
        }
        else
        {
            cx.localizedError2(cx.input.origin, node.pos(), new InstanceTypeMustHaveType());
        }
    }

    private void processResourceBundle(Context context, MetaDataNode node, boolean onClass)
    {
        if (node.count() ==  0)
        {
            context.localizedError2(node.pos(), new RBEmptyMetadata());
        }
        else
        {
            final String name = node.getValue(0);
            // add the ResourceBundle name to the CU list so we can add it to the SWF later
            unit.resourceBundleHistory.add(name);

            if (onClass)
            {
                // e.g. [ResourceBundle(...)] public clas Foo ...
                // nothing else to do
            }
            else
            {
                // e.g. [ResourceBundle(...)] var foo
                Node def = node.def;
                if (def instanceof VariableDefinitionNode)
                {
                    if( cur_func != null )
                    {
                        // A local variable likely will not get turned into a trait, so hoist the metadata to the
                        // enclosing function so that it still appears in the abc
                        cur_func.addMetaDataNode(node);
                    }
                    VariableDefinitionNode varDefinition = (VariableDefinitionNode) def;
   
                    // We look to see if the variable is directly assigned a value.  If not, then
                    // we construct the nodes to assign it to "ResourceBundle.getResourceBundle(name)".
                    // We don't complain if the variable is already assigned a value, as this will
                    // happen if the metadata is coming from a SWC (or the user could just be doing
                    // something crazy).
                    if ((varDefinition.list != null) &&
                        (varDefinition.list.items != null) &&
                        (varDefinition.list.items.size() > 0))
                    {
                        Object item = varDefinition.list.items.get(0);
                        if (item instanceof VariableBindingNode)
                        {
                            VariableBindingNode variableBinding = (VariableBindingNode) item;
                            if (variableBinding.initializer == null)
                            {
                                context.localizedWarning2(context.input.origin, node.pos(),
                                                          new VariableLevelResourceBundleMetaDataDeprecated());

                                String type = NodeMagic.lookupType( variableBinding );
                                // FIXME: only checking for ResourceBundle here, not mx.resources.ResourceBundle.
                                // Not sure how to check for the full name, since lookupType() returns the short name
                                // and getVariableTypeName() only returns exactly what is in the code, without
                                // regards to imports
                                // Jono: I don't think it's possible at this time (?), we'd have to
                                // be able to resolve short names with imports, might be too early?
                                if (type == null || ! type.equals("ResourceBundle"))
                                {
                                    context.localizedError2(context.input.origin, node.pos(), new NotResourceBundleType());
                                }
   
                                IdentifierNode idNode = new IdentifierNode("ResourceBundle", 0);
                                GetExpressionNode getNode = new GetExpressionNode(idNode);
                                getNode.setPosition(0);
                                MemberExpressionNode memberNode = new MemberExpressionNode(null, getNode, 0);
   
                                LiteralStringNode litNode = new LiteralStringNode(name);
                                litNode.setPosition(0);
                                ArgumentListNode argNode = new ArgumentListNode(litNode, 0);
                                MemberExpressionNode ad = new MemberExpressionNode(new MemberExpressionNode( null, new GetExpressionNode( new IdentifierNode("ApplicationDomain", 0) ), 0),
                                                                                   new GetExpressionNode( new IdentifierNode( "currentDomain", 0 )), 0);
                                argNode.items.push_back( ad );
                                IdentifierNode idNode3 = new IdentifierNode("getResourceBundle", 0);
                                CallExpressionNode callNode = new CallExpressionNode(idNode3, argNode);
   
                                variableBinding.initializer = new MemberExpressionNode(memberNode, callNode, 0);
                                NodeMagic.addImport( context, currentClassNode, NameFormatter.toDot(standardDefs.CLASS_APPLICATIONDOMAIN));
                            }
                        }
                    }
                }
                // if it's on a function, assume this is the metadata that we hoisted up
                else if (! (def instanceof FunctionDefinitionNode))
                {
                    // we need ResourceBundle metadata to be on a variable
                    context.localizedError2(node.pos(), new RBOnlyOnVars());
                }
            }
        }
    }

    /**
     *
     */
    private void processArrayElementTypeMetaData(Context cx, MetaDataNode node)
    {
        if (node.count() == 1)
        {
            unit.expressions.add(NameFormatter.toMultiName(node.getValue(0)));
        }
        else
        {
            cx.localizedError2(cx.input.origin, node.pos(), new ArrayElementTypeMustHaveType());
        }
    }

    /**
     *
     */
    private void processPercentProxyMetaData(Context cx, MetaDataNode node)
    {
        if (node.count() != 1)
        {
            cx.localizedError2(cx.input.origin, node.pos(), new PercentProxyMustHaveProperty());
        }
    }

    /**
     *
     */
    private void processEventMetaData(MetaDataNode node)
    {
        String typeName = node.getValue("type");
        if (typeName != null)
        {
            unit.expressions.add(NameFormatter.toMultiName(typeName));
        }
    }

    /**
     *
     */
    private void processIconFileMetaData(Context cx, MetaDataNode node)
    {
        String icon = node.getValue(0);

        if (icon != null)
        {
            if (unit.icon == null)
            {
                unit.icon = icon;
            }
            else if (!unit.icon.equals(icon))
            {
                cx.localizedError2(cx.input.origin, node.pos(),
                                   new DuplicateIconFileMetadata(unit.icon, icon,
                                                                 unit.getSource().getNameForReporting()));
            }
           
            if (unit.iconFile == null)
            {
                unit.iconFile = unit.getSource().resolve(icon);

                // It's not an error if iconFile is null, because it
                // might be available in the SWC.  We check for this
                // in Swc.addIcons().
            }
        }
    }

    /**
     *
     */
    private void processLicenseMetaData(Context cx, MetaDataNode node)
    {
        String className = NodeMagic.retrieveClassName( node );
        String packageName = (className.indexOf( ':' ) == -1)? null : className.substring( 0, className.indexOf( ':' ) );
        String id = node.getValue( "id" );
        if (id == null)
        {
            if (packageName != null)
                id = packageName;
            else
                id = className;
        }
        String handler = node.getValue( "handler" );
        if (handler == null)
        {
            if (packageName != null)
                handler = packageName + ".LicenseHandler";
            else
                handler = id + "LicenseHandler";
        }
        unit.licensedClassReqs.put( id, NodeMagic.normalizeClassName( handler ) );
    }

    /**
     *
     */
    private void processRemoteClassMetaData(Context cx, MetaDataNode node)
    {
        String className = NodeMagic.retrieveClassName( node );
        String alias = node.getValue( "alias" );
        if (alias == null)
        {
      alias = ">" + className;  // Magic, apparently.  See bug 159983.
        }
        unit.remoteClassAliases.put( className, alias );
    }

    /**
     *
     */
    private void processFrameMetaData(MetaDataNode node)
    {
        // Note: internal form of these values is package:classname
        if (node.getValue( "factoryClass" ) != null)
        {
            unit.loaderClass = NodeMagic.normalizeClassName( node.getValue( "factoryClass" ) );
        }
        if (node.getValue( "extraClass" ) != null )
        {
            unit.extraClasses.add( NodeMagic.normalizeClassName( node.getValue( "extraClass" ) ) );
        }
    }

    private void processEffectTriggerMetaData(MetaDataNode node)
    {
        String triggerName = node.getValue( "name" );
        if (triggerName == null)
        {
            triggerName = node.getValue(0);
        }

        String event = node.getValue( "event" );

        if (event == null)
        {
            event = "";
        }

        unit.effectTriggers.put(triggerName, event);
    }

    private void processAccessibilityClassMetaData(Context cx, MetaDataNode node)
    {  
        if (node.getValue( "implementation" ) != null)
        {
            unit.addAccessibilityClass(new MetaData(node));
        }
        else
        {
            cx.localizedError2(cx.input.origin, node.pos(), new AccessibilityClassMustHaveType());
        }
    }
   
    private void processHostComponentMetaData(Context cx, MetaDataNode node)
    {
        if (node.count() == 1)
        {
            if (unit.hostComponentMetaData == null)
            {
                unit.expressions.add(NameFormatter.toMultiName(node.getValue(0)));
               
                // Here we save a reference to our HostComponent metadata as well
                // as its owning class, because later at the time we validate our
                // host component contract (CompilerExtension.generate()), node.def
                // might not be valid.
                unit.hostComponentMetaData = node;
                if (node.def != null)
                  unit.hostComponentOwnerClass =  NodeMagic.getClassName((ClassDefinitionNode) node.def);
            }
            else
            {
                cx.localizedError2(cx.input.origin, node.pos(), new OnlyOneHostComponentAllowed());
            }
        }
        else
        {
            cx.localizedError2(cx.input.origin, node.pos(), new HostComponentMustHaveType());
        }
    }

    private void processSkinPartMetaData(Context cx, MetaDataNode node)
    {
        if ((node.def.attrs == null) ||
            !node.def.attrs.hasPublic &&
            !NodeMagic.getAttributes(node.def).contains(NodeMagic.PUBLIC) &&
            !NodeMagic.getAttributes(node.def).contains(SymbolTable.publicNamespace))
        {
            String origin = null;

            if (cx.input != null)
            {
                origin = cx.input.origin;
            }

            cx.localizedError2(origin, node.def.pos(), new SkinPartsMustBePublic());
        }
    }
   
    private void processSkinStateMetaData(Context cx, MetaDataNode node)
    {
        if (unit.skinStates == null)
        {
          unit.skinStates = new HashSet<String>();
        }
       
        // Ensure someone hasn't inadvertently duplicated SkinState metadata.
        String stateName = node.getValue(0);
        if (stateName != null)
        {
          if (!unit.skinStates.add(stateName))
          {
            cx.localizedError2(node.pos(), new DuplicateSkinState(stateName));
          }           
        }
    }
 
    /**
     * do this after parsing. the purpose is to remove method bodies and rhs of var so as to speed up compilation.
     */
    public static void removeNonAPIContent(CompilationUnit ascUnit)
    {
    //  NOTE: only attempt what follows if everything is a-ok
        if (ThreadLocalToolkit.errorCount() > 0)
        {
            return;
        }

        ClassDefinitionNode clsdef = getFirstClassDefinition((ProgramNode) ascUnit.getSyntaxTree());
        assert clsdef != null : "could not find a class definition node...";

        CompilerContext context = ascUnit.getContext();
        Context cx = context.getAscContext();

        for (int i = 0, size = (clsdef != null && clsdef.statements != null && clsdef.statements.items != null) ? clsdef.statements.items.size() : 0; i < size; i++)
        {
            Object node = clsdef.statements.items.get(i);

            if (node instanceof FunctionDefinitionNode)
            {
                FunctionDefinitionNode function = (FunctionDefinitionNode) node;

                if (function.fexpr != null && function.fexpr.body != null &&
                    function.fexpr.body.items != null)
                {
                    // C: assume that the last node is always the synthetic ReturnStatementNode.
                    NodeFactory nodeFactory = cx.getNodeFactory();
                    function.fexpr.body = nodeFactory.statementList(null, function.fexpr.body.items.removeLast());

                    if (function.fexpr.signature != null && function.fexpr.signature.result != null)
                    {
                        function.fexpr.body.items.add(0, nodeFactory.list(null, nodeFactory.returnStatement(nodeFactory.literalNull())));
                    }
                }
            }
            else if (node instanceof VariableDefinitionNode)
            {
                VariableDefinitionNode var = (VariableDefinitionNode) node;

                for (int k = 0, len = var.list.items.size(); k < len; k++)
                {
                    VariableBindingNode binding = (VariableBindingNode) var.list.items.get(k);
                    // Const vars may need their initializers if they are used where
                    // a compile time constant is required, such as in a parameter initializer
                    // for an optional function param.
                    if( binding.kind != Tokens.CONST_TOKEN )
                        binding.initializer = null;
                }
            }
        }
    }

    /**
     * return the first ClassDefinitionNode
     */
    private static ClassDefinitionNode getFirstClassDefinition(ProgramNode program)
    {
        for (int i = 0, size = (program != null && program.statements != null && program.statements.items != null) ? program.statements.items.size() : 0; i < size; i++)
        {
            Object node = program.statements.items.get(i);

            if (node instanceof ClassDefinitionNode)
            {
                return (ClassDefinitionNode) node;
            }
        }

        return null;
    }

    public static void ensureMetaDataHasDefinition(CompilationUnit compilationUnit)
    {
        ProgramNode programNode = (ProgramNode) compilationUnit.getSyntaxTree();
        CompilerContext context = compilationUnit.getContext();
        Context cx = context.getAscContext();
        MetaDataEvaluator metaDataEvaluator = new MetaDataEvaluator();
        programNode.evaluate(cx, metaDataEvaluator);
    }

    /**
     * Make sure binding variables only occur once in any
     * generated class's superclass chain.  This is accomplished by assuming they are not
     * in the superclass chain.  See InterfaceDef.vm.  This is the most common case.  The
     * rare case will be that they are already are defined.  In this case, we go into the
     * syntax tree and pluck out the unnecessary variables.
     */
    public static void stripRedeclaredManagementVars(CompilationUnit ascUnit, String className, SymbolTable symbolTable)
    {
    //  NOTE: only attempt what follows if everything is a-ok
        if (ThreadLocalToolkit.errorCount() > 0)
        {
            return;
        }

        ProgramNode program = (ProgramNode) ascUnit.getSyntaxTree();
        ClassDefinitionNode classDefinitionNode = getFirstClassDefinition(program);
        assert classDefinitionNode != null : "could not find a class definition node...";

        CompilerContext context = ascUnit.getContext();
        Context cx = context.getAscContext();

        TypeAnalyzer typeAnalyzer = symbolTable.getTypeAnalyzer();

        program.evaluate(cx, typeAnalyzer);

        ClassInfo classInfo = typeAnalyzer.getClassInfo(className);

        // If classInfo is null, then errors should be reported downstream.
        if (classInfo != null)
        {
            ClassInfo baseClassInfo = classInfo.getBaseClassInfo();

            if (baseClassInfo != null && !FrameworkDefs.bindingManagementVars.isEmpty())
            {
                // NOTE: take the presence of first var to imply the presence of the entire set
                if (baseClassInfo.definesVariable((FrameworkDefs.bindingManagementVars.get(0)).getName()))
                {
                    removeVariables(classDefinitionNode, FrameworkDefs.bindingManagementVars);
                }
            }
        }
    }

    /**
     * remove definitions of any variables whose names are found in the passed VariableDeclaration array.
     * Note: ignores type and qualifiers. Only names have to match.
     */
    private static void removeVariables(ClassDefinitionNode classDefinition, List variableDeclarations)
    {
        Iterator iterator = classDefinition.statements.items.iterator();

        while ( iterator.hasNext() )
        {
            Object node = iterator.next();

            if (node instanceof VariableDefinitionNode)
            {
                VariableDefinitionNode variableDefinition = (VariableDefinitionNode) node;

                if ((variableDefinition.list != null) &&
                    (variableDefinition.list.items != null) &&
                    (variableDefinition.list.items.size() == 1))
                {
                    Object variableNode = variableDefinition.list.items.get(0);

                    if (variableNode instanceof VariableBindingNode)
                    {
                        VariableBindingNode variableBindingNode = (VariableBindingNode) variableNode;

                        String name = variableBindingNode.variable.identifier.name;

                        for (Iterator varDeclIter = variableDeclarations.iterator(); varDeclIter.hasNext(); )
                        {
                            if (name.equals(((VariableDeclaration)varDeclIter.next()).getName()))
                            {
                                iterator.remove();
                            }
                        }
                    }
                }
            }
        }
    }

    // error messages

    public static class DuplicateIconFileMetadata extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 1091141392400511452L;
        public DuplicateIconFileMetadata(String icon, String val, String sourceName)
        {
            super();
            this.icon = icon;
            this.val = val;
            this.sourceName = sourceName;
        }

        public final String icon;
        public final String val;
        public final String sourceName;
    }

    public static class DuplicateMetaData extends CompilerMessage.CompilerWarning
    {
        private static final long serialVersionUID = -8603582432515358134L;
        public String declaringClass;
        public String setter;
        public String metaData;

        public DuplicateMetaData(String declaringClass, String setter, String metaData)
        {
            this.declaringClass = declaringClass;
            this.setter = setter;
            this.metaData = metaData;
        }
    }
   
    public static class DuplicateSkinState extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -8603582234515358134L;
        public String name;

        public DuplicateSkinState(String name)
        {
            this.name = name;
        }
    }

    public static class NotResourceBundleType extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 1230443452465285417L;
    }

    public static class RemoteClassRequiresAlias extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -1068806137611429285L;
    }

    public static class AccessibilityClassMustHaveType extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -8834434215232392864L;
    }
   
    public static class ArrayElementTypeMustHaveType extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -8834434214722392864L;
    }
   
    public static class HostComponentMustHaveType extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -8834434137722392864L;
    }

    public static class InstanceTypeMustHaveType extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -3077472527217768870L;
    }

    public static class OnlyOneHostComponentAllowed extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -8834434137722392865L;
    }

    public static class PercentProxyMustHaveProperty extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -5187666526248931183L;
    }

    public static class MultipleConstructorDefs extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 2475353328071972520L;
    }

    public static class RBOnlyOnVars extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 8017070971699999050L;
    }

    public static class RBEmptyMetadata extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 5290330001936137663L;
    }

    public static class SkinPartsMustBePublic extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 5290330001936137666L;
    }

    public static class VariableLevelResourceBundleMetaDataDeprecated
        extends CompilerMessage.CompilerWarning
    {
    }
}
TOP

Related Classes of flex2.compiler.as3.SyntaxTreeEvaluator$RemoteClassRequiresAlias

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.