/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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 com.google.dart.engine.internal.element.member; import com.google.dart.engine.element.ConstructorElement; import com.google.dart.engine.element.Element; import com.google.dart.engine.element.ElementVisitor; import com.google.dart.engine.element.FieldFormalParameterElement; import com.google.dart.engine.element.MethodElement; import com.google.dart.engine.element.ParameterElement; import com.google.dart.engine.element.PropertyAccessorElement; import com.google.dart.engine.internal.type.TypeParameterTypeImpl; import com.google.dart.engine.type.InterfaceType; import com.google.dart.engine.type.ParameterizedType; import com.google.dart.engine.type.Type; import com.google.dart.engine.utilities.dart.ParameterKind; import com.google.dart.engine.utilities.source.SourceRange; /** * Instances of the class {@code ParameterMember} represent a parameter element defined in a * parameterized type where the values of the type parameters are known. */ public class ParameterMember extends VariableMember implements ParameterElement { /** * If the given parameter's type is different when any type parameters from the defining type's * declaration are replaced with the actual type arguments from the defining type, create a * parameter member representing the given parameter. Return the member that was created, or the * base parameter if no member was created. * * @param baseParameter the base parameter for which a member might be created * @param definingType the type defining the parameters and arguments to be used in the * substitution * @return the parameter element that will return the correctly substituted types */ public static ParameterElement from(ParameterElement baseParameter, ParameterizedType definingType) { if (baseParameter == null || definingType.getTypeArguments().length == 0) { return baseParameter; } // Check if parameter type depends on defining type type arguments. // It is possible that we did not resolve field formal parameter yet, so skip this check for it. boolean isFieldFormal = baseParameter instanceof FieldFormalParameterElement; if (!isFieldFormal) { Type baseType = baseParameter.getType(); Type[] argumentTypes = definingType.getTypeArguments(); Type[] parameterTypes = TypeParameterTypeImpl.getTypes(definingType.getTypeParameters()); Type substitutedType = baseType.substitute(argumentTypes, parameterTypes); if (baseType.equals(substitutedType)) { return baseParameter; } } // TODO(brianwilkerson) Consider caching the substituted type in the instance. It would use more // memory but speed up some operations. We need to see how often the type is being re-computed. if (isFieldFormal) { return new FieldFormalParameterMember( (FieldFormalParameterElement) baseParameter, definingType); } return new ParameterMember(baseParameter, definingType); } /** * Initialize a newly created element to represent a parameter of the given parameterized type. * * @param baseElement the element on which the parameterized element was created * @param definingType the type in which the element is defined */ public ParameterMember(ParameterElement baseElement, ParameterizedType definingType) { super(baseElement, definingType); } @Override public <R> R accept(ElementVisitor<R> visitor) { return visitor.visitParameterElement(this); } @Override @SuppressWarnings("unchecked") public <E extends Element> E getAncestor(Class<E> elementClass) { E element = getBaseElement().getAncestor(elementClass); ParameterizedType definingType = getDefiningType(); if (definingType instanceof InterfaceType) { InterfaceType definingInterfaceType = (InterfaceType) definingType; if (element instanceof ConstructorElement) { return (E) ConstructorMember.from((ConstructorElement) element, definingInterfaceType); } else if (element instanceof MethodElement) { return (E) MethodMember.from((MethodElement) element, definingInterfaceType); } else if (element instanceof PropertyAccessorElement) { return (E) PropertyAccessorMember.from( (PropertyAccessorElement) element, definingInterfaceType); } } return element; } @Override public ParameterElement getBaseElement() { return (ParameterElement) super.getBaseElement(); } @Override public String getDefaultValueCode() { return getBaseElement().getDefaultValueCode(); } @Override public Element getEnclosingElement() { return getBaseElement().getEnclosingElement(); } @Override public ParameterKind getParameterKind() { return getBaseElement().getParameterKind(); } @Override public ParameterElement[] getParameters() { ParameterElement[] baseParameters = getBaseElement().getParameters(); int parameterCount = baseParameters.length; if (parameterCount == 0) { return baseParameters; } ParameterElement[] parameterizedParameters = new ParameterElement[parameterCount]; for (int i = 0; i < parameterCount; i++) { parameterizedParameters[i] = ParameterMember.from(baseParameters[i], getDefiningType()); } return parameterizedParameters; } @Override public SourceRange getVisibleRange() { return getBaseElement().getVisibleRange(); } @Override public boolean isInitializingFormal() { return getBaseElement().isInitializingFormal(); } @Override public String toString() { ParameterElement baseElement = getBaseElement(); String left = ""; String right = ""; switch (baseElement.getParameterKind()) { case NAMED: left = "{"; right = "}"; break; case POSITIONAL: left = "["; right = "]"; break; case REQUIRED: // No need to change the default. break; } StringBuilder builder = new StringBuilder(); builder.append(left); builder.append(getType()); builder.append(" "); builder.append(baseElement.getDisplayName()); builder.append(right); return builder.toString(); } @Override public void visitChildren(ElementVisitor<?> visitor) { super.visitChildren(visitor); safelyVisitChildren(getParameters(), visitor); } }