| package com.google.dart.engine.internal.resolver; |
| |
| import com.google.dart.engine.ast.ClassDeclaration; |
| import com.google.dart.engine.ast.ClassTypeAlias; |
| import com.google.dart.engine.ast.EnumDeclaration; |
| import com.google.dart.engine.ast.FunctionDeclaration; |
| import com.google.dart.engine.ast.NodeList; |
| import com.google.dart.engine.ast.TopLevelVariableDeclaration; |
| import com.google.dart.engine.ast.TypeArgumentList; |
| import com.google.dart.engine.ast.TypeName; |
| import com.google.dart.engine.element.ClassElement; |
| import com.google.dart.engine.element.ConstructorElement; |
| import com.google.dart.engine.element.ParameterElement; |
| import com.google.dart.engine.internal.element.ClassElementImpl; |
| import com.google.dart.engine.internal.element.ConstructorElementImpl; |
| import com.google.dart.engine.internal.element.ParameterElementImpl; |
| import com.google.dart.engine.internal.type.DynamicTypeImpl; |
| import com.google.dart.engine.internal.type.FunctionTypeImpl; |
| import com.google.dart.engine.internal.type.TypeParameterTypeImpl; |
| import com.google.dart.engine.source.Source; |
| import com.google.dart.engine.type.InterfaceType; |
| import com.google.dart.engine.type.Type; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Instances of the class {@code SecondTypeResolverVisitor} are used to finish any resolve steps |
| * after the {@link TypeResolverVisitor} that cannot happen in the {@link TypeResolverVisitor}, but |
| * should happen before the next tasks. |
| * <p> |
| * Currently this visitor only finishes the resolution of {@link ClassTypeAlias}s, thus the scopes |
| * of other top level AST nodes do not currently have to be built. |
| * |
| * @coverage dart.engine.resolver |
| */ |
| public class ImplicitConstructorBuilder extends ScopedVisitor { |
| |
| /** |
| * Initialize a newly created visitor to finish resolution in the nodes in a compilation unit. |
| * |
| * @param library the library containing the compilation unit being resolved |
| * @param source the source representing the compilation unit being visited |
| * @param typeProvider the object used to access the types from the core library |
| */ |
| public ImplicitConstructorBuilder(Library library, Source source, TypeProvider typeProvider) { |
| super(library, source, typeProvider); |
| } |
| |
| /** |
| * Initialize a newly created visitor to finish resolution in the nodes in a compilation unit. |
| * |
| * @param library the library containing the compilation unit being resolved |
| * @param source the source representing the compilation unit being visited |
| * @param typeProvider the object used to access the types from the core library |
| */ |
| public ImplicitConstructorBuilder(ResolvableLibrary library, Source source, |
| TypeProvider typeProvider) { |
| super(library, source, typeProvider); |
| } |
| |
| @Override |
| public Void visitClassDeclaration(ClassDeclaration node) { |
| return null; |
| } |
| |
| @Override |
| public Void visitClassTypeAlias(ClassTypeAlias node) { |
| super.visitClassTypeAlias(node); |
| InterfaceType superclassType = null; |
| |
| Type type = node.getSuperclass().getType(); |
| if (type instanceof InterfaceType) { |
| superclassType = (InterfaceType) type; |
| } else { |
| superclassType = getTypeProvider().getObjectType(); |
| } |
| |
| ClassElementImpl classElement = (ClassElementImpl) node.getElement(); |
| if (classElement != null) { |
| ClassElement superclassElement = superclassType.getElement(); |
| if (superclassElement != null) { |
| ConstructorElement[] constructors = superclassElement.getConstructors(); |
| int count = constructors.length; |
| if (count > 0) { |
| Type[] parameterTypes = TypeParameterTypeImpl.getTypes(superclassType.getTypeParameters()); |
| Type[] argumentTypes = getArgumentTypes( |
| node.getSuperclass().getTypeArguments(), |
| parameterTypes); |
| InterfaceType classType = classElement.getType(); |
| ArrayList<ConstructorElement> implicitConstructors = new ArrayList<ConstructorElement>( |
| count); |
| for (int i = 0; i < count; i++) { |
| ConstructorElement explicitConstructor = constructors[i]; |
| if (!explicitConstructor.isFactory()) { |
| implicitConstructors.add(createImplicitContructor( |
| classType, |
| explicitConstructor, |
| parameterTypes, |
| argumentTypes)); |
| } |
| } |
| classElement.setConstructors(implicitConstructors.toArray(new ConstructorElement[implicitConstructors.size()])); |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public Void visitEnumDeclaration(EnumDeclaration node) { |
| return null; |
| } |
| |
| @Override |
| public Void visitFunctionDeclaration(FunctionDeclaration node) { |
| return null; |
| } |
| |
| @Override |
| public Void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| return null; |
| } |
| |
| /** |
| * Create an implicit constructor that is copied from the given constructor, but that is in the |
| * given class. |
| * |
| * @param classType the class in which the implicit constructor is defined |
| * @param explicitConstructor the constructor on which the implicit constructor is modeled |
| * @param parameterTypes the types to be replaced when creating parameters |
| * @param argumentTypes the types with which the parameters are to be replaced |
| * @return the implicit constructor that was created |
| */ |
| private ConstructorElement createImplicitContructor(InterfaceType classType, |
| ConstructorElement explicitConstructor, Type[] parameterTypes, Type[] argumentTypes) { |
| ConstructorElementImpl implicitConstructor = new ConstructorElementImpl( |
| explicitConstructor.getName(), |
| -1); |
| implicitConstructor.setSynthetic(true); |
| implicitConstructor.setRedirectedConstructor(explicitConstructor); |
| implicitConstructor.setConst(explicitConstructor.isConst()); |
| implicitConstructor.setReturnType(classType); |
| ParameterElement[] explicitParameters = explicitConstructor.getParameters(); |
| int count = explicitParameters.length; |
| if (count > 0) { |
| ParameterElement[] implicitParameters = new ParameterElement[count]; |
| for (int i = 0; i < count; i++) { |
| ParameterElement explicitParameter = explicitParameters[i]; |
| ParameterElementImpl implicitParameter = new ParameterElementImpl( |
| explicitParameter.getName(), |
| -1); |
| implicitParameter.setConst(explicitParameter.isConst()); |
| implicitParameter.setFinal(explicitParameter.isFinal()); |
| implicitParameter.setParameterKind(explicitParameter.getParameterKind()); |
| implicitParameter.setSynthetic(true); |
| implicitParameter.setType(explicitParameter.getType().substitute( |
| argumentTypes, |
| parameterTypes)); |
| implicitParameters[i] = implicitParameter; |
| } |
| implicitConstructor.setParameters(implicitParameters); |
| } |
| FunctionTypeImpl type = new FunctionTypeImpl(implicitConstructor); |
| type.setTypeArguments(classType.getTypeArguments()); |
| implicitConstructor.setType(type); |
| return implicitConstructor; |
| } |
| |
| /** |
| * Return an array of argument types that corresponds to the array of parameter types and that are |
| * derived from the given list of type arguments. |
| * |
| * @param typeArguments the type arguments from which the types will be taken |
| * @param parameterTypes the parameter types that must be matched by the type arguments |
| * @return the argument types that correspond to the parameter types |
| */ |
| private Type[] getArgumentTypes(TypeArgumentList typeArguments, Type[] parameterTypes) { |
| DynamicTypeImpl dynamic = DynamicTypeImpl.getInstance(); |
| int parameterCount = parameterTypes.length; |
| Type[] types = new Type[parameterCount]; |
| if (typeArguments == null) { |
| for (int i = 0; i < parameterCount; i++) { |
| types[i] = dynamic; |
| } |
| } else { |
| NodeList<TypeName> arguments = typeArguments.getArguments(); |
| int argumentCount = Math.min(arguments.size(), parameterCount); |
| for (int i = 0; i < argumentCount; i++) { |
| types[i] = arguments.get(i).getType(); |
| } |
| for (int i = argumentCount; i < parameterCount; i++) { |
| types[i] = dynamic; |
| } |
| } |
| return types; |
| } |
| } |