blob: da58fd1e63d6c1eadb435fd6a6d423437722ca7a [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/string_source.dart';
/**
* A type provider that can be used by tests without creating the element model
* for the core library.
*/
class TestTypeProvider extends TypeProviderBase {
/**
* The type representing the built-in type 'bool'.
*/
InterfaceType _boolType;
/**
* The type representing the type 'bottom'.
*/
DartType _bottomType;
/**
* The type representing the built-in type 'double'.
*/
InterfaceType _doubleType;
/**
* The type representing the built-in type 'deprecated'.
*/
InterfaceType _deprecatedType;
/**
* The type representing the built-in type 'dynamic'.
*/
DartType _dynamicType;
/**
* The type representing the built-in type 'Function'.
*/
InterfaceType _functionType;
/**
* The type representing 'Future<dynamic>'
*/
InterfaceType _futureDynamicType;
/**
* The type representing 'Future<Null>'
*/
InterfaceType _futureNullType;
/**
* The type representing the built-in type 'FutureOr'
*/
InterfaceType _futureOrNullType;
/**
* The type representing the built-in type 'FutureOr'
*/
InterfaceType _futureOrType;
/**
* The type representing the built-in type 'Future'
*/
InterfaceType _futureType;
/**
* The type representing the built-in type 'int'.
*/
InterfaceType _intType;
/**
* The type representing 'Iterable<dynamic>'
*/
InterfaceType _iterableDynamicType;
/**
* The type representing 'Iterable<Object>'
*/
InterfaceType _iterableObjectType;
/**
* The type representing the built-in type 'Iterable'.
*/
InterfaceType _iterableType;
/**
* The type representing the built-in type 'Iterator'.
*/
InterfaceType _iteratorType;
/**
* The type representing the built-in type 'List'.
*/
InterfaceType _listType;
/**
* The type representing the built-in type 'Map'.
*/
InterfaceType _mapType;
/**
* The type representing the built-in type 'Map<Object, Object>'.
*/
InterfaceType _mapObjectObjectType;
/**
* The type representing the built-in type 'Never'.
*/
InterfaceType _neverType;
/**
* An shared object representing the value 'null'.
*/
DartObjectImpl _nullObject;
/**
* The type representing the built-in type 'Null'.
*/
InterfaceType _nullType;
/**
* The type representing the built-in type 'num'.
*/
InterfaceType _numType;
/**
* The type representing the built-in type 'Object'.
*/
InterfaceType _objectType;
/**
* The type representing the built-in type 'Set'.
*/
InterfaceType _setType;
/**
* The type representing the built-in type 'StackTrace'.
*/
InterfaceType _stackTraceType;
/**
* The type representing 'Stream<dynamic>'.
*/
InterfaceType _streamDynamicType;
/**
* The type representing the built-in type 'Stream'.
*/
InterfaceType _streamType;
/**
* The type representing the built-in type 'String'.
*/
InterfaceType _stringType;
/**
* The type representing the built-in type 'Symbol'.
*/
InterfaceType _symbolType;
/**
* The type representing the built-in type 'Type'.
*/
InterfaceType _typeType;
/**
* The analysis context, if any. Used to create an appropriate 'dart:async'
* library to back `Future<T>`.
*/
AnalysisContext _context;
/**
* The analysis driver, if any. Used to create an appropriate 'dart:async'
* library to back `Future<T>`.
*/
AnalysisDriver _driver;
TestTypeProvider([this._context, this._driver]);
@override
InterfaceType get boolType {
if (_boolType == null) {
ClassElementImpl boolElement = ElementFactory.classElement2("bool");
_boolType = boolElement.type;
ConstructorElementImpl fromEnvironment =
ElementFactory.constructorElement(
boolElement, "fromEnvironment", true);
fromEnvironment.parameters = <ParameterElement>[
ElementFactory.requiredParameter2("name", stringType),
ElementFactory.namedParameter3("defaultValue",
type: _boolType,
initializer: AstTestFactory.booleanLiteral(false),
initializerCode: 'false')
];
fromEnvironment.factory = true;
fromEnvironment.isCycleFree = true;
boolElement.constructors = <ConstructorElement>[fromEnvironment];
}
return _boolType;
}
@override
DartType get bottomType {
if (_bottomType == null) {
_bottomType = BottomTypeImpl.instance;
}
return _bottomType;
}
@override
InterfaceType get deprecatedType {
if (_deprecatedType == null) {
ClassElementImpl deprecatedElement =
ElementFactory.classElement2("Deprecated");
FieldElementImpl expiresField = ElementFactory.fieldElement(
'expires', false, true, false, stringType);
deprecatedElement.fields = <FieldElement>[expiresField];
deprecatedElement.accessors = <PropertyAccessorElement>[
expiresField.getter
];
ConstructorElementImpl constructor = ElementFactory.constructorElement(
deprecatedElement, '', true, [stringType]);
(constructor.parameters[0] as ParameterElementImpl).name = 'expires';
ConstructorFieldInitializer expiresInit =
AstTestFactory.constructorFieldInitializer(
true, 'expires', AstTestFactory.identifier3('expires'));
expiresInit.fieldName.staticElement = expiresField;
(expiresInit.expression as SimpleIdentifier).staticElement =
constructor.parameters[0];
constructor.constantInitializers = <ConstructorInitializer>[expiresInit];
deprecatedElement.constructors = <ConstructorElement>[constructor];
_deprecatedType = deprecatedElement.type;
}
return _deprecatedType;
}
@override
InterfaceType get doubleType {
if (_doubleType == null) {
_initializeNumericTypes();
}
return _doubleType;
}
@override
DartType get dynamicType {
if (_dynamicType == null) {
_dynamicType = DynamicTypeImpl.instance;
}
return _dynamicType;
}
@override
InterfaceType get functionType {
if (_functionType == null) {
ClassElementImpl functionClass = ElementFactory.classElement2("Function");
functionClass.constructors = <ConstructorElement>[
ElementFactory.constructorElement(functionClass, null, false)
];
_functionType = functionClass.type;
}
return _functionType;
}
@override
InterfaceType get futureDynamicType {
if (_futureDynamicType == null) {
_futureDynamicType = futureType.instantiate(<DartType>[dynamicType]);
}
return _futureDynamicType;
}
@override
InterfaceType get futureNullType {
if (_futureNullType == null) {
_futureNullType = futureType.instantiate(<DartType>[nullType]);
}
return _futureNullType;
}
@override
InterfaceType get futureOrNullType {
if (_futureOrNullType == null) {
_futureOrNullType = futureOrType.instantiate(<DartType>[nullType]);
}
return _futureOrNullType;
}
@override
InterfaceType get futureOrType {
if (_futureOrType == null) {
_initDartAsync();
}
return _futureOrType;
}
@override
InterfaceType get futureType {
if (_futureType == null) {
_initDartAsync();
}
return _futureType;
}
@override
InterfaceType get intType {
if (_intType == null) {
_initializeNumericTypes();
}
return _intType;
}
@override
InterfaceType get iterableDynamicType {
if (_iterableDynamicType == null) {
_iterableDynamicType = iterableType.instantiate(<DartType>[dynamicType]);
}
return _iterableDynamicType;
}
@override
InterfaceType get iterableObjectType {
if (_iterableObjectType == null) {
_iterableObjectType = iterableType.instantiate(<DartType>[objectType]);
}
return _iterableObjectType;
}
@override
InterfaceType get iterableType {
if (_iterableType == null) {
ClassElementImpl iterableElement =
ElementFactory.classElement2("Iterable", ["E"]);
_iterableType = iterableElement.type;
DartType eType = iterableElement.typeParameters[0].type;
_setAccessors(iterableElement, <PropertyAccessorElement>[
ElementFactory.getterElement(
"iterator", false, iteratorType.instantiate(<DartType>[eType])),
ElementFactory.getterElement("last", false, eType)
]);
iterableElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(iterableElement, '', true)
..isCycleFree = true
];
_propagateTypeArguments(iterableElement);
}
return _iterableType;
}
InterfaceType get iteratorType {
if (_iteratorType == null) {
ClassElementImpl iteratorElement =
ElementFactory.classElement2("Iterator", ["E"]);
_iteratorType = iteratorElement.type;
DartType eType = iteratorElement.typeParameters[0].type;
_setAccessors(iteratorElement, <PropertyAccessorElement>[
ElementFactory.getterElement("current", false, eType)
]);
iteratorElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(iteratorElement, null, false)
];
_propagateTypeArguments(iteratorElement);
}
return _iteratorType;
}
@override
InterfaceType get listType {
if (_listType == null) {
ClassElementImpl listElement =
ElementFactory.classElement2("List", ["E"]);
listElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement2(listElement, null)
];
_listType = listElement.type;
DartType eType = listElement.typeParameters[0].type;
InterfaceType iterableType =
this.iterableType.instantiate(<DartType>[eType]);
listElement.interfaces = <InterfaceType>[iterableType];
_setAccessors(listElement, <PropertyAccessorElement>[
ElementFactory.getterElement("length", false, intType)
]);
listElement.methods = <MethodElement>[
ElementFactory.methodElement("[]", eType, [intType]),
ElementFactory.methodElement(
"[]=", VoidTypeImpl.instance, [intType, eType]),
ElementFactory.methodElement("add", VoidTypeImpl.instance, [eType])
];
_propagateTypeArguments(listElement);
}
return _listType;
}
@override
InterfaceType get mapObjectObjectType {
if (_mapObjectObjectType == null) {
_mapObjectObjectType =
mapType.instantiate(<DartType>[objectType, objectType]);
}
return _mapObjectObjectType;
}
@override
InterfaceType get mapType {
if (_mapType == null) {
ClassElementImpl mapElement =
ElementFactory.classElement2("Map", ["K", "V"]);
_mapType = mapElement.type;
DartType kType = mapElement.typeParameters[0].type;
DartType vType = mapElement.typeParameters[1].type;
_setAccessors(mapElement, <PropertyAccessorElement>[
ElementFactory.getterElement("length", false, intType)
]);
mapElement.methods = <MethodElement>[
ElementFactory.methodElement("[]", vType, [objectType]),
ElementFactory.methodElement(
"[]=", VoidTypeImpl.instance, [kType, vType])
];
mapElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(mapElement, '', false)
..external = true
..factory = true
];
_propagateTypeArguments(mapElement);
}
return _mapType;
}
@override
InterfaceType get neverType {
if (_neverType == null) {
ClassElementImpl neverElement =
ElementFactory.classElement('Never', objectType);
_neverType = neverElement.type;
}
return _neverType;
}
@override
DartObjectImpl get nullObject {
if (_nullObject == null) {
_nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
}
return _nullObject;
}
@override
InterfaceType get nullType {
if (_nullType == null) {
var nullElement = ElementFactory.classElement2("Null");
nullElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(
nullElement, '_uninstantiatable', false)
..factory = true
];
// Create a library element for "dart:core"
// This enables the "isDartCoreNull" getter.
var library = new LibraryElementImpl.forNode(
_context, null, AstTestFactory.libraryIdentifier2(["dart.core"]));
var unit = new CompilationUnitElementImpl();
library.definingCompilationUnit = unit;
unit.librarySource = unit.source = new StringSource('', null);
nullElement.enclosingElement = library;
_nullType = nullElement.type;
}
return _nullType;
}
@override
InterfaceType get numType {
if (_numType == null) {
_initializeNumericTypes();
}
return _numType;
}
@override
InterfaceType get objectType {
if (_objectType == null) {
ClassElementImpl objectElement = ElementFactory.object;
_objectType = objectElement.type;
ConstructorElementImpl constructor =
ElementFactory.constructorElement(objectElement, '', true);
constructor.constantInitializers = <ConstructorInitializer>[];
objectElement.constructors = <ConstructorElement>[constructor];
objectElement.methods = <MethodElement>[
ElementFactory.methodElement("toString", stringType),
ElementFactory.methodElement("==", boolType, [_objectType]),
ElementFactory.methodElement("noSuchMethod", dynamicType, [dynamicType])
];
_setAccessors(objectElement, <PropertyAccessorElement>[
ElementFactory.getterElement("hashCode", false, intType),
ElementFactory.getterElement("runtimeType", false, typeType)
]);
}
return _objectType;
}
@override
InterfaceType get setType {
if (_setType == null) {
ClassElementImpl setElement = ElementFactory.classElement2("Set", ["E"]);
_setType = setElement.type;
}
return _setType;
}
@override
InterfaceType get stackTraceType {
if (_stackTraceType == null) {
ClassElementImpl stackTraceElement =
ElementFactory.classElement2("StackTrace");
stackTraceElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(stackTraceElement, null, false)
];
_stackTraceType = stackTraceElement.type;
}
return _stackTraceType;
}
@override
InterfaceType get streamDynamicType {
if (_streamDynamicType == null) {
_streamDynamicType = streamType.instantiate(<DartType>[dynamicType]);
}
return _streamDynamicType;
}
@override
InterfaceType get streamType {
if (_streamType == null) {
_streamType = ElementFactory.classElement2("Stream", ["T"]).type;
}
return _streamType;
}
@override
InterfaceType get stringType {
if (_stringType == null) {
ClassElementImpl stringElement = ElementFactory.classElement2("String");
_stringType = stringElement.type;
_setAccessors(stringElement, <PropertyAccessorElement>[
ElementFactory.getterElement("isEmpty", false, boolType),
ElementFactory.getterElement("length", false, intType),
ElementFactory.getterElement(
"codeUnits", false, listType.instantiate(<DartType>[intType]))
]);
stringElement.methods = <MethodElement>[
ElementFactory.methodElement("+", _stringType, [_stringType]),
ElementFactory.methodElement("toLowerCase", _stringType),
ElementFactory.methodElement("toUpperCase", _stringType)
];
ConstructorElementImpl fromEnvironment =
ElementFactory.constructorElement(
stringElement, "fromEnvironment", true);
fromEnvironment.parameters = <ParameterElement>[
ElementFactory.requiredParameter2("name", stringType),
ElementFactory.namedParameter3("defaultValue", type: _stringType)
];
fromEnvironment.factory = true;
fromEnvironment.isCycleFree = true;
stringElement.constructors = <ConstructorElement>[fromEnvironment];
}
return _stringType;
}
@override
InterfaceType get symbolType {
if (_symbolType == null) {
ClassElementImpl symbolClass = ElementFactory.classElement2("Symbol");
ConstructorElementImpl constructor = ElementFactory.constructorElement(
symbolClass, '', true, [stringType]);
constructor.factory = true;
constructor.isCycleFree = true;
symbolClass.constructors = <ConstructorElement>[constructor];
_symbolType = symbolClass.type;
}
return _symbolType;
}
@override
InterfaceType get typeType {
if (_typeType == null) {
ClassElementImpl typeClass = ElementFactory.classElement2("Type");
typeClass.constructors = <ConstructorElement>[
ElementFactory.constructorElement(typeClass, null, false)
..isSynthetic = true
];
_typeType = typeClass.type;
}
return _typeType;
}
void _initDartAsync() {
Source asyncSource;
if (_driver != null) {
asyncSource = _driver.sourceFactory.forUri(DartSdk.DART_ASYNC);
} else if (_context != null) {
asyncSource = _context.sourceFactory.forUri(DartSdk.DART_ASYNC);
_context.setContents(asyncSource, "");
} else {
asyncSource = null;
}
CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
_context, null, AstTestFactory.libraryIdentifier2(["dart.async"]));
asyncLibrary.definingCompilationUnit = asyncUnit;
asyncUnit.librarySource = asyncUnit.source = asyncSource;
ClassElementImpl future = ElementFactory.classElement2("Future", ["T"]);
_futureType = future.type;
asyncUnit.types = <ClassElement>[future];
ClassElementImpl futureOr = ElementFactory.classElement2("FutureOr", ["T"]);
_futureOrType = futureOr.type;
asyncUnit.types = <ClassElement>[future, futureOr];
}
/**
* 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.
*/
void _initializeNumericTypes() {
//
// Create the type hierarchy.
//
ClassElementImpl numElement = ElementFactory.classElement2("num");
_numType = numElement.type;
ClassElementImpl intElement = ElementFactory.classElement("int", _numType);
_intType = intElement.type;
ClassElementImpl doubleElement =
ElementFactory.classElement("double", _numType);
_doubleType = doubleElement.type;
//
// Force the referenced types to be cached.
//
objectType;
boolType;
nullType;
stringType;
//
// Add the methods.
//
numElement.methods = <MethodElement>[
ElementFactory.methodElement("+", _numType, [_numType]),
ElementFactory.methodElement("-", _numType, [_numType]),
ElementFactory.methodElement("*", _numType, [_numType]),
ElementFactory.methodElement("%", _numType, [_numType]),
ElementFactory.methodElement("/", _doubleType, [_numType]),
ElementFactory.methodElement("~/", _numType, [_numType]),
ElementFactory.methodElement("-", _numType),
ElementFactory.methodElement("remainder", _numType, [_numType]),
ElementFactory.methodElement("<", _boolType, [_numType]),
ElementFactory.methodElement("<=", _boolType, [_numType]),
ElementFactory.methodElement(">", _boolType, [_numType]),
ElementFactory.methodElement(">=", _boolType, [_numType]),
ElementFactory.methodElement("==", _boolType, [_objectType]),
ElementFactory.methodElement("abs", _numType),
ElementFactory.methodElement("floor", _numType),
ElementFactory.methodElement("ceil", _numType),
ElementFactory.methodElement("round", _numType),
ElementFactory.methodElement("truncate", _numType),
ElementFactory.methodElement("toInt", _intType),
ElementFactory.methodElement("toDouble", _doubleType),
ElementFactory.methodElement("toStringAsFixed", _stringType, [_intType]),
ElementFactory.methodElement(
"toStringAsExponential", _stringType, [_intType]),
ElementFactory.methodElement(
"toStringAsPrecision", _stringType, [_intType]),
ElementFactory.methodElement("toRadixString", _stringType, [_intType])
];
numElement.accessors = [
ElementFactory.getterElement('isInfinite', false, _boolType),
ElementFactory.getterElement('isNaN', false, _boolType),
ElementFactory.getterElement('isNegative', false, _boolType),
];
intElement.methods = <MethodElement>[
ElementFactory.methodElement("&", _intType, [_intType]),
ElementFactory.methodElement("|", _intType, [_intType]),
ElementFactory.methodElement("^", _intType, [_intType]),
ElementFactory.methodElement("~", _intType),
ElementFactory.methodElement("<<", _intType, [_intType]),
ElementFactory.methodElement(">>", _intType, [_intType]),
ElementFactory.methodElement("-", _intType),
ElementFactory.methodElement("abs", _intType),
ElementFactory.methodElement("round", _intType),
ElementFactory.methodElement("floor", _intType),
ElementFactory.methodElement("ceil", _intType),
ElementFactory.methodElement("truncate", _intType),
ElementFactory.methodElement("toString", _stringType)
];
ConstructorElementImpl fromEnvironment =
ElementFactory.constructorElement(intElement, "fromEnvironment", true);
fromEnvironment.parameters = <ParameterElement>[
ElementFactory.requiredParameter2("name", stringType),
ElementFactory.namedParameter3("defaultValue", type: _intType)
];
fromEnvironment.factory = true;
fromEnvironment.isCycleFree = true;
numElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(numElement, null, false)
..isSynthetic = true
];
intElement.constructors = <ConstructorElement>[fromEnvironment];
doubleElement.constructors = <ConstructorElement>[
ElementFactory.constructorElement(doubleElement, null, false)
..isSynthetic = true
];
ConstFieldElementImpl varINFINITY = ElementFactory.fieldElement(
"INFINITY", true, false, true, _doubleType,
initializer: AstTestFactory.doubleLiteral(double.infinity));
varINFINITY.constantInitializer = AstTestFactory.binaryExpression(
AstTestFactory.integer(1), TokenType.SLASH, AstTestFactory.integer(0));
List<FieldElement> fields = <FieldElement>[
ElementFactory.fieldElement("NAN", true, false, true, _doubleType,
initializer: AstTestFactory.doubleLiteral(double.nan)),
varINFINITY,
ElementFactory.fieldElement(
"NEGATIVE_INFINITY", true, false, true, _doubleType,
initializer: AstTestFactory.doubleLiteral(double.negativeInfinity)),
ElementFactory.fieldElement(
"MIN_POSITIVE", true, false, true, _doubleType,
initializer: AstTestFactory.doubleLiteral(double.minPositive)),
ElementFactory.fieldElement("MAX_FINITE", true, false, true, _doubleType,
initializer: AstTestFactory.doubleLiteral(double.maxFinite))
];
doubleElement.fields = fields;
int fieldCount = fields.length;
List<PropertyAccessorElement> accessors =
new List<PropertyAccessorElement>(fieldCount);
for (int i = 0; i < fieldCount; i++) {
accessors[i] = fields[i].getter;
}
doubleElement.accessors = accessors;
doubleElement.methods = <MethodElement>[
ElementFactory.methodElement("remainder", _doubleType, [_numType]),
ElementFactory.methodElement("+", _doubleType, [_numType]),
ElementFactory.methodElement("-", _doubleType, [_numType]),
ElementFactory.methodElement("*", _doubleType, [_numType]),
ElementFactory.methodElement("%", _doubleType, [_numType]),
ElementFactory.methodElement("/", _doubleType, [_numType]),
ElementFactory.methodElement("~/", _doubleType, [_numType]),
ElementFactory.methodElement("-", _doubleType),
ElementFactory.methodElement("abs", _doubleType),
ElementFactory.methodElement("round", _doubleType),
ElementFactory.methodElement("floor", _doubleType),
ElementFactory.methodElement("ceil", _doubleType),
ElementFactory.methodElement("truncate", _doubleType),
ElementFactory.methodElement("toString", _stringType)
];
}
/**
* Given a [classElement] representing a class with type parameters, propagate
* those type parameters to all of the accessors, methods and constructors
* defined for the class.
*/
void _propagateTypeArguments(ClassElementImpl classElement) {
for (PropertyAccessorElement accessor in classElement.accessors) {
(accessor as ExecutableElementImpl).type = new FunctionTypeImpl(accessor);
}
for (MethodElement method in classElement.methods) {
(method as ExecutableElementImpl).type = new FunctionTypeImpl(method);
}
}
/**
* Set the accessors for the given class [element] to the given [accessors]
* and also set the fields to those that correspond to the accessors.
*/
void _setAccessors(
ClassElementImpl element, List<PropertyAccessorElement> accessors) {
element.accessors = accessors;
element.fields = accessors
.map((PropertyAccessorElement accessor) => accessor.variable)
.cast<FieldElement>()
.toList();
}
}