blob: 56deded31b7c689ba1172daf7b9a09957bd64dcd [file] [log] [blame]
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;
}
}