| /* |
| * 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); |
| } |
| } |
| } |