blob: 1ba84892a827e7a58a04c3c0309bb6feb170f6cb [file] [log] [blame]
/*
* 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.resolver;
import com.google.dart.engine.element.ConstructorElement;
import com.google.dart.engine.element.FieldElement;
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.element.ClassElementImpl;
import com.google.dart.engine.internal.element.ConstructorElementImpl;
import com.google.dart.engine.internal.type.BottomTypeImpl;
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.internal.type.VoidTypeImpl;
import com.google.dart.engine.type.InterfaceType;
import com.google.dart.engine.type.Type;
import static com.google.dart.engine.element.ElementFactory.classElement;
import static com.google.dart.engine.element.ElementFactory.constructorElement;
import static com.google.dart.engine.element.ElementFactory.fieldElement;
import static com.google.dart.engine.element.ElementFactory.getObject;
import static com.google.dart.engine.element.ElementFactory.getterElement;
import static com.google.dart.engine.element.ElementFactory.methodElement;
import static com.google.dart.engine.element.ElementFactory.namedParameter;
import static com.google.dart.engine.element.ElementFactory.requiredParameter;
/**
* Instances of the class {@code TestTypeProvider} implement a type provider that can be used by
* tests without creating the element model for the core library.
*/
public class TestTypeProvider implements TypeProvider {
/**
* The type representing the built-in type 'bool'.
*/
private InterfaceType boolType;
/**
* The type representing the type 'bottom'.
*/
private Type bottomType;
/**
* The type representing the built-in type 'double'.
*/
private InterfaceType doubleType;
/**
* The type representing the built-in type 'deprecated'.
*/
private InterfaceType deprecatedType;
/**
* The type representing the built-in type 'dynamic'.
*/
private Type dynamicType;
/**
* The type representing the built-in type 'Function'.
*/
private InterfaceType functionType;
/**
* The type representing the built-in type 'int'.
*/
private InterfaceType intType;
/**
* The type representing 'Iterable<dynamic>'
*/
private InterfaceType iterableDynamicType;
/**
* The type representing the built-in type 'Iterable'.
*/
private InterfaceType iterableType;
/**
* The type representing the built-in type 'Iterator'.
*/
private InterfaceType iteratorType;
/**
* The type representing the built-in type 'List'.
*/
private InterfaceType listType;
/**
* The type representing the built-in type 'Map'.
*/
private InterfaceType mapType;
/**
* The type representing the built-in type 'Null'.
*/
private InterfaceType nullType;
/**
* The type representing the built-in type 'num'.
*/
private InterfaceType numType;
/**
* The type representing the built-in type 'Object'.
*/
private InterfaceType objectType;
/**
* The type representing the built-in type 'StackTrace'.
*/
private InterfaceType stackTraceType;
/**
* The type representing the built-in type 'String'.
*/
private InterfaceType stringType;
/**
* The type representing the built-in type 'Symbol'.
*/
private InterfaceType symbolType;
/**
* The type representing the built-in type 'Type'.
*/
private InterfaceType typeType;
/**
* Initialize a newly created type provider to provide stand-ins for the types defined in the core
* library.
*/
public TestTypeProvider() {
super();
}
@Override
public InterfaceType getBoolType() {
if (boolType == null) {
ClassElementImpl boolElement = classElement("bool");
boolType = boolElement.getType();
ConstructorElementImpl fromEnvironment = constructorElement(
boolElement,
"fromEnvironment",
true);
fromEnvironment.setParameters(new ParameterElement[] {
requiredParameter("name", getStringType()), namedParameter("defaultValue", boolType)});
fromEnvironment.setFactory(true);
boolElement.setConstructors(new ConstructorElement[] {fromEnvironment});
}
return boolType;
}
@Override
public Type getBottomType() {
if (bottomType == null) {
bottomType = BottomTypeImpl.getInstance();
}
return bottomType;
}
@Override
public InterfaceType getDeprecatedType() {
if (deprecatedType == null) {
ClassElementImpl deprecatedElement = classElement("Deprecated");
deprecatedElement.setConstructors(new ConstructorElement[] {constructorElement(
deprecatedElement,
null,
true,
getStringType())});
deprecatedType = deprecatedElement.getType();
}
return deprecatedType;
}
@Override
public InterfaceType getDoubleType() {
if (doubleType == null) {
initializeNumericTypes();
}
return doubleType;
}
@Override
public Type getDynamicType() {
if (dynamicType == null) {
dynamicType = DynamicTypeImpl.getInstance();
}
return dynamicType;
}
@Override
public InterfaceType getFunctionType() {
if (functionType == null) {
functionType = classElement("Function").getType();
}
return functionType;
}
@Override
public InterfaceType getIntType() {
if (intType == null) {
initializeNumericTypes();
}
return intType;
}
@Override
public InterfaceType getIterableDynamicType() {
if (iterableDynamicType == null) {
iterableDynamicType = getIterableType().substitute(new Type[] {getDynamicType()});
}
return iterableDynamicType;
}
@Override
public InterfaceType getIterableType() {
if (iterableType == null) {
ClassElementImpl iterableElement = classElement("Iterable", "E");
iterableType = iterableElement.getType();
Type eType = iterableElement.getTypeParameters()[0].getType();
iterableElement.setAccessors(new PropertyAccessorElement[] {//
getterElement("iterator", false, getIteratorType().substitute(new Type[] {eType})),
getterElement("last", false, eType),});
propagateTypeArguments(iterableElement);
}
return iterableType;
}
public InterfaceType getIteratorType() {
if (iteratorType == null) {
ClassElementImpl iteratorElement = classElement("Iterator", "E");
iteratorType = iteratorElement.getType();
Type eType = iteratorElement.getTypeParameters()[0].getType();
iteratorElement.setAccessors(new PropertyAccessorElement[] {//
getterElement("current", false, eType),});
propagateTypeArguments(iteratorElement);
}
return iteratorType;
}
@Override
public InterfaceType getListType() {
if (listType == null) {
ClassElementImpl listElement = classElement("List", "E");
listElement.setConstructors(new ConstructorElement[] {constructorElement(listElement, null)});
listType = listElement.getType();
Type eType = listElement.getTypeParameters()[0].getType();
InterfaceType iterableType = getIterableType().substitute(new Type[] {eType});
listElement.setInterfaces(new InterfaceType[] {iterableType});
listElement.setAccessors(new PropertyAccessorElement[] {getterElement(
"length",
false,
getIntType())});
listElement.setMethods(new MethodElement[] {
methodElement("[]", eType, getIntType()),
methodElement("[]=", VoidTypeImpl.getInstance(), getIntType(), eType),
methodElement("add", VoidTypeImpl.getInstance(), eType)});
propagateTypeArguments(listElement);
}
return listType;
}
@Override
public InterfaceType getMapType() {
if (mapType == null) {
ClassElementImpl mapElement = classElement("Map", "K", "V");
mapType = mapElement.getType();
Type kType = mapElement.getTypeParameters()[0].getType();
Type vType = mapElement.getTypeParameters()[1].getType();
mapElement.setAccessors(new PropertyAccessorElement[] {getterElement(
"length",
false,
getIntType())});
mapElement.setMethods(new MethodElement[] {
methodElement("[]", vType, getObjectType()),
methodElement("[]=", VoidTypeImpl.getInstance(), kType, vType)});
propagateTypeArguments(mapElement);
}
return mapType;
}
@Override
public InterfaceType getNullType() {
if (nullType == null) {
nullType = classElement("Null").getType();
}
return nullType;
}
@Override
public InterfaceType getNumType() {
if (numType == null) {
initializeNumericTypes();
}
return numType;
}
@Override
public InterfaceType getObjectType() {
if (objectType == null) {
ClassElementImpl objectElement = getObject();
objectType = objectElement.getType();
objectElement.setConstructors(new ConstructorElement[] {constructorElement(
objectElement,
null)});
objectElement.setMethods(new MethodElement[] {
methodElement("toString", getStringType()),
methodElement("==", getBoolType(), objectType),
methodElement("noSuchMethod", getDynamicType(), getDynamicType())});
objectElement.setAccessors(new PropertyAccessorElement[] {
getterElement("hashCode", false, getIntType()),
getterElement("runtimeType", false, getTypeType())});
}
return objectType;
}
@Override
public InterfaceType getStackTraceType() {
if (stackTraceType == null) {
stackTraceType = classElement("StackTrace").getType();
}
return stackTraceType;
}
@Override
public InterfaceType getStringType() {
if (stringType == null) {
stringType = classElement("String").getType();
ClassElementImpl stringElement = (ClassElementImpl) stringType.getElement();
stringElement.setAccessors(new PropertyAccessorElement[] {//
getterElement("isEmpty", false, getBoolType()),
getterElement("length", false, getIntType()),
getterElement("codeUnits", false, getListType().substitute(new Type[] {getIntType()}))});
stringElement.setMethods(new MethodElement[] {
methodElement("+", stringType, stringType), methodElement("toLowerCase", stringType),
methodElement("toUpperCase", stringType)});
ConstructorElementImpl fromEnvironment = constructorElement(
stringElement,
"fromEnvironment",
true);
fromEnvironment.setParameters(new ParameterElement[] {
requiredParameter("name", getStringType()), namedParameter("defaultValue", stringType)});
fromEnvironment.setFactory(true);
stringElement.setConstructors(new ConstructorElement[] {fromEnvironment});
}
return stringType;
}
@Override
public InterfaceType getSymbolType() {
if (symbolType == null) {
ClassElementImpl symbolClass = classElement("Symbol");
ConstructorElementImpl constructor = constructorElement(
symbolClass,
null,
true,
getStringType());
constructor.setFactory(true);
symbolClass.setConstructors(new ConstructorElement[] {constructor});
symbolType = symbolClass.getType();
}
return symbolType;
}
@Override
public InterfaceType getTypeType() {
if (typeType == null) {
typeType = classElement("Type").getType();
}
return typeType;
}
/**
* Initialize the numeric types. They are created as a group so that we can (a) create the right
* hierarchy and (b) add members to them.
*/
private void initializeNumericTypes() {
//
// Create the type hierarchy.
//
ClassElementImpl numElement = classElement("num");
numType = numElement.getType();
ClassElementImpl intElement = classElement("int", numType);
intType = intElement.getType();
ClassElementImpl doubleElement = classElement("double", numType);
doubleType = doubleElement.getType();
//
// Force the referenced types to be cached.
//
getObjectType();
getBoolType();
getStringType();
//
// Add the methods.
//
numElement.setMethods(new MethodElement[] {
methodElement("+", numType, numType), methodElement("-", numType, numType),
methodElement("*", numType, numType), methodElement("%", numType, numType),
methodElement("/", doubleType, numType), methodElement("~/", numType, numType),
methodElement("-", numType), methodElement("remainder", numType, numType),
methodElement("<", boolType, numType), methodElement("<=", boolType, numType),
methodElement(">", boolType, numType), methodElement(">=", boolType, numType),
methodElement("==", boolType, objectType), methodElement("isNaN", boolType),
methodElement("isNegative", boolType), methodElement("isInfinite", boolType),
methodElement("abs", numType), methodElement("floor", numType),
methodElement("ceil", numType), methodElement("round", numType),
methodElement("truncate", numType), methodElement("toInt", intType),
methodElement("toDouble", doubleType),
methodElement("toStringAsFixed", stringType, intType),
methodElement("toStringAsExponential", stringType, intType),
methodElement("toStringAsPrecision", stringType, intType),
methodElement("toRadixString", stringType, intType),});
intElement.setMethods(new MethodElement[] {
methodElement("&", intType, intType),
methodElement("|", intType, intType),
methodElement("^", intType, intType),
methodElement("~", intType),
methodElement("<<", intType, intType),
methodElement(">>", intType, intType),
// getterElement("isEven", boolType),
// getterElement("isOdd", boolType),
methodElement("-", intType), methodElement("abs", intType),
methodElement("round", intType), methodElement("floor", intType),
methodElement("ceil", intType), methodElement("truncate", intType),
methodElement("toString", stringType),
// methodElement(/*external static*/ "parse", intType, stringType),
});
ConstructorElementImpl fromEnvironment = constructorElement(intElement, "fromEnvironment", true);
fromEnvironment.setParameters(new ParameterElement[] {
requiredParameter("name", getStringType()), namedParameter("defaultValue", intType)});
fromEnvironment.setFactory(true);
intElement.setConstructors(new ConstructorElement[] {fromEnvironment});
FieldElement[] fields = new FieldElement[] {fieldElement("NAN", true, false, true, doubleType), // 0.0 / 0.0
fieldElement("INFINITY", true, false, true, doubleType), // 1.0 / 0.0
fieldElement("NEGATIVE_INFINITY", true, false, true, doubleType), // -INFINITY
fieldElement("MIN_POSITIVE", true, false, true, doubleType), // 5e-324
fieldElement("MAX_FINITE", true, false, true, doubleType), // 1.7976931348623157e+308;
};
doubleElement.setFields(fields);
int fieldCount = fields.length;
PropertyAccessorElement[] accessors = new PropertyAccessorElement[fieldCount];
for (int i = 0; i < fieldCount; i++) {
accessors[i] = fields[i].getGetter();
}
doubleElement.setAccessors(accessors);
doubleElement.setMethods(new MethodElement[] {
methodElement("remainder", doubleType, numType), methodElement("+", doubleType, numType),
methodElement("-", doubleType, numType), methodElement("*", doubleType, numType),
methodElement("%", doubleType, numType), methodElement("/", doubleType, numType),
methodElement("~/", doubleType, numType), methodElement("-", doubleType),
methodElement("abs", doubleType), methodElement("round", doubleType),
methodElement("floor", doubleType), methodElement("ceil", doubleType),
methodElement("truncate", doubleType), methodElement("toString", stringType),
// methodElement(/*external static*/ "parse", doubleType, stringType),
});
}
/**
* Given a class element representing a class with type parameters, propagate those type
* parameters to all of the accessors, methods and constructors defined for the class.
*
* @param classElement the element representing the class with type parameters
*/
private void propagateTypeArguments(ClassElementImpl classElement) {
Type[] typeArguments = TypeParameterTypeImpl.getTypes(classElement.getTypeParameters());
for (PropertyAccessorElement accessor : classElement.getAccessors()) {
FunctionTypeImpl functionType = (FunctionTypeImpl) accessor.getType();
functionType.setTypeArguments(typeArguments);
}
for (MethodElement method : classElement.getMethods()) {
FunctionTypeImpl functionType = (FunctionTypeImpl) method.getType();
functionType.setTypeArguments(typeArguments);
}
for (ConstructorElement constructor : classElement.getConstructors()) {
FunctionTypeImpl functionType = (FunctionTypeImpl) constructor.getType();
functionType.setTypeArguments(typeArguments);
}
}
}