/* * * 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.as; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import org.apache.flex.compiler.common.ASImportTarget; import org.apache.flex.compiler.common.ASModifier; import org.apache.flex.compiler.common.IImportTarget; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.definitions.references.IReference; import org.apache.flex.compiler.definitions.references.ReferenceFactory; import org.apache.flex.compiler.internal.definitions.FunctionDefinition; import org.apache.flex.compiler.internal.definitions.InterfaceDefinition; import org.apache.flex.compiler.internal.definitions.NamespaceDefinition; import org.apache.flex.compiler.internal.scopes.ASScope; import org.apache.flex.compiler.internal.scopes.TypeScope; import org.apache.flex.compiler.internal.semantics.PostProcessStep; import org.apache.flex.compiler.parsing.IASToken; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.as.IExpressionNode; import org.apache.flex.compiler.tree.as.IIdentifierNode; import org.apache.flex.compiler.tree.as.IInterfaceNode; /** * ActionScript parse tree node representing an interface definition */ public class InterfaceNode extends MemberedNode implements IInterfaceNode { /** * Constructor. * * @param name The node holding the interface name. */ public InterfaceNode(ExpressionNodeBase name) { init(name); } /** * The class keyword */ protected KeywordNode interfaceKeywordNode; /** * The extends keyword (if one is present) */ protected KeywordNode extendsKeywordNode; /** * The collection of base interfaces */ protected TransparentContainerNode baseInterfacesNode; /** * Generated FunctionNode to represent cast function */ protected FunctionNode castFunctionNode; // // NodeBase overrides // @Override public ASTNodeID getNodeID() { return ASTNodeID.InterfaceID; } @Override public int getSpanningStart() { return getNodeStartForTooling(); } @Override protected void setChildren(boolean fillInOffsets) { addDecorationChildren(fillInOffsets); addChildInOrder(interfaceKeywordNode, fillInOffsets); addChildInOrder(nameNode, fillInOffsets); addChildInOrder(extendsKeywordNode, fillInOffsets); addChildInOrder(contentsNode, fillInOffsets); if (extendsKeywordNode != null || baseInterfacesNode.getChildCount() > 0) addChildInOrder(baseInterfacesNode, fillInOffsets); } @Override protected void analyze(EnumSet<PostProcessStep> set, ASScope scope, Collection<ICompilerProblem> problems) { if (set.contains(PostProcessStep.POPULATE_SCOPE)) { InterfaceDefinition definition = buildDefinition(); setDefinition(definition); scope.addDefinition(definition); TypeScope typeScope = new TypeScope(scope, contentsNode, definition); definition.setContainedScope(typeScope); scope = typeScope; setupCastFunction(set, definition, scope); } if (set.contains(PostProcessStep.RECONNECT_DEFINITIONS)) { reconnectDef(scope); scope = this.getDefinition().getContainedScope(); contentsNode.reconnectScope(scope); } // Recurse on the interface block. contentsNode.analyze(set, scope, problems); } /* * For debugging only. Builds a string such as <code>"IFoo"</code> from the * name of the interface being defined. */ @Override protected boolean buildInnerString(StringBuilder sb) { sb.append('"'); sb.append(getName()); sb.append('"'); return true; } // // TreeNode overrides // @Override protected int getInitialChildCount() { return 2; } // // BaseDefinitionNode overrides // @Override protected void init(ExpressionNodeBase nameNode) { super.init(nameNode); extendsKeywordNode = null; baseInterfacesNode = new TransparentContainerNode(); castFunctionNode = null; } @Override public boolean hasModifier(ASModifier modifier) { return false; } @Override public InterfaceDefinition getDefinition() { return (InterfaceDefinition)super.getDefinition(); } @Override protected void setDefinition(IDefinition definition) { assert definition instanceof InterfaceDefinition; super.setDefinition(definition); } // // IInterfaceNode implementations // @Override public boolean isImplicit() { return false; } @Override public String getQualifiedName() { IImportTarget importTarget = ASImportTarget.buildImportFromPackageName(getWorkspace(), getPackageName()); String qualifiedName = importTarget.getQualifiedName(getName()); if (qualifiedName == null) return getShortName(); return qualifiedName; } @Override public String getShortName() { String name = getName(); int lastDot = name.lastIndexOf("."); if (lastDot != -1) name = name.substring(lastDot + 1); return name; } @Override public InterfaceClassification getInterfaceClassification() { if (getParent() instanceof FileNode) return InterfaceClassification.INNER_INTERFACE; return InterfaceClassification.PACKAGE_MEMBER; } @Override public IExpressionNode[] getExtendedInterfaceNodes() { ArrayList<IExpressionNode> interfaceNodeList = new ArrayList<IExpressionNode>(); int childCount = baseInterfacesNode.getChildCount(); if (baseInterfacesNode != null && childCount > 0) { for (int i = 0; i < childCount; i++) { IASNode child = baseInterfacesNode.getChild(i); if (child instanceof IIdentifierNode) { interfaceNodeList.add(((IIdentifierNode)child)); } } } return interfaceNodeList.toArray(new IExpressionNode[0]); } @Override public String[] getExtendedInterfaces() { ArrayList<String> interfaceNodeList = new ArrayList<String>(); int childCount = baseInterfacesNode.getChildCount(); if (baseInterfacesNode != null && childCount > 0) { for (int i = 0; i < childCount; i++) { IASNode child = baseInterfacesNode.getChild(i); if (child instanceof IIdentifierNode) { interfaceNodeList.add(((IIdentifierNode)child).getName()); } } } return interfaceNodeList.toArray(new String[0]); } // // Other methods // /** * Sets the interface keyword. Used during parsing. * * @param interfaceKeyword token containing the keyword */ public void setInterfaceKeyword(IASToken interfaceKeyword) { interfaceKeywordNode = new KeywordNode(interfaceKeyword); } /** * Get the node containing the class keyword * * @return the node containing class */ public KeywordNode getClassKeywordNode() { return interfaceKeywordNode; } /** * Get the node containing the extends keyword, if one exists * * @return the node containing extends */ public KeywordNode getExtendsKeywordNode() { return extendsKeywordNode; } /** * Sets the extends keyword if one is present. Used during parsing. * * @param extendsKeyword token containing the keyword */ public void setExtendsKeyword(IASToken extendsKeyword) { extendsKeywordNode = new KeywordNode(extendsKeyword); } /** * Add an implemented interface to this class. Used during parsing. * * @param interfaceName node containing the interface name */ public void addBaseInterface(ExpressionNodeBase interfaceName) { baseInterfacesNode.addChild(interfaceName); } /** * Get the container of base interfaces for this interfaces * * @return the node containing the base interfaces */ public ContainerNode getBaseInterfacesNode() { return baseInterfacesNode; } private void setupCastFunction(EnumSet<PostProcessStep> set, InterfaceDefinition def, ASScope scope) { // Unlike ClassNode, InterfaceNode doesn't create implicit definitions // for "this" or "super" for interfaces; but it does create an implicit // function that helps us resolve casting expressions such as IFoo(foo). FunctionDefinition castFunc = new FunctionDefinition(getName()); castFunc.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace()); castFunc.setReturnTypeReference(ReferenceFactory.resolvedReference(def)); castFunc.setCastFunction(); castFunc.setImplicit(); // Add this definition to the interface scope. scope.addDefinition(castFunc); } /** * Get the dummy node representing the cast function * * @return cast function */ public FunctionNode getCastFunctionNode() { return castFunctionNode; } InterfaceDefinition buildDefinition() { String definitionName = nameNode.computeSimpleReference(); InterfaceDefinition definition = new InterfaceDefinition(definitionName); definition.setNode(this); fillInNamespaceAndModifiers(definition); fillInMetadata(definition); // Set the interfaces that this interface extends. if (baseInterfacesNode != null) { int n = baseInterfacesNode.getChildCount(); IReference[] baseInterfaces = new IReference[n]; for (int i = 0; i < n; i++) { IASNode child = baseInterfacesNode.getChild(i); if (child instanceof ExpressionNodeBase) baseInterfaces[i] = ((ExpressionNodeBase)child).computeTypeReference(); } definition.setExtendedInterfaceReferences(baseInterfaces); } return definition; } }