/* * * 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 org.apache.flex.compiler.internal.tree.mxml; import org.apache.flex.compiler.definitions.IClassDefinition; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.internal.scopes.MXMLFileScope; import org.apache.flex.compiler.internal.scopes.TypeScope; import org.apache.flex.compiler.internal.tree.as.NodeBase; import org.apache.flex.compiler.mxml.IMXMLTagAttributeData; import org.apache.flex.compiler.mxml.IMXMLTagData; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.problems.MXMLSemanticProblem; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.mxml.IMXMLClassDefinitionNode; import org.apache.flex.compiler.tree.mxml.IMXMLComponentNode; import static org.apache.flex.compiler.mxml.IMXMLLanguageConstants.*; class MXMLComponentNode extends MXMLFactoryNode implements IMXMLComponentNode { /** * Constructor * * @param parent The parent node of this node, or <code>null</code> if there * is no parent. */ MXMLComponentNode(NodeBase parent) { super(parent); } /** * The name of the class as specified by the <code>className</code> * attribute. This may be <code>null</code>. */ private String className; /** * The class-defining node which is the sole child of this node. */ private MXMLClassDefinitionNode containedClassDefinitionNode; @Override public ASTNodeID getNodeID() { return ASTNodeID.MXMLComponentID; } @Override public String getName() { IClassDefinition classDefinition = getContainedClassDefinition(); // The classDefinition can be null when Component tag is partially written // i.e., with no component inside it // e.g. <fx:Component></fx:Component> return classDefinition != null ? classDefinition.getBaseName() : ""; } @Override public int getChildCount() { return containedClassDefinitionNode != null ? 1 : 0; } @Override public IASNode getChild(int i) { return i == 0 ? containedClassDefinitionNode : null; } @Override protected void processTagSpecificAttribute(MXMLTreeBuilder builder, IMXMLTagData tag, IMXMLTagAttributeData attribute, MXMLNodeInfo info) { if (attribute.isSpecialAttribute(ATTRIBUTE_CLASS_NAME)) { if (className == null) { // TODO Check that the class name is a valid AS identifier // and doesn't have conflicts with other names. String rawValue = attribute.getRawValue(); if (rawValue != null) className = attribute.getMXMLDialect().trim(rawValue); } } else { super.processTagSpecificAttribute(builder, tag, attribute, info); } } @Override protected void processChildTag(MXMLTreeBuilder builder, IMXMLTagData tag, IMXMLTagData childTag, MXMLNodeInfo info) { boolean handled = false; if (containedClassDefinitionNode == null) { containedClassDefinitionNode = new MXMLClassDefinitionNode(this); handled = true; // check also that there is only one child tag and that // there are no text units around the child tag FlexProject project = builder.getProject(); IDefinition tagDef = builder.getFileScope().resolveTagToDefinition(childTag); // Check that the root tag mapped to a definition. if (tagDef == null) { // TODO Add a problem subclass for this. ICompilerProblem problem = new MXMLSemanticProblem(childTag); builder.addProblem(problem); } // Check that the definition is for a class. if (!(tagDef instanceof IClassDefinition)) { // TODO Add a problem subclass for this. ICompilerProblem problem = new MXMLSemanticProblem(childTag); builder.addProblem(problem); } IClassDefinition tagDefinition = (IClassDefinition)tagDef; // Check that the class is not final. if (tagDefinition.isFinal()) { // TODO Add a problem subclass for this. ICompilerProblem problem = new MXMLSemanticProblem(childTag); builder.addProblem(problem); } // Find the ClassDefinition that was created for the component class. MXMLFileScope fileScope = builder.getFileScope(); ClassDefinition fxComponentClassDefinition = fileScope.getClassDefinitionForComponentTag(tag); assert fxComponentClassDefinition != null : "MXMLScopeBuilder failed to build a class for an fx:Component"; // attach scope with the component class definition node. TypeScope componentClassScope = (TypeScope)fxComponentClassDefinition.getContainedScope(); containedClassDefinitionNode.setScope(componentClassScope); // TODO Move this logic to initializeFromTag(). // Connect node to definitions and vice versa. containedClassDefinitionNode.setClassReference(project, tagDefinition); // TODO Move this logic to initializeFromTag(). containedClassDefinitionNode.setClassDefinition(fxComponentClassDefinition); // TODO Move this logic to initializeFromTag(). int nameStart = fxComponentClassDefinition.getNameStart(); int nameEnd = fxComponentClassDefinition.getNameEnd(); fxComponentClassDefinition.setNode(containedClassDefinitionNode); // TODO The above call is setting nameStart and nameEnd to -1 // because the MXML class definition node doesn't have a name expression node. // We need to reset the correct nameStart and nameEnd. fxComponentClassDefinition.setNameLocation(nameStart, nameEnd); containedClassDefinitionNode.initializeFromTag(builder, childTag); } if (!handled) { super.processChildTag(builder, tag, childTag, info); } } @Override public String getClassName() { return className; } @Override public IMXMLClassDefinitionNode getContainedClassDefinitionNode() { return containedClassDefinitionNode; } @Override public IClassDefinition getContainedClassDefinition() { return containedClassDefinitionNode != null ? containedClassDefinitionNode.getClassDefinition() : null; } }