blob: 041127555a189e17a5c02a1447f0f9818fff8eb7 [file] [log] [blame]
// Copyright (c) 2015, 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.
library analyzer.test.src.summary.summary_common;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/summary/base.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/public_namespace_computer.dart'
as public_namespace;
import 'package:path/path.dart' show posix;
import 'package:test/test.dart';
import '../context/mock_sdk.dart';
/**
* Convert the given Posix style file [path] to the corresponding absolute URI.
*/
String absUri(String path) {
String absolutePath = posix.absolute(path);
return posix.toUri(absolutePath).toString();
}
/**
* Convert a summary object (or a portion of one) into a canonical form that
* can be easily compared using [expect]. If [orderByName] is true, and the
* object is a [List], it is sorted by the `name` field of its elements.
*/
Object canonicalize(Object obj, {bool orderByName: false}) {
if (obj is SummaryClass) {
Map<String, Object> result = <String, Object>{};
obj.toMap().forEach((String key, Object value) {
bool orderByName = false;
if (obj is UnlinkedPublicNamespace && key == 'names' ||
obj is UnlinkedPublicName && key == 'members') {
orderByName = true;
}
result[key] = canonicalize(value, orderByName: orderByName);
});
return result;
} else if (obj is List) {
List<Object> result = <Object>[];
for (Object item in obj) {
result.add(canonicalize(item));
}
if (orderByName) {
result.sort((Object a, Object b) {
if (a is Map && b is Map) {
return Comparable.compare(a['name'], b['name']);
} else {
return 0;
}
});
}
return result;
} else if (obj is String || obj is num || obj is bool) {
return obj;
} else {
return obj.toString();
}
}
UnlinkedPublicNamespace computePublicNamespaceFromText(
String text, Source source) {
CharacterReader reader = new CharSequenceReader(text);
Scanner scanner =
new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER);
Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
UnlinkedPublicNamespace namespace = new UnlinkedPublicNamespace.fromBuffer(
public_namespace.computePublicNamespace(unit).toBuffer());
return namespace;
}
/**
* Type of a function that validates an [EntityRef].
*/
typedef void _EntityRefValidator(EntityRef entityRef);
/**
* [SerializedMockSdk] is a singleton class representing the result of
* serializing the mock SDK to summaries. It is computed once and then shared
* among test invocations so that we don't bog down the tests.
*
* Note: should an exception occur during computation of [instance], it will
* silently be set to null to allow other tests to complete quickly.
*/
class SerializedMockSdk {
static final SerializedMockSdk instance = _serializeMockSdk();
final Map<String, UnlinkedUnit> uriToUnlinkedUnit;
final Map<String, LinkedLibrary> uriToLinkedLibrary;
SerializedMockSdk._(this.uriToUnlinkedUnit, this.uriToLinkedLibrary);
static SerializedMockSdk _serializeMockSdk() {
try {
Map<String, UnlinkedUnit> uriToUnlinkedUnit = <String, UnlinkedUnit>{};
Map<String, LinkedLibrary> uriToLinkedLibrary = <String, LinkedLibrary>{};
PackageBundle bundle = new MockSdk().getLinkedBundle();
for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
String uri = bundle.unlinkedUnitUris[i];
uriToUnlinkedUnit[uri] = bundle.unlinkedUnits[i];
}
for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
String uri = bundle.linkedLibraryUris[i];
uriToLinkedLibrary[uri] = bundle.linkedLibraries[i];
}
return new SerializedMockSdk._(uriToUnlinkedUnit, uriToLinkedLibrary);
} catch (_) {
return null;
}
}
}
/**
* Base class containing most summary tests. This allows summary tests to be
* re-used to exercise all the different ways in which summaries can be
* generated (e.g. direct from the AST, from the element model, from a
* "relinking" process, etc.)
*/
abstract class SummaryTest {
/**
* A test will set this to `true` if it contains `import`, `export`, or
* `part` declarations that deliberately refer to non-existent files.
*/
bool allowMissingFiles = false;
/**
* Get access to the linked defining compilation unit.
*/
LinkedUnit get definingUnit => linked.units[0];
/**
* Whether the parts of the IDL marked `@informative` are expected to be
* included in the generated summary; if `false`, these parts of the IDL won't
* be checked.
*/
bool get includeInformative => true;
/**
* Get access to the linked summary that results from serializing and
* then deserializing the library under test.
*/
LinkedLibrary get linked;
/**
* `true` if the linked portion of the summary only contains prelinked data.
* This happens because we don't yet have a full linker; only a prelinker.
*/
bool get skipFullyLinkedData;
/**
* `true` if non-const variable initializers are not serialized.
*/
bool get skipNonConstInitializers;
/**
* `true` if the linked portion of the summary contains the result of strong
* mode analysis.
*/
bool get strongMode;
/**
* Get access to the unlinked compilation unit summaries that result from
* serializing and deserializing the library under test.
*/
List<UnlinkedUnit> get unlinkedUnits;
/**
* Add the given source file so that it may be referenced by the file under
* test.
*/
Source addNamedSource(String filePath, String contents);
/**
* TODO(scheglov) rename "Const" to "Expr" everywhere
*/
void assertUnlinkedConst(UnlinkedExpr constExpr,
{bool isValidConst: true,
List<UnlinkedExprOperation> operators: const <UnlinkedExprOperation>[],
List<UnlinkedExprAssignOperator> assignmentOperators:
const <UnlinkedExprAssignOperator>[],
List<int> ints: const <int>[],
List<double> doubles: const <double>[],
List<String> strings: const <String>[],
List<_EntityRefValidator> referenceValidators:
const <_EntityRefValidator>[]}) {
expect(constExpr, isNotNull);
expect(constExpr.isValidConst, isValidConst);
expect(constExpr.operations, operators);
expect(constExpr.ints, ints);
expect(constExpr.doubles, doubles);
expect(constExpr.strings, strings);
expect(constExpr.assignmentOperators, assignmentOperators);
expect(constExpr.references, hasLength(referenceValidators.length));
for (int i = 0; i < referenceValidators.length; i++) {
referenceValidators[i](constExpr.references[i]);
}
}
/**
* Check that [annotations] contains a single entry which is a reference to
* a top level variable called `a` in the current library.
*/
void checkAnnotationA(List<UnlinkedExpr> annotations) {
expect(annotations, hasLength(1));
assertUnlinkedConst(annotations[0], operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'a',
expectedKind: ReferenceKind.topLevelPropertyAccessor)
]);
}
void checkConstCycle(String className,
{String name: '', bool hasCycle: true}) {
UnlinkedClass cls = findClass(className);
int constCycleSlot =
findExecutable(name, executables: cls.executables).constCycleSlot;
expect(constCycleSlot, isNot(0));
if (!skipFullyLinkedData) {
expect(
definingUnit.constCycles,
hasCycle
? contains(constCycleSlot)
: isNot(contains(constCycleSlot)));
}
}
/**
* Verify that the [dependency]th element of the dependency table represents
* a file reachable via the given [absoluteUri].
*/
void checkDependency(int dependency, String absoluteUri) {
expect(dependency, new isInstanceOf<int>());
expect(linked.dependencies[dependency].uri, absoluteUri);
}
/**
* Verify that the given [dependency] lists the given
* [relativeUris] as its parts.
*/
void checkDependencyParts(
LinkedDependency dependency, List<String> relativeUris) {
expect(dependency.parts, relativeUris);
}
/**
* Check that the given [documentationComment] matches the first
* Javadoc-style comment found in [text].
*
* Note that the algorithm for finding the Javadoc-style comment in [text] is
* a simple-minded text search; it is easily confused by corner cases such as
* strings containing comments, nested comments, etc.
*/
void checkDocumentationComment(
UnlinkedDocumentationComment documentationComment, String text) {
expect(documentationComment, isNotNull);
int commentStart = text.indexOf('/*');
expect(commentStart, isNot(-1));
int commentEnd = text.indexOf('*/');
expect(commentEnd, isNot(-1));
commentEnd += 2;
String expectedCommentText =
text.substring(commentStart, commentEnd).replaceAll('\r\n', '\n');
expect(documentationComment.text, expectedCommentText);
}
/**
* Verify that the given [typeRef] represents the type `dynamic`.
*/
void checkDynamicTypeRef(EntityRef typeRef) {
checkTypeRef(typeRef, null, 'dynamic');
}
/**
* Verify that the given [exportName] represents a reference to an entity
* declared in a file reachable via [absoluteUri], having name [expectedName].
* [expectedKind] is the kind of object referenced. [expectedTargetUnit] is
* the index of the compilation unit in which the target of the [exportName]
* is expected to appear; if not specified it is assumed to be the defining
* compilation unit.
*/
void checkExportName(LinkedExportName exportName, String absoluteUri,
String expectedName, ReferenceKind expectedKind,
{int expectedTargetUnit: 0}) {
expect(exportName, new isInstanceOf<LinkedExportName>());
// Exported names must come from other libraries.
expect(exportName.dependency, isNot(0));
checkDependency(exportName.dependency, absoluteUri);
expect(exportName.name, expectedName);
expect(exportName.kind, expectedKind);
expect(exportName.unit, expectedTargetUnit);
}
/**
* Verify that the dependency table contains an entry for a file reachable
* via the given [relativeUri]. If [fullyLinked] is
* `true`, then the dependency should be a fully-linked dependency; otherwise
* it should be a prelinked dependency.
*
* The index of the [LinkedDependency] is returned.
*/
int checkHasDependency(String relativeUri, {bool fullyLinked: false}) {
List<String> found = <String>[];
for (int i = 0; i < linked.dependencies.length; i++) {
LinkedDependency dep = linked.dependencies[i];
if (dep.uri == relativeUri) {
if (fullyLinked) {
expect(i, greaterThanOrEqualTo(linked.numPrelinkedDependencies));
} else {
expect(i, lessThan(linked.numPrelinkedDependencies));
}
return i;
}
found.add(dep.uri);
}
fail('Did not find dependency $relativeUri. Found: $found');
}
/**
* Test an inferred type. If [onlyInStrongMode] is `true` (the default) and
* strong mode is disabled, verify that the given [slotId] exists and has no
* associated type. Otherwise, behave as in [checkLinkedTypeSlot].
*/
void checkInferredTypeSlot(
int slotId, String absoluteUri, String expectedName,
{int numTypeArguments: 0,
ReferenceKind expectedKind: ReferenceKind.classOrEnum,
int expectedTargetUnit: 0,
LinkedUnit linkedSourceUnit,
UnlinkedUnit unlinkedSourceUnit,
int numTypeParameters: 0,
bool onlyInStrongMode: true}) {
if (strongMode || !onlyInStrongMode) {
checkLinkedTypeSlot(slotId, absoluteUri, expectedName,
numTypeArguments: numTypeArguments,
expectedKind: expectedKind,
expectedTargetUnit: expectedTargetUnit,
linkedSourceUnit: linkedSourceUnit,
unlinkedSourceUnit: unlinkedSourceUnit,
numTypeParameters: numTypeParameters);
} else {
// A slot id should have been assigned but it should not be associated
// with any type.
expect(slotId, isNot(0));
expect(getTypeRefForSlot(slotId, linkedSourceUnit: linkedSourceUnit),
isNull);
}
}
/**
* Verify that the dependency table *does not* contain any entries for a file
* reachable via the given [relativeUri].
*/
void checkLacksDependency(String relativeUri) {
for (LinkedDependency dep in linked.dependencies) {
if (dep.uri == relativeUri) {
fail('Unexpected dependency found: $relativeUri');
}
}
}
/**
* Verify that the given [typeRef] represents the type `dynamic`.
*/
void checkLinkedDynamicTypeRef(EntityRef typeRef) {
checkLinkedTypeRef(typeRef, null, 'dynamic');
}
/**
* Verify that the given [typeRef] represents a reference to a type declared
* in a file reachable via [absoluteUri], having name [expectedName]. Verify
* that the number of type arguments is equal to [numTypeArguments].
* [expectedKind] is the kind of object referenced. [linkedSourceUnit] and
* [unlinkedSourceUnit] refer to the compilation unit within which the
* [typeRef] appears; if not specified they are assumed to refer to the
* defining compilation unit. [expectedTargetUnit] is the index of the
* compilation unit in which the target of the [typeRef] is expected to
* appear; if not specified it is assumed to be the defining compilation unit.
* [numTypeParameters] is the number of type parameters of the thing being
* referred to.
*/
void checkLinkedTypeRef(
EntityRef typeRef, String absoluteUri, String expectedName,
{int numTypeArguments: 0,
ReferenceKind expectedKind: ReferenceKind.classOrEnum,
int expectedTargetUnit: 0,
LinkedUnit linkedSourceUnit,
UnlinkedUnit unlinkedSourceUnit,
int numTypeParameters: 0}) {
linkedSourceUnit ??= definingUnit;
expect(typeRef, isNotNull,
reason: 'No entry in linkedSourceUnit.types matching slotId');
expect(typeRef.paramReference, 0);
int index = typeRef.reference;
expect(typeRef.typeArguments, hasLength(numTypeArguments));
checkReferenceIndex(index, absoluteUri, expectedName,
expectedKind: expectedKind,
expectedTargetUnit: expectedTargetUnit,
linkedSourceUnit: linkedSourceUnit,
unlinkedSourceUnit: unlinkedSourceUnit,
numTypeParameters: numTypeParameters);
}
/**
* Verify that the given [slotId] represents a reference to a type declared
* in a file reachable via [absoluteUri], having name [expectedName]. Verify
* that the number of type arguments is equal to [numTypeArguments].
* [expectedKind] is the kind of object referenced. [linkedSourceUnit] and
* [unlinkedSourceUnit] refer to the compilation unit within which the
* [typeRef] appears; if not specified they are assumed to refer to the
* defining compilation unit. [expectedTargetUnit] is the index of the
* compilation unit in which the target of the [typeRef] is expected to
* appear; if not specified it is assumed to be the defining compilation unit.
* [numTypeParameters] is the number of type parameters of the thing being
* referred to.
*/
void checkLinkedTypeSlot(int slotId, String absoluteUri, String expectedName,
{int numTypeArguments: 0,
ReferenceKind expectedKind: ReferenceKind.classOrEnum,
int expectedTargetUnit: 0,
LinkedUnit linkedSourceUnit,
UnlinkedUnit unlinkedSourceUnit,
int numTypeParameters: 0}) {
// Slot ids should be nonzero, since zero means "no associated slot".
expect(slotId, isNot(0));
if (skipFullyLinkedData) {
return;
}
linkedSourceUnit ??= definingUnit;
checkLinkedTypeRef(
getTypeRefForSlot(slotId, linkedSourceUnit: linkedSourceUnit),
absoluteUri,
expectedName,
numTypeArguments: numTypeArguments,
expectedKind: expectedKind,
expectedTargetUnit: expectedTargetUnit,
linkedSourceUnit: linkedSourceUnit,
unlinkedSourceUnit: unlinkedSourceUnit,
numTypeParameters: numTypeParameters);
}
/**
* Verify that the given [typeRef] represents a reference to a type parameter
* having the given [deBruijnIndex].
*/
void checkParamTypeRef(EntityRef typeRef, int deBruijnIndex) {
expect(typeRef, new isInstanceOf<EntityRef>());
expect(typeRef.reference, 0);
expect(typeRef.typeArguments, isEmpty);
expect(typeRef.paramReference, deBruijnIndex);
}
/**
* Verify that [prefixReference] is a valid reference to a prefix having the
* given [name].
*/
void checkPrefix(int prefixReference, String name) {
expect(prefixReference, isNot(0));
expect(unlinkedUnits[0].references[prefixReference].prefixReference, 0);
expect(unlinkedUnits[0].references[prefixReference].name, name);
expect(definingUnit.references[prefixReference].dependency, 0);
expect(definingUnit.references[prefixReference].kind, ReferenceKind.prefix);
expect(definingUnit.references[prefixReference].unit, 0);
}
/**
* Check the data structures that are reachable from an index in the
* references table. If the reference in question is an explicit
* reference, return the [UnlinkedReference] that is used to make the
* explicit reference. If the type reference in question is an implicit
* reference, return `null`.
*/
UnlinkedReference checkReferenceIndex(
int referenceIndex, String absoluteUri, String expectedName,
{ReferenceKind expectedKind: ReferenceKind.classOrEnum,
int expectedTargetUnit: 0,
LinkedUnit linkedSourceUnit,
UnlinkedUnit unlinkedSourceUnit,
int numTypeParameters: 0,
bool unresolvedHasName: false}) {
linkedSourceUnit ??= definingUnit;
unlinkedSourceUnit ??= unlinkedUnits[0];
LinkedReference referenceResolution =
linkedSourceUnit.references[referenceIndex];
String name;
UnlinkedReference reference;
if (referenceIndex < unlinkedSourceUnit.references.length) {
// This is an explicit reference, so its name and prefix should be in
// [UnlinkedUnit.references].
expect(referenceResolution.name, isEmpty);
reference = unlinkedSourceUnit.references[referenceIndex];
name = reference.name;
if (reference.prefixReference != 0) {
// Prefixes should appear in the references table before any reference
// that uses them.
expect(reference.prefixReference, lessThan(referenceIndex));
}
} else {
// This is an implicit reference, so its name should be in
// [LinkedUnit.references].
name = referenceResolution.name;
}
// Index 0 is reserved.
expect(referenceIndex, isNot(0));
if (absoluteUri == null) {
expect(referenceResolution.dependency, 0);
} else {
checkDependency(referenceResolution.dependency, absoluteUri);
}
if (expectedName == null) {
expect(name, isEmpty);
} else {
expect(name, expectedName);
}
expect(referenceResolution.kind, expectedKind);
expect(referenceResolution.unit, expectedTargetUnit);
expect(referenceResolution.numTypeParameters, numTypeParameters);
return reference;
}
/**
* Verify that the given [typeRef] represents a reference to a type declared
* in a file reachable via [absoluteUri], having name [expectedName].
* If [expectedPrefix] is supplied, verify that the type is reached via the
* given prefix. Verify that the number of type arguments is equal to
* [numTypeArguments]. [expectedKind] is the kind of object referenced.
* [linkedSourceUnit] and [unlinkedSourceUnit] refer to the compilation unit
* within which the [typeRef] appears; if not specified they are assumed to
* refer to the defining compilation unit. [expectedTargetUnit] is the index
* of the compilation unit in which the target of the [typeRef] is expected
* to appear; if not specified it is assumed to be the defining compilation
* unit. [numTypeParameters] is the number of type parameters of the thing
* being referred to.
*/
void checkTypeRef(EntityRef typeRef, String absoluteUri, String expectedName,
{String expectedPrefix,
List<_PrefixExpectation> prefixExpectations,
int numTypeArguments: 0,
ReferenceKind expectedKind: ReferenceKind.classOrEnum,
EntityRefKind entityKind: null,
int expectedTargetUnit: 0,
LinkedUnit linkedSourceUnit,
UnlinkedUnit unlinkedSourceUnit,
int numTypeParameters: 0,
bool unresolvedHasName: false}) {
linkedSourceUnit ??= definingUnit;
expect(typeRef, new isInstanceOf<EntityRef>());
expect(typeRef.paramReference, 0);
int index = typeRef.reference;
expect(typeRef.typeArguments, hasLength(numTypeArguments));
if (entityKind == EntityRefKind.genericFunctionType) {
// [GenericFunctionType]s don't have references to check.
return;
}
UnlinkedReference reference = checkReferenceIndex(
index, absoluteUri, expectedName,
expectedKind: expectedKind,
expectedTargetUnit: expectedTargetUnit,
linkedSourceUnit: linkedSourceUnit,
unlinkedSourceUnit: unlinkedSourceUnit,
numTypeParameters: numTypeParameters,
unresolvedHasName: unresolvedHasName);
expect(reference, isNotNull,
reason: 'Unlinked type refs must refer to an explicit reference');
if (expectedPrefix != null) {
checkPrefix(reference.prefixReference, expectedPrefix);
} else if (prefixExpectations != null) {
for (_PrefixExpectation expectation in prefixExpectations) {
expect(reference.prefixReference, isNot(0));
reference = checkReferenceIndex(reference.prefixReference,
expectation.absoluteUri, expectation.name,
expectedKind: expectation.kind,
expectedTargetUnit: expectedTargetUnit,
linkedSourceUnit: linkedSourceUnit,
unlinkedSourceUnit: unlinkedSourceUnit,
numTypeParameters: expectation.numTypeParameters);
}
expect(reference.prefixReference, 0);
} else {
expect(reference.prefixReference, 0);
}
}
/**
* Verify that the given [typeRef] represents a reference to an unresolved
* type.
*/
void checkUnresolvedTypeRef(
EntityRef typeRef, String expectedPrefix, String expectedName,
{LinkedUnit linkedSourceUnit, UnlinkedUnit unlinkedSourceUnit}) {
// When serializing from the element model, unresolved type refs lose their
// name.
checkTypeRef(typeRef, null, expectedName,
expectedPrefix: expectedPrefix,
expectedKind: ReferenceKind.unresolved,
linkedSourceUnit: linkedSourceUnit,
unlinkedSourceUnit: unlinkedSourceUnit);
}
/**
* Verify that the given [typeRef] represents the type `void`.
*/
void checkVoidTypeRef(EntityRef typeRef) {
checkTypeRef(typeRef, null, 'void');
}
fail_invalid_prefix_dynamic() {
// if (checkAstDerivedData) {
// // TODO(paulberry): get this to work properly.
// return;
// }
var t = serializeTypeText('dynamic.T', allowErrors: true);
checkUnresolvedTypeRef(t, 'dynamic', 'T');
}
fail_invalid_prefix_type_parameter() {
// if (checkAstDerivedData) {
// // TODO(paulberry): get this to work properly.
// return;
// }
checkUnresolvedTypeRef(
serializeClassText('class C<T> { T.U x; }', allowErrors: true)
.fields[0]
.type,
'T',
'U');
}
fail_invalid_prefix_void() {
// if (checkAstDerivedData) {
// // TODO(paulberry): get this to work properly.
// return;
// }
checkUnresolvedTypeRef(
serializeTypeText('void.T', allowErrors: true), 'void', 'T');
}
/**
* Find the class with the given [className] in the summary, and return its
* [UnlinkedClass] data structure. If [unit] is not given, the class is
* looked for in the defining compilation unit.
*/
UnlinkedClass findClass(String className,
{bool failIfAbsent: false, UnlinkedUnit unit}) {
unit ??= unlinkedUnits[0];
UnlinkedClass result;
for (UnlinkedClass cls in unit.classes) {
if (cls.name == className) {
if (result != null) {
fail('Duplicate class $className');
}
result = cls;
}
}
if (result == null && failIfAbsent) {
fail('Class $className not found in serialized output');
}
return result;
}
/**
* Find the enum with the given [enumName] in the summary, and return its
* [UnlinkedEnum] data structure. If [unit] is not given, the enum is looked
* for in the defining compilation unit.
*/
UnlinkedEnum findEnum(String enumName,
{bool failIfAbsent: false, UnlinkedUnit unit}) {
unit ??= unlinkedUnits[0];
UnlinkedEnum result;
for (UnlinkedEnum e in unit.enums) {
if (e.name == enumName) {
if (result != null) {
fail('Duplicate enum $enumName');
}
result = e;
}
}
if (result == null && failIfAbsent) {
fail('Enum $enumName not found in serialized output');
}
return result;
}
/**
* Find the executable with the given [executableName] in the summary, and
* return its [UnlinkedExecutable] data structure. If [executables] is not
* given, then the executable is searched for in the defining compilation
* unit.
*/
UnlinkedExecutable findExecutable(String executableName,
{List<UnlinkedExecutable> executables, bool failIfAbsent: false}) {
executables ??= unlinkedUnits[0].executables;
UnlinkedExecutable result;
for (UnlinkedExecutable executable in executables) {
if (executable.name == executableName) {
if (result != null) {
fail('Duplicate executable $executableName');
}
result = executable;
}
}
if (result == null && failIfAbsent) {
fail('Executable $executableName not found in serialized output');
}
return result;
}
/**
* Find the parameter with the given [name] in [parameters].
*/
UnlinkedParam findParameter(List<UnlinkedParam> parameters, String name) {
UnlinkedParam result;
for (UnlinkedParam parameter in parameters) {
if (parameter.name == name) {
if (result != null) {
fail('Duplicate parameter $name');
}
result = parameter;
}
}
if (result == null) {
fail('Parameter $name not found');
}
return result;
}
/**
* Find the typedef with the given [typedefName] in the summary, and return
* its [UnlinkedTypedef] data structure. If [unit] is not given, the typedef
* is looked for in the defining compilation unit.
*/
UnlinkedTypedef findTypedef(String typedefName,
{bool failIfAbsent: false, UnlinkedUnit unit}) {
unit ??= unlinkedUnits[0];
UnlinkedTypedef result;
for (UnlinkedTypedef type in unit.typedefs) {
if (type.name == typedefName) {
if (result != null) {
fail('Duplicate typedef $typedefName');
}
result = type;
}
}
if (result == null && failIfAbsent) {
fail('Typedef $typedefName not found in serialized output');
}
return result;
}
/**
* Find the top level variable with the given [variableName] in the summary,
* and return its [UnlinkedVariable] data structure. If [variables] is not
* specified, the variable is looked for in the defining compilation unit.
*/
UnlinkedVariable findVariable(String variableName,
{List<UnlinkedVariable> variables, bool failIfAbsent: false}) {
variables ??= unlinkedUnits[0].variables;
UnlinkedVariable result;
for (UnlinkedVariable variable in variables) {
if (variable.name == variableName) {
if (result != null) {
fail('Duplicate variable $variableName');
}
result = variable;
}
}
if (result == null && failIfAbsent) {
fail('Variable $variableName not found in serialized output');
}
return result;
}
/**
* Find the entry in [linkedSourceUnit.types] matching [slotId].
*/
EntityRef getTypeRefForSlot(int slotId, {LinkedUnit linkedSourceUnit}) {
linkedSourceUnit ??= definingUnit;
for (EntityRef typeRef in linkedSourceUnit.types) {
if (typeRef.slot == slotId) {
return typeRef;
}
}
return null;
}
/**
* Serialize the given library [text] and return the summary of the class
* with the given [className].
*/
UnlinkedClass serializeClassText(String text,
{String className: 'C', bool allowErrors: false}) {
serializeLibraryText(text, allowErrors: allowErrors);
return findClass(className, failIfAbsent: true);
}
/**
* Serialize the given library [text] and return the summary of the enum with
* the given [enumName].
*/
UnlinkedEnum serializeEnumText(String text, [String enumName = 'E']) {
serializeLibraryText(text);
return findEnum(enumName, failIfAbsent: true);
}
/**
* Serialize the given library [text] and return the summary of the
* executable with the given [executableName].
*/
UnlinkedExecutable serializeExecutableText(String text,
{String executableName: 'f', bool allowErrors: false}) {
serializeLibraryText(text, allowErrors: allowErrors);
return findExecutable(executableName, failIfAbsent: true);
}
/**
* Serialize the given library [text], then deserialize it and store its
* summary in [lib].
*/
void serializeLibraryText(String text, {bool allowErrors: false});
/**
* Serialize the given method [text] and return the summary of the executable
* with the given [executableName].
*/
UnlinkedExecutable serializeMethodText(String text,
[String executableName = 'f']) {
serializeLibraryText('class C { $text }');
return findExecutable(executableName,
executables: findClass('C', failIfAbsent: true).executables,
failIfAbsent: true);
}
/**
* Serialize the given library [text] and return the summary of the typedef
* with the given [typedefName].
*/
UnlinkedTypedef serializeTypedefText(String text,
[String typedefName = 'F']) {
serializeLibraryText(text);
return findTypedef(typedefName, failIfAbsent: true);
}
/**
* Serialize a type declaration using the given [text] as a type name, and
* return a summary of the corresponding [EntityRef]. If the type
* declaration needs to refer to types that are not available in core, those
* types may be declared in [otherDeclarations].
*/
EntityRef serializeTypeText(String text,
{String otherDeclarations: '', bool allowErrors: false}) {
return serializeVariableText('$otherDeclarations\n$text v;',
allowErrors: allowErrors)
.type;
}
/**
* Serialize the given library [text] and return the summary of the variable
* with the given [variableName].
*/
UnlinkedVariable serializeVariableText(String text,
{String variableName: 'v', bool allowErrors: false}) {
serializeLibraryText(text, allowErrors: allowErrors);
return findVariable(variableName, failIfAbsent: true);
}
test_apiSignature() {
List<int> signature1;
List<int> signature2;
List<int> signature3;
{
serializeLibraryText('class A {}');
signature1 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText('class A { }');
signature2 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText('class B {}');
signature3 = unlinkedUnits[0].apiSignature;
}
expect(signature2, signature1);
expect(signature3, isNot(signature1));
}
test_apiSignature_excludeBody_constructor() {
List<int> signature1;
List<int> signature2;
List<int> signature3;
{
serializeLibraryText(r'''
class A {
A() {
}
}
''');
signature1 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText(r'''
class A {
A() {
int v1;
f() {
double v2;
}
}
}
''');
signature2 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText(r'''
class A {
A(int p) {
}
}
''');
}
expect(signature2, signature1);
expect(signature3, isNot(signature1));
}
test_apiSignature_excludeBody_method() {
List<int> signature1;
List<int> signature2;
List<int> signature3;
{
serializeLibraryText(r'''
class A {
m() {
}
}
''');
signature1 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText(r'''
class A {
m() {
int v1;
f() {
double v2;
}
}
}
''');
signature2 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText(r'''
class A {
m(p) {
}
}
''');
}
expect(signature2, signature1);
expect(signature3, isNot(signature1));
}
test_apiSignature_excludeBody_topLevelFunction() {
List<int> signature1;
List<int> signature2;
List<int> signature3;
{
serializeLibraryText('main() {}');
signature1 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText(r'''
main() {
int v1 = 1;
f() {
int v2 = 2;
}
}
''');
signature2 = unlinkedUnits[0].apiSignature;
}
{
serializeLibraryText('main(p) {}');
signature3 = unlinkedUnits[0].apiSignature;
}
expect(signature2, signature1);
expect(signature3, isNot(signature1));
}
test_bottom_reference_shared() {
if (skipFullyLinkedData) {
return;
}
// The synthetic executables for both `x` and `y` have type `() => `Bottom`.
// Verify that they both use the same reference to `Bottom`.
serializeLibraryText('int x = null; int y = null;');
EntityRef xInitializerReturnType =
getTypeRefForSlot(findVariable('x').initializer.inferredReturnTypeSlot);
EntityRef yInitializerReturnType =
getTypeRefForSlot(findVariable('y').initializer.inferredReturnTypeSlot);
expect(xInitializerReturnType.reference, yInitializerReturnType.reference);
}
test_cascaded_export_hide_hide() {
addNamedSource('/lib1.dart', 'export "lib2.dart" hide C hide B, C;');
addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib1.dart';
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib2.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_export_hide_show() {
addNamedSource('/lib1.dart', 'export "lib2.dart" hide C show A, C;');
addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib1.dart';
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib2.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_export_show_hide() {
addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B hide B, C;');
addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib1.dart';
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib2.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_export_show_show() {
addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B show A, C;');
addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib1.dart';
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib2.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_import_hide_hide() {
addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib.dart' hide C hide B, C;
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_import_hide_show() {
addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib.dart' hide C show A, C;
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_import_show_hide() {
addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib.dart' show A, B hide B, C;
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_cascaded_import_show_show() {
addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
serializeLibraryText('''
import 'lib.dart' show A, B show A, C;
A a;
B b;
C c;
''', allowErrors: true);
checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'A');
checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
}
test_class_abstract() {
UnlinkedClass cls = serializeClassText('abstract class C {}');
expect(cls.isAbstract, true);
}
test_class_alias_abstract() {
UnlinkedClass cls = serializeClassText(
'abstract class C = D with E; class D {} class E {}');
expect(cls.isAbstract, true);
}
test_class_alias_concrete() {
UnlinkedClass cls =
serializeClassText('class C = _D with _E; class _D {} class _E {}');
expect(cls.isAbstract, false);
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
ReferenceKind.classOrEnum);
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
}
test_class_alias_documented() {
if (!includeInformative) return;
String text = '''
// Extra comment so doc comment offset != 0
/**
* Docs
*/
class C = D with E;
class D {}
class E {}''';
UnlinkedClass cls = serializeClassText(text);
expect(cls.documentationComment, isNotNull);
checkDocumentationComment(cls.documentationComment, text);
}
test_class_alias_flag() {
UnlinkedClass cls =
serializeClassText('class C = D with E; class D {} class E {}');
expect(cls.isMixinApplication, true);
}
test_class_alias_generic() {
serializeClassText('class C<A, B> = _D with _E; class _D {} class _E {}');
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 2);
}
test_class_alias_mixin_order() {
UnlinkedClass cls = serializeClassText('''
class C = D with E, F;
class D {}
class E {}
class F {}
''');
expect(cls.mixins, hasLength(2));
checkTypeRef(cls.mixins[0], null, 'E');
checkTypeRef(cls.mixins[1], null, 'F');
}
test_class_alias_no_implicit_constructors() {
UnlinkedClass cls = serializeClassText('''
class C = D with E;
class D {
D.foo();
D.bar();
}
class E {}
''');
expect(cls.executables, isEmpty);
}
test_class_alias_private() {
serializeClassText('class _C = _D with _E; class _D {} class _E {}',
className: '_C');
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
}
test_class_alias_reference_generic() {
EntityRef typeRef = serializeTypeText('C',
otherDeclarations: 'class C<D, E> = F with G; class F {} class G {}');
checkTypeRef(typeRef, null, 'C', numTypeParameters: 2);
}
test_class_alias_reference_generic_imported() {
addNamedSource(
'/lib.dart', 'class C<D, E> = F with G; class F {} class G {}');
EntityRef typeRef =
serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
checkTypeRef(typeRef, absUri('/lib.dart'), 'C', numTypeParameters: 2);
}
test_class_alias_supertype() {
UnlinkedClass cls =
serializeClassText('class C = D with E; class D {} class E {}');
checkTypeRef(cls.supertype, null, 'D');
expect(cls.hasNoSupertype, isFalse);
}
test_class_codeRange() {
if (!includeInformative) return;
UnlinkedClass cls = serializeClassText(' class C {}');
_assertCodeRange(cls.codeRange, 1, 10);
}
test_class_concrete() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.isAbstract, false);
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
ReferenceKind.classOrEnum);
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
}
test_class_constMembers() {
UnlinkedClass cls = serializeClassText('''
class C {
int fieldInstance = 0;
final int fieldInstanceFinal = 0;
static int fieldStatic = 0;
static final int fieldStaticFinal = 0;
static const int fieldStaticConst = 0;
static const int _fieldStaticConstPrivate = 0;
static void methodStaticPublic() {}
static void _methodStaticPrivate() {}
void methodInstancePublic() {}
C operator+(C c) => null;
}
''');
expect(cls.isAbstract, false);
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
UnlinkedPublicName className = unlinkedUnits[0].publicNamespace.names[0];
expect(className.kind, ReferenceKind.classOrEnum);
expect(className.name, 'C');
expect(className.numTypeParameters, 0);
// executables
Map<String, UnlinkedPublicName> executablesMap =
<String, UnlinkedPublicName>{};
className.members.forEach((e) => executablesMap[e.name] = e);
expect(executablesMap, hasLength(4));
Map<String, ReferenceKind> expectedExecutableKinds =
<String, ReferenceKind>{
'fieldStaticConst': ReferenceKind.propertyAccessor,
'fieldStaticFinal': ReferenceKind.propertyAccessor,
'fieldStatic': ReferenceKind.propertyAccessor,
'methodStaticPublic': ReferenceKind.method,
};
expectedExecutableKinds.forEach((String name, ReferenceKind expectedKind) {
UnlinkedPublicName executable = executablesMap[name];
expect(executable.kind, expectedKind);
expect(executable.members, isEmpty);
});
}
test_class_constMembers_constructors() {
UnlinkedClass cls = serializeClassText('''
class C {
const C();
const C.constructorNamedPublicConst();
C.constructorNamedPublic();
C._constructorNamedPrivate();
}
''');
expect(cls.isAbstract, false);
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
UnlinkedPublicName className = unlinkedUnits[0].publicNamespace.names[0];
expect(className.kind, ReferenceKind.classOrEnum);
expect(className.name, 'C');
expect(className.numTypeParameters, 0);
// executables
Map<String, UnlinkedPublicName> executablesMap =
<String, UnlinkedPublicName>{};
className.members.forEach((e) => executablesMap[e.name] = e);
expect(executablesMap, hasLength(2));
{
UnlinkedPublicName executable =
executablesMap['constructorNamedPublicConst'];
expect(executable.kind, ReferenceKind.constructor);
expect(executable.members, isEmpty);
}
{
UnlinkedPublicName executable = executablesMap['constructorNamedPublic'];
expect(executable.kind, ReferenceKind.constructor);
expect(executable.members, isEmpty);
}
}
test_class_documented() {
if (!includeInformative) return;
String text = '''
// Extra comment so doc comment offset != 0
/**
* Docs
*/
class C {}''';
UnlinkedClass cls = serializeClassText(text);
expect(cls.documentationComment, isNotNull);
checkDocumentationComment(cls.documentationComment, text);
}
test_class_documented_tripleSlash() {
if (!includeInformative) return;
String text = '''
/// aaa
/// bbbb
/// cc
class C {}''';
UnlinkedClass cls = serializeClassText(text);
UnlinkedDocumentationComment comment = cls.documentationComment;
expect(comment, isNotNull);
expect(comment.text, '/// aaa\n/// bbbb\n/// cc');
}
test_class_documented_with_references() {
if (!includeInformative) return;
String text = '''
// Extra comment so doc comment offset != 0
/**
* Docs referring to [D] and [E]
*/
class C {}
class D {}
class E {}''';
UnlinkedClass cls = serializeClassText(text);
expect(cls.documentationComment, isNotNull);
checkDocumentationComment(cls.documentationComment, text);
}
test_class_documented_with_with_windows_line_endings() {
if (!includeInformative) return;
String text = '/**\r\n * Docs\r\n */\r\nclass C {}';
UnlinkedClass cls = serializeClassText(text);
expect(cls.documentationComment, isNotNull);
checkDocumentationComment(cls.documentationComment, text);
}
test_class_interface() {
UnlinkedClass cls = serializeClassText('''
class C implements D {}
class D {}
''');
expect(cls.interfaces, hasLength(1));
checkTypeRef(cls.interfaces[0], null, 'D');
}
test_class_interface_order() {
UnlinkedClass cls = serializeClassText('''
class C implements D, E {}
class D {}
class E {}
''');
expect(cls.interfaces, hasLength(2));
checkTypeRef(cls.interfaces[0], null, 'D');
checkTypeRef(cls.interfaces[1], null, 'E');
}
test_class_mixin() {
UnlinkedClass cls = serializeClassText('''
class C extends Object with D {}
class D {}
''');
expect(cls.mixins, hasLength(1));
checkTypeRef(cls.mixins[0], null, 'D');
}
test_class_mixin_order() {
UnlinkedClass cls = serializeClassText('''
class C extends Object with D, E {}
class D {}
class E {}
''');
expect(cls.mixins, hasLength(2));
checkTypeRef(cls.mixins[0], null, 'D');
checkTypeRef(cls.mixins[1], null, 'E');
}
test_class_name() {
var classText = 'class C {}';
UnlinkedClass cls = serializeClassText(classText);
expect(cls.name, 'C');
if (includeInformative) {
expect(cls.nameOffset, classText.indexOf('C'));
}
}
test_class_no_flags() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.isAbstract, false);
expect(cls.isMixinApplication, false);
}
test_class_no_interface() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.interfaces, isEmpty);
}
test_class_no_mixins() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.mixins, isEmpty);
}
test_class_no_type_param() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.typeParameters, isEmpty);
}
test_class_non_alias_flag() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.isMixinApplication, false);
}
test_class_private() {
serializeClassText('class _C {}', className: '_C');
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
}
test_class_reference_generic() {
EntityRef typeRef =
serializeTypeText('C', otherDeclarations: 'class C<D, E> {}');
checkTypeRef(typeRef, null, 'C', numTypeParameters: 2);
}
test_class_reference_generic_imported() {
addNamedSource('/lib.dart', 'class C<D, E> {}');
EntityRef typeRef =
serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
checkTypeRef(typeRef, absUri('/lib.dart'), 'C', numTypeParameters: 2);
}
test_class_superclass() {
UnlinkedClass cls = serializeClassText('class C {}');
expect(cls.supertype, isNull);
expect(cls.hasNoSupertype, isFalse);
}
test_class_superclass_explicit() {
UnlinkedClass cls = serializeClassText('class C extends D {} class D {}');
expect(cls.supertype, isNotNull);
checkTypeRef(cls.supertype, null, 'D');
expect(cls.hasNoSupertype, isFalse);
}
test_class_type_param_bound() {
UnlinkedClass cls = serializeClassText('class C<T extends List> {}');
expect(cls.typeParameters, hasLength(1));
{
UnlinkedTypeParam typeParameter = cls.typeParameters[0];
expect(typeParameter.name, 'T');
expect(typeParameter.bound, isNotNull);
checkTypeRef(typeParameter.bound, 'dart:core', 'List',
numTypeParameters: 1);
}
}
test_class_type_param_f_bound() {
UnlinkedClass cls = serializeClassText('class C<T, U extends List<T>> {}');
EntityRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
checkParamTypeRef(typeArgument, 2);
}
test_class_type_param_f_bound_self_ref() {
UnlinkedClass cls = serializeClassText('class C<T, U extends List<U>> {}');
EntityRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
checkParamTypeRef(typeArgument, 1);
}
test_class_type_param_no_bound() {
String text = 'class C<T> {}';
UnlinkedClass cls = serializeClassText(text);
expect(cls.typeParameters, hasLength(1));
expect(cls.typeParameters[0].name, 'T');
if (includeInformative) {
expect(cls.typeParameters[0].nameOffset, text.indexOf('T'));
}
expect(cls.typeParameters[0].bound, isNull);
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
}
test_closure_executable_with_bottom_return_type() {
UnlinkedVariable variable = serializeVariableText('var v = (() => null);');
UnlinkedExecutable closure;
{
UnlinkedExecutable executable = variable.initializer;
expect(executable.localFunctions, hasLength(1));
expect(executable.localFunctions[0].returnType, isNull);
closure = executable.localFunctions[0];
}
if (strongMode) {
// Strong mode infers a type for the closure of `() => Null`.
checkInferredTypeSlot(
closure.inferredReturnTypeSlot, 'dart:core', 'Null');
} else {
// Spec mode infers a type for the closure of `() => Bottom`.
checkInferredTypeSlot(closure.inferredReturnTypeSlot, null, '*bottom*',
onlyInStrongMode: false);
}
}
test_closure_executable_with_imported_return_type() {
addNamedSource('/a.dart', 'class C { D d; } class D {}');
// The closure has type `() => D`; `D` is defined in a library that is
// imported.
UnlinkedExecutable executable = serializeVariableText(r'''
import "a.dart";
var v = (() {
print((() => new C().d)());
});
''').initializer.localFunctions[0];
expect(executable.localFunctions, hasLength(1));
expect(executable.localFunctions[0].returnType, isNull);
checkInferredTypeSlot(executable.localFunctions[0].inferredReturnTypeSlot,
absUri('/a.dart'), 'D',
onlyInStrongMode: false);
checkHasDependency(absUri('/a.dart'), fullyLinked: false);
}
test_closure_executable_with_return_type_from_closure() {
if (skipFullyLinkedData) {
return;
}
// The closure has type `() => () => int`, where the `() => int` part refers
// to the nested closure.
UnlinkedExecutable executable = serializeExecutableText('''
f() {
print(() {}); // force the closure below to have index 1
print(() => () => 0);
}
''');
expect(executable.localFunctions, hasLength(2));
EntityRef closureType =
getTypeRefForSlot(executable.localFunctions[1].inferredReturnTypeSlot);
checkLinkedTypeRef(closureType, null, '',
expectedKind: ReferenceKind.function);
int outerClosureIndex =
definingUnit.references[closureType.reference].containingReference;
checkReferenceIndex(outerClosureIndex, null, '',
expectedKind: ReferenceKind.function);
int topLevelFunctionIndex =
definingUnit.references[outerClosureIndex].containingReference;
checkReferenceIndex(topLevelFunctionIndex, null, 'f',
expectedKind: ReferenceKind.topLevelFunction);
expect(
definingUnit.references[topLevelFunctionIndex].containingReference, 0);
}
test_closure_executable_with_unimported_return_type() {
addNamedSource('/a.dart', 'import "b.dart"; class C { D d; }');
addNamedSource('/b.dart', 'class D {}');
// The closure has type `() => D`; `D` is defined in a library that is not
// imported.
UnlinkedExecutable executable = serializeVariableText(r'''
import "a.dart";
var v = (() {
print((() => new C().d)());
});
''').initializer.localFunctions[0];
expect(executable.localFunctions, hasLength(1));
expect(executable.localFunctions[0].returnType, isNull);
checkInferredTypeSlot(executable.localFunctions[0].inferredReturnTypeSlot,
absUri('/b.dart'), 'D',
onlyInStrongMode: false);
if (!skipFullyLinkedData) {
checkHasDependency('b.dart', fullyLinked: true);
}
}
test_constExpr_binary_add() {
UnlinkedVariable variable = serializeVariableText('const v = 1 + 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.add
], ints: [
1,
2
]);
}
test_constExpr_binary_and() {
UnlinkedVariable variable =
serializeVariableText('const v = true && false;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushTrue,
UnlinkedExprOperation.pushFalse,
UnlinkedExprOperation.and
]);
}
test_constExpr_binary_bitAnd() {
UnlinkedVariable variable = serializeVariableText('const v = 1 & 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.bitAnd
], ints: [
1,
2
]);
}
test_constExpr_binary_bitOr() {
UnlinkedVariable variable = serializeVariableText('const v = 1 | 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.bitOr
], ints: [
1,
2
]);
}
test_constExpr_binary_bitShiftLeft() {
UnlinkedVariable variable = serializeVariableText('const v = 1 << 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.bitShiftLeft
], ints: [
1,
2
]);
}
test_constExpr_binary_bitShiftRight() {
UnlinkedVariable variable = serializeVariableText('const v = 1 >> 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.bitShiftRight
], ints: [
1,
2
]);
}
test_constExpr_binary_bitXor() {
UnlinkedVariable variable = serializeVariableText('const v = 1 ^ 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.bitXor
], ints: [
1,
2
]);
}
test_constExpr_binary_divide() {
UnlinkedVariable variable = serializeVariableText('const v = 1 / 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.divide
], ints: [
1,
2
]);
}
test_constExpr_binary_equal() {
UnlinkedVariable variable = serializeVariableText('const v = 1 == 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.equal
], ints: [
1,
2
]);
}
test_constExpr_binary_equal_not() {
UnlinkedVariable variable = serializeVariableText('const v = 1 != 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.notEqual
], ints: [
1,
2
]);
}
test_constExpr_binary_floorDivide() {
UnlinkedVariable variable = serializeVariableText('const v = 1 ~/ 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.floorDivide
], ints: [
1,
2
]);
}
test_constExpr_binary_greater() {
UnlinkedVariable variable = serializeVariableText('const v = 1 > 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.greater
], ints: [
1,
2
]);
}
test_constExpr_binary_greaterEqual() {
UnlinkedVariable variable = serializeVariableText('const v = 1 >= 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.greaterEqual
], ints: [
1,
2
]);
}
test_constExpr_binary_less() {
UnlinkedVariable variable = serializeVariableText('const v = 1 < 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.less
], ints: [
1,
2
]);
}
test_constExpr_binary_lessEqual() {
UnlinkedVariable variable = serializeVariableText('const v = 1 <= 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.lessEqual
], ints: [
1,
2
]);
}
test_constExpr_binary_modulo() {
UnlinkedVariable variable = serializeVariableText('const v = 1 % 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.modulo
], ints: [
1,
2
]);
}
test_constExpr_binary_multiply() {
UnlinkedVariable variable = serializeVariableText('const v = 1 * 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.multiply
], ints: [
1,
2
]);
}
test_constExpr_binary_or() {
UnlinkedVariable variable =
serializeVariableText('const v = false || true;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushFalse,
UnlinkedExprOperation.pushTrue,
UnlinkedExprOperation.or
]);
}
test_constExpr_binary_qq() {
UnlinkedVariable variable = serializeVariableText('const v = 1 ?? 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.ifNull
], ints: [
1,
2
]);
}
test_constExpr_binary_subtract() {
UnlinkedVariable variable = serializeVariableText('const v = 1 - 2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.subtract
], ints: [
1,
2
]);
}
test_constExpr_classMember_shadows_typeParam() {
// Although it is an error for a class member to have the same name as a
// type parameter, the spec makes it clear that the class member scope is
// nested inside the type parameter scope. So go ahead and verify that
// the class member shadows the type parameter.
String text = '''
class C<T> {
static const T = null;
final x;
const C() : x = T;
}
''';
UnlinkedClass cls = serializeClassText(text, allowErrors: true);
assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
operators: [
UnlinkedExprOperation.pushReference
],
referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'T',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
numTypeParameters: 1)
])
]);
}
test_constExpr_conditional() {
UnlinkedVariable variable =
serializeVariableText('const v = true ? 1 : 2;', allowErrors: true);
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushTrue,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.conditional
], ints: [
1,
2
]);
}
test_constExpr_constructorParam_shadows_classMember() {
UnlinkedClass cls = serializeClassText('''
class C {
static const a = null;
final b;
const C(a) : b = a;
}
''');
assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
operators: [UnlinkedExprOperation.pushParameter], strings: ['a']);
}
test_constExpr_constructorParam_shadows_typeParam() {
UnlinkedClass cls = serializeClassText('''
class C<T> {
final x;
const C(T) : x = T;
}
''');
assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
operators: [UnlinkedExprOperation.pushParameter], strings: ['T']);
}
test_constExpr_functionExpression() {
if (skipNonConstInitializers) {
return;
}
UnlinkedVariable variable = serializeVariableText('''
import 'dart:async';
const v = (f) async => await f;
''');
assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
isValidConst: false,
operators: [
UnlinkedExprOperation.pushParameter,
UnlinkedExprOperation.await
],
strings: [
'f'
],
ints: []);
}
test_constExpr_functionExpression_asArgument() {
// Even though function expressions are not allowed in constant
// declarations, they might occur due to erroneous code, so make sure they
// function correctly.
UnlinkedVariable variable = serializeVariableText('''
const v = foo(5, () => 42);
foo(a, b) {}
''');
assertUnlinkedConst(variable.initializer.bodyExpr,
isValidConst: false,
operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushLocalFunctionReference,
UnlinkedExprOperation.invokeMethodRef
],
ints: [
5,
0,
0,
0,
2,
0
],
referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'foo',
expectedKind: ReferenceKind.topLevelFunction)
]);
}
test_constExpr_functionExpression_asArgument_multiple() {
// Even though function expressions are not allowed in constant
// declarations, they might occur due to erroneous code, so make sure they
// function correctly.
UnlinkedVariable variable = serializeVariableText('''
const v = foo(5, () => 42, () => 43);
foo(a, b, c) {}
''');
assertUnlinkedConst(variable.initializer.bodyExpr,
isValidConst: false,
operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushLocalFunctionReference,
UnlinkedExprOperation.pushLocalFunctionReference,
UnlinkedExprOperation.invokeMethodRef
],
ints: [
5,
0,
0,
0,
1,
0,
3,
0
],
referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'foo',
expectedKind: ReferenceKind.topLevelFunction)
]);
}
test_constExpr_functionExpression_inConstructorInitializers() {
// Even though function expressions are not allowed in constant
// declarations, they might occur due to erroneous code, so make sure they
// function correctly.
UnlinkedExecutable executable = serializeClassText('''
class C {
final x, y;
const C() : x = (() => 42), y = (() => 43);
}
''').executables[0];
expect(executable.localFunctions, hasLength(2));
assertUnlinkedConst(executable.constantInitializers[0].expression,
isValidConst: false,
operators: [UnlinkedExprOperation.pushLocalFunctionReference],
ints: [0, 0]);
assertUnlinkedConst(executable.constantInitializers[1].expression,
isValidConst: false,
operators: [UnlinkedExprOperation.pushLocalFunctionReference],
ints: [0, 1]);
}
test_constExpr_invokeConstructor_generic_named() {
UnlinkedVariable variable = serializeVariableText('''
class C<K, V> {
const C.named();
}
const v = const C<int, String>.named();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, null, 'named',
expectedKind: ReferenceKind.constructor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
numTypeParameters: 2)
],
numTypeArguments: 2);
checkTypeRef(r.typeArguments[0], 'dart:core', 'int');
checkTypeRef(r.typeArguments[1], 'dart:core', 'String');
}
]);
}
test_constExpr_invokeConstructor_generic_named_imported() {
addNamedSource('/a.dart', '''
class C<K, V> {
const C.named();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = const C<int, String>.named();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, null, 'named',
expectedKind: ReferenceKind.constructor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart'), numTypeParameters: 2)
],
numTypeArguments: 2);
checkTypeRef(r.typeArguments[0], 'dart:core', 'int');
checkTypeRef(r.typeArguments[1], 'dart:core', 'String');
}
]);
}
test_constExpr_invokeConstructor_generic_named_imported_withPrefix() {
addNamedSource('/a.dart', '''
class C<K, V> {
const C.named();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = const p.C<int, String>.named();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, null, 'named',
expectedKind: ReferenceKind.constructor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart'), numTypeParameters: 2),
new _PrefixExpectation(ReferenceKind.prefix, 'p')
],
numTypeArguments: 2);
checkTypeRef(r.typeArguments[0], 'dart:core', 'int');
checkTypeRef(r.typeArguments[1], 'dart:core', 'String');
}
]);
}
test_constExpr_invokeConstructor_generic_unnamed() {
UnlinkedVariable variable = serializeVariableText('''
class C<K, V> {
const C();
}
const v = const C<int, String>();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, null, 'C',
expectedKind: ReferenceKind.classOrEnum,
numTypeParameters: 2,
numTypeArguments: 2);
checkTypeRef(r.typeArguments[0], 'dart:core', 'int');
checkTypeRef(r.typeArguments[1], 'dart:core', 'String');
}
]);
}
test_constExpr_invokeConstructor_generic_unnamed_imported() {
addNamedSource('/a.dart', '''
class C<K, V> {
const C();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = const C<int, String>();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, absUri('/a.dart'), 'C',
expectedKind: ReferenceKind.classOrEnum,
numTypeParameters: 2,
numTypeArguments: 2);
checkTypeRef(r.typeArguments[0], 'dart:core', 'int');
checkTypeRef(r.typeArguments[1], 'dart:core', 'String');
}
]);
}
test_constExpr_invokeConstructor_generic_unnamed_imported_withPrefix() {
addNamedSource('/a.dart', '''
class C<K, V> {
const C();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = const p.C<int, String>();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, absUri('/a.dart'), 'C',
expectedKind: ReferenceKind.classOrEnum,
numTypeParameters: 2,
numTypeArguments: 2,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.prefix, 'p')
]);
checkTypeRef(r.typeArguments[0], 'dart:core', 'int');
checkTypeRef(r.typeArguments[1], 'dart:core', 'String');
}
]);
}
test_constExpr_invokeConstructor_named() {
UnlinkedVariable variable = serializeVariableText('''
class C {
const C.named();
}
const v = const C.named();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'named',
expectedKind: ReferenceKind.constructor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_invokeConstructor_named_imported() {
addNamedSource('/a.dart', '''
class C {
const C.named();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = const C.named();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'named',
expectedKind: ReferenceKind.constructor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart'))
])
]);
}
test_constExpr_invokeConstructor_named_imported_withPrefix() {
addNamedSource('/a.dart', '''
class C {
const C.named();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = const p.C.named();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'named',
expectedKind: ReferenceKind.constructor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart')),
new _PrefixExpectation(ReferenceKind.prefix, 'p')
])
]);
}
test_constExpr_invokeConstructor_unnamed() {
UnlinkedVariable variable = serializeVariableText('''
class C {
const C(a, b, c, d, {e, f, g});
}
const v = const C(11, 22, 3.3, '444', e: 55, g: '777', f: 66);
''');
// Stack: 11 22 3.3 '444' 55 '777' 66 ^head
// Ints: ^pointer 3 4
// Doubles: ^pointer
// Strings: ^pointer 'e' 'g' 'f' ''
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushDouble,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.invokeConstructor,
], ints: [
11,
22,
55,
66,
3,
4,
], doubles: [
3.3
], strings: [
'444',
'777',
'e',
'g',
'f'
], referenceValidators: [
(EntityRef r) =>
checkTypeRef(r, null, 'C', expectedKind: ReferenceKind.classOrEnum)
]);
}
test_constExpr_invokeConstructor_unnamed_imported() {
addNamedSource('/a.dart', '''
class C {
const C();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = const C();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'C',
expectedKind: ReferenceKind.classOrEnum)
]);
}
test_constExpr_invokeConstructor_unnamed_imported_withPrefix() {
addNamedSource('/a.dart', '''
class C {
const C();
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = const p.C();
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'C',
expectedKind: ReferenceKind.classOrEnum,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.prefix, 'p')
])
]);
}
test_constExpr_invokeConstructor_unresolved_named() {
UnlinkedVariable variable = serializeVariableText('''
class C {}
const v = const C.foo();
''', allowErrors: true);
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'foo',
expectedKind: ReferenceKind.unresolved,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_invokeConstructor_unresolved_named2() {
UnlinkedVariable variable = serializeVariableText('''
const v = const C.foo();
''', allowErrors: true);
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'foo',
expectedKind: ReferenceKind.unresolved,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.unresolved, 'C')
])
]);
}
test_constExpr_invokeConstructor_unresolved_named_prefixed() {
addNamedSource('/a.dart', '''
class C {
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = const p.C.foo();
''', allowErrors: true);
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'foo',
expectedKind: ReferenceKind.unresolved,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart')),
new _PrefixExpectation(ReferenceKind.prefix, 'p')
])
]);
}
test_constExpr_invokeConstructor_unresolved_named_prefixed2() {
addNamedSource('/a.dart', '');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = const p.C.foo();
''', allowErrors: true);
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'foo',
expectedKind: ReferenceKind.unresolved,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.unresolved, 'C'),
new _PrefixExpectation(ReferenceKind.prefix, 'p')
])
]);
}
test_constExpr_invokeConstructor_unresolved_unnamed() {
UnlinkedVariable variable = serializeVariableText('''
const v = const Foo();
''', allowErrors: true);
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.invokeConstructor,
], ints: [
0,
0
], referenceValidators: [
(EntityRef r) =>
checkTypeRef(r, null, 'Foo', expectedKind: ReferenceKind.unresolved)
]);
}
test_constExpr_invokeMethodRef_identical() {
UnlinkedVariable variable =
serializeVariableText('const v = identical(42, null);');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushNull,
UnlinkedExprOperation.invokeMethodRef
], ints: [
42,
0,
2,
0
], referenceValidators: [
(EntityRef r) {
checkTypeRef(r, 'dart:core', 'identical',
expectedKind: ReferenceKind.topLevelFunction);
}
]);
}
test_constExpr_length_classConstField() {
UnlinkedVariable variable = serializeVariableText('''
class C {
static const int length = 0;
}
const int v = C.length;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'length',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_length_classConstField_imported_withPrefix() {
addNamedSource('/a.dart', '''
class C {
static const int length = 0;
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const int v = p.C.length;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'length',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart')),
new _PrefixExpectation(ReferenceKind.prefix, 'p')
])
]);
}
test_constExpr_length_identifierTarget() {
UnlinkedVariable variable = serializeVariableText('''
const String a = 'aaa';
const int v = a.length;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'length',
expectedKind: ReferenceKind.unresolved,
unresolvedHasName: true,
prefixExpectations: [
new _PrefixExpectation(
ReferenceKind.topLevelPropertyAccessor, 'a')
])
]);
}
test_constExpr_length_identifierTarget_classConstField() {
UnlinkedVariable variable = serializeVariableText('''
class C {
static const String F = '';
}
const int v = C.F.length;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'length',
expectedKind: ReferenceKind.unresolved,
unresolvedHasName: true,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.propertyAccessor, 'F'),
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
])
]);
}
test_constExpr_length_identifierTarget_imported() {
addNamedSource('/a.dart', '''
const String a = 'aaa';
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const int v = a.length;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'length',
expectedKind: ReferenceKind.unresolved,
unresolvedHasName: true,
prefixExpectations: [
new _PrefixExpectation(
ReferenceKind.topLevelPropertyAccessor, 'a',
absoluteUri: absUri('/a.dart'))
])
]);
}
test_constExpr_length_identifierTarget_imported_withPrefix() {
addNamedSource('/a.dart', '''
const String a = 'aaa';
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const int v = p.a.length;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'length',
expectedKind: ReferenceKind.unresolved,
unresolvedHasName: true,
prefixExpectations: [
new _PrefixExpectation(
ReferenceKind.topLevelPropertyAccessor, 'a',
absoluteUri: absUri('/a.dart')),
new _PrefixExpectation(ReferenceKind.prefix, 'p')
])
]);
}
test_constExpr_length_parenthesizedBinaryTarget() {
UnlinkedVariable variable =
serializeVariableText('const v = ("abc" + "edf").length;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.add,
UnlinkedExprOperation.extractProperty
], strings: [
'abc',
'edf',
'length'
]);
}
test_constExpr_length_parenthesizedStringTarget() {
UnlinkedVariable variable =
serializeVariableText('const v = ("abc").length;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.extractProperty
], strings: [
'abc',
'length'
]);
}
test_constExpr_length_stringLiteralTarget() {
UnlinkedVariable variable =
serializeVariableText('const v = "abc".length;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.extractProperty
], strings: [
'abc',
'length'
]);
}
test_constExpr_makeSymbol() {
UnlinkedVariable variable = serializeVariableText('const v = #a.bb.ccc;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.makeSymbol], strings: ['a.bb.ccc']);
}
test_constExpr_makeTypedList() {
UnlinkedVariable variable =
serializeVariableText('const v = const <int>[11, 22, 33];');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.makeTypedList
], ints: [
11,
22,
33,
3
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
expectedKind: ReferenceKind.classOrEnum)
]);
}
test_constExpr_makeTypedList_dynamic() {
UnlinkedVariable variable =
serializeVariableText('const v = const <dynamic>[11, 22, 33];');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.makeTypedList
], ints: [
11,
22,
33,
3
], referenceValidators: [
(EntityRef r) => checkDynamicTypeRef(r)
]);
}
test_constExpr_makeTypedList_functionType() {
UnlinkedVariable variable =
serializeVariableText('final v = <void Function(int)>[];');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.makeTypedList
], ints: [
0 // Size of the list
], referenceValidators: [
(EntityRef reference) {
expect(reference, new isInstanceOf<EntityRef>());
expect(reference.entityKind, EntityRefKind.genericFunctionType);
expect(reference.syntheticParams, hasLength(1));
{
final param = reference.syntheticParams[0];
expect(param.name, ''); // no name for generic type parameters
checkTypeRef(param.type, 'dart:core', 'int',
expectedKind: ReferenceKind.classOrEnum);
}
expect(reference.paramReference, 0);
expect(reference.typeParameters, hasLength(0));
// TODO(mfairhurst) check this references void
expect(reference.syntheticReturnType, isNotNull);
}
]);
}
test_constExpr_makeTypedList_functionType_withTypeParameters() {
UnlinkedVariable variable = serializeVariableText(
'final v = <void Function<T>(Function<Q>(T, Q))>[];');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.makeTypedList
], ints: [
0 // Size of the list
], referenceValidators: [
(EntityRef reference) {
expect(reference, new isInstanceOf<EntityRef>());
expect(reference.entityKind, EntityRefKind.genericFunctionType);
expect(reference.syntheticParams, hasLength(1));
{
final param = reference.syntheticParams[0];
expect(param.type, new isInstanceOf<EntityRef>());
expect(param.type.entityKind, EntityRefKind.genericFunctionType);
expect(param.type.syntheticParams, hasLength(2));
{
final subparam = param.type.syntheticParams[0];
expect(subparam.name, ''); // no name for generic type parameters
expect(subparam.type, new isInstanceOf<EntityRef>());
expect(subparam.type.paramReference, 2);
}
{
final subparam = param.type.syntheticParams[1];
expect(subparam.name, ''); // no name for generic type parameters
expect(subparam.type, new isInstanceOf<EntityRef>());
expect(subparam.type.paramReference, 1);
}
}
expect(reference.paramReference, 0);
expect(reference.typeParameters, hasLength(1));
// TODO(mfairhurst) check this references void
expect(reference.syntheticReturnType, isNotNull);
}
]);
}
test_constExpr_makeTypedMap() {
UnlinkedVariable variable = serializeVariableText(
'const v = const <int, String>{11: "aaa", 22: "bbb", 33: "ccc"};');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.makeTypedMap
], ints: [
11,
22,
33,
3
], strings: [
'aaa',
'bbb',
'ccc'
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
expectedKind: ReferenceKind.classOrEnum),
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
expectedKind: ReferenceKind.classOrEnum)
]);
}
test_constExpr_makeTypedMap_dynamic() {
UnlinkedVariable variable = serializeVariableText(
'const v = const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"};');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.makeTypedMap
], ints: [
11,
22,
33,
3
], strings: [
'aaa',
'bbb',
'ccc'
], referenceValidators: [
(EntityRef r) => checkDynamicTypeRef(r),
(EntityRef r) => checkDynamicTypeRef(r)
]);
}
test_constExpr_makeUntypedList() {
UnlinkedVariable variable =
serializeVariableText('const v = const [11, 22, 33];');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.makeUntypedList
], ints: [
11,
22,
33,
3
]);
}
test_constExpr_makeUntypedMap() {
UnlinkedVariable variable = serializeVariableText(
'const v = const {11: "aaa", 22: "bbb", 33: "ccc"};');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushString,
UnlinkedExprOperation.makeUntypedMap
], ints: [
11,
22,
33,
3
], strings: [
'aaa',
'bbb',
'ccc'
]);
}
test_constExpr_parenthesized() {
UnlinkedVariable variable = serializeVariableText('const v = (1 + 2) * 3;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.add,
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.multiply,
], ints: [
1,
2,
3
]);
}
test_constExpr_prefix_complement() {
UnlinkedVariable variable = serializeVariableText('const v = ~2;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.complement
], ints: [
2
]);
}
test_constExpr_prefix_negate() {
UnlinkedVariable variable = serializeVariableText('const v = -(2);');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.negate
], ints: [
2
]);
}
test_constExpr_prefix_not() {
UnlinkedVariable variable = serializeVariableText('const v = !true;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushTrue, UnlinkedExprOperation.not]);
}
test_constExpr_pushDouble() {
UnlinkedVariable variable = serializeVariableText('const v = 123.4567;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushDouble], doubles: [123.4567]);
}
test_constExpr_pushFalse() {
UnlinkedVariable variable = serializeVariableText('const v = false;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushFalse]);
}
test_constExpr_pushInt() {
UnlinkedVariable variable = serializeVariableText('const v = 1;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushInt], ints: [1]);
}
test_constExpr_pushInt_max() {
UnlinkedVariable variable = serializeVariableText('const v = 0xFFFFFFFF;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
], ints: [
0xFFFFFFFF
]);
}
test_constExpr_pushInt_negative() {
UnlinkedVariable variable = serializeVariableText('const v = -5;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.negate
], ints: [
5
]);
}
test_constExpr_pushLongInt_maxNegative() {
UnlinkedVariable variable =
serializeVariableText('const v = 0xFFFFFFFFFFFFFFFF;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushInt,
UnlinkedExprOperation.negate
], ints: [
1
]);
}
test_constExpr_pushLongInt_maxPositive() {
UnlinkedVariable variable =
serializeVariableText('const v = 0x7FFFFFFFFFFFFFFF;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushLongInt],
ints: [2, 0x7FFFFFFF, 0xFFFFFFFF]);
}
test_constExpr_pushLongInt_min2() {
UnlinkedVariable variable = serializeVariableText('const v = 0x100000000;');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushLongInt
], ints: [
2,
1,
0,
]);
}
test_constExpr_pushLongInt_tooLong() {
UnlinkedVariable variable =
serializeVariableText('const v = 0x10000000000000000;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushInt], ints: [0]);
}
test_constExpr_pushNull() {
UnlinkedVariable variable = serializeVariableText('const v = null;');
assertUnlinkedConst(variable.initializer.bodyExpr,
operators: [UnlinkedExprOperation.pushNull]);
}
test_constExpr_pushReference_class() {
UnlinkedVariable variable = serializeVariableText('''
class C {}
const v = C;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) =>
checkTypeRef(r, null, 'C', expectedKind: ReferenceKind.classOrEnum)
]);
}
test_constExpr_pushReference_enum() {
UnlinkedVariable variable = serializeVariableText('''
enum C {V1, V2, V3}
const v = C;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) =>
checkTypeRef(r, null, 'C', expectedKind: ReferenceKind.classOrEnum)
]);
}
test_constExpr_pushReference_enumValue() {
UnlinkedVariable variable = serializeVariableText('''
enum C {V1, V2, V3}
const v = C.V1;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'V1',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_pushReference_enumValue_viaImport() {
addNamedSource('/a.dart', '''
enum C {V1, V2, V3}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = C.V1;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'V1',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart'))
])
]);
}
test_constExpr_pushReference_enumValues() {
UnlinkedVariable variable = serializeVariableText('''
enum C {V1, V2, V3}
const v = C.values;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'values',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_pushReference_enumValues_viaImport() {
addNamedSource('/a.dart', '''
enum C {V1, V2, V3}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = C.values;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'values',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart'))
])
]);
}
test_constExpr_pushReference_field() {
UnlinkedVariable variable = serializeVariableText('''
class C {
static const int F = 1;
}
const v = C.F;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'F',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_pushReference_field_imported() {
addNamedSource('/a.dart', '''
class C {
static const int F = 1;
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart';
const v = C.F;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'F',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart'))
])
]);
}
test_constExpr_pushReference_field_imported_withPrefix() {
addNamedSource('/a.dart', '''
class C {
static const int F = 1;
}
''');
UnlinkedVariable variable = serializeVariableText('''
import 'a.dart' as p;
const v = p.C.F;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'F',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
absoluteUri: absUri('/a.dart')),
new _PrefixExpectation(ReferenceKind.prefix, 'p'),
])
]);
}
test_constExpr_pushReference_field_simpleIdentifier() {
UnlinkedVariable variable = serializeClassText('''
class C {
static const a = b;
static const b = null;
}
''').fields[0];
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'b',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}
test_constExpr_pushReference_staticGetter() {
UnlinkedVariable variable = serializeVariableText('''
class C {
static int get x => null;
}
const v = C.x;
''');
assertUnlinkedConst(variable.initializer.bodyExpr, operators: [
UnlinkedExprOperation.pushReference
], referenceValidators: [
(EntityRef r) => checkTypeRef(r, null, 'x',
expectedKind: ReferenceKind.propertyAccessor,
prefixExpectations: [
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
])
]);
}