11b59bec8d
This is needed for two reasons: 1. Summary linking, because type inference needs to behave differently for opted-in vs. opted-out libraries. 2. Summary resynthesis, because TypeParameterElement.type needs to behave differently for opted-in vs. opted-out libraries. Note that reason 1 won't apply to the summary2 mechanism, because it has access to full ASTs when doing type inference. But it will still need to record compilation unit NNBD status for reason 2. This CL merely stores the correct data in the summary; it doesn't address resynthesis, linking, or summary2. Change-Id: I1aa2226e5865ef76747267de6198223997d6ad0d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101920 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
11857 lines
395 KiB
Dart
11857 lines
395 KiB
Dart
// 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.
|
|
|
|
import 'package:analyzer/dart/analysis/features.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/string_source.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:analyzer/src/summary/summarize_const_expr.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'test_strategies.dart';
|
|
|
|
/// 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, FeatureSet featureSet) {
|
|
CharacterReader reader = new CharSequenceReader(text);
|
|
Scanner scanner =
|
|
new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER)
|
|
..configureFeatures(featureSet);
|
|
Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER,
|
|
featureSet: featureSet);
|
|
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);
|
|
|
|
/// Test cases that exercise summary generation in a black-box fashion.
|
|
///
|
|
/// These test cases may be mixed into any class derived from
|
|
/// [SummaryBlackBoxTestStrategy], allowing summary generation to be unit-tested
|
|
/// in a variety of ways.
|
|
mixin SummaryTestCases implements SummaryBlackBoxTestStrategy {
|
|
/// Get access to the linked defining compilation unit.
|
|
LinkedUnit get definingUnit => linked.units[0];
|
|
|
|
FeatureSet get disableNnbd => FeatureSet.forTesting(sdkVersion: '2.2.2');
|
|
|
|
FeatureSet get enableNnbd =>
|
|
FeatureSet.forTesting(additionalFeatures: [Feature.non_nullable]);
|
|
|
|
/// TODO(scheglov) rename "Const" to "Expr" everywhere
|
|
void assertUnlinkedConst(UnlinkedExpr constExpr, String sourceRepresentation,
|
|
{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>[],
|
|
bool forTypeInferenceOnly: false}) {
|
|
if (forTypeInferenceOnly && !containsNonConstExprs) {
|
|
expect(constExpr, isNull);
|
|
return;
|
|
}
|
|
expect(constExpr, isNotNull);
|
|
expect(constExpr.sourceRepresentation,
|
|
_normalizeTokenString(sourceRepresentation));
|
|
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], 'a', 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 TypeMatcher<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 TypeMatcher<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}) {
|
|
checkLinkedTypeSlot(slotId, absoluteUri, expectedName,
|
|
numTypeArguments: numTypeArguments,
|
|
expectedKind: expectedKind,
|
|
expectedTargetUnit: expectedTargetUnit,
|
|
linkedSourceUnit: linkedSourceUnit,
|
|
unlinkedSourceUnit: unlinkedSourceUnit,
|
|
numTypeParameters: numTypeParameters);
|
|
}
|
|
|
|
/// 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 TypeMatcher<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,
|
|
EntityRefNullabilitySuffix nullabilitySuffix:
|
|
EntityRefNullabilitySuffix.starOrIrrelevant}) {
|
|
linkedSourceUnit ??= definingUnit;
|
|
expect(typeRef, new TypeMatcher<EntityRef>());
|
|
expect(typeRef.paramReference, 0);
|
|
int index = typeRef.reference;
|
|
expect(typeRef.typeArguments, hasLength(numTypeArguments));
|
|
expect(typeRef.nullabilitySuffix, nullabilitySuffix);
|
|
|
|
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 mixin with the given [name] in the summary, and return its
|
|
/// [UnlinkedClass] data structure.
|
|
UnlinkedClass findMixin(String name) {
|
|
UnlinkedClass result;
|
|
for (UnlinkedClass mixin in unlinkedUnits[0].mixins) {
|
|
if (mixin.name == name) {
|
|
if (result != null) {
|
|
fail('Duplicate mixin $name');
|
|
}
|
|
result = mixin;
|
|
}
|
|
}
|
|
if (result == null) {
|
|
fail('Mixin $name 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 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 mixin
|
|
/// with the given [name].
|
|
UnlinkedClass serializeMixinText(String text,
|
|
{String name: 'M', bool allowErrors: false}) {
|
|
serializeLibraryText(text, allowErrors: allowErrors);
|
|
return findMixin(name);
|
|
}
|
|
|
|
/// 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, imports: ''}) {
|
|
if (imports.isNotEmpty && !imports.endsWith('\n')) {
|
|
imports += '\n';
|
|
}
|
|
serializeLibraryText('$imports$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('var x = throw null; var y = throw null;');
|
|
EntityRef xInitializerReturnType =
|
|
getTypeRefForSlot(findVariable('x').initializer.inferredReturnTypeSlot);
|
|
EntityRef yInitializerReturnType =
|
|
getTypeRefForSlot(findVariable('y').initializer.inferredReturnTypeSlot);
|
|
checkLinkedTypeRef(xInitializerReturnType, null, '*bottom*');
|
|
checkLinkedTypeRef(yInitializerReturnType, null, '*bottom*');
|
|
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() {
|
|
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_notSimplyBoundedSlot() {
|
|
var cls = serializeClassText(
|
|
'class C<T extends C> = D with E; class D {} class E {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_alias_notSimplyBoundedSlot_simple_because_non_generic() {
|
|
// If no type parameters are specified, then the class is simply bounded, so
|
|
// there is no reason to assign it a slot.
|
|
var cls = serializeClassText('class C = D with E; class D {} class E {}');
|
|
expect(cls.notSimplyBoundedSlot, 0);
|
|
}
|
|
|
|
test_class_alias_notSimplyBoundedSlot_simple_by_syntax() {
|
|
// If no bounds are specified, then the class is simply bounded by sintax
|
|
// alone, so there is no reason to assign it a slot.
|
|
var cls =
|
|
serializeClassText('class C<T> = D with E; class D {} class E {}');
|
|
expect(cls.notSimplyBoundedSlot, 0);
|
|
}
|
|
|
|
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() {
|
|
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() {
|
|
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() {
|
|
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() {
|
|
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() {
|
|
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');
|
|
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_superclass() {
|
|
UnlinkedClass cls = serializeClassText('part of dart.core; class Object {}',
|
|
className: 'Object');
|
|
expect(cls.supertype, isNull);
|
|
expect(cls.hasNoSupertype, isTrue);
|
|
}
|
|
|
|
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_notSimplyBounded_circularity_via_typedef() {
|
|
// C's type parameter T is not simply bounded because its bound, F, expands
|
|
// to `dynamic F(C)`, which refers to C.
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T extends F> {} typedef F(C value);');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBounded_circularity_with_type_params() {
|
|
// C's type parameter T is simply bounded because even though it refers to
|
|
// C, it specifies a bound.
|
|
UnlinkedClass cls = serializeClassText('class C<T extends C<dynamic>> {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(cls.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBounded_dependency_with_type_params() {
|
|
// C's type parameter T is simply bounded because even though it refers to
|
|
// non-simply-bounded type D, it specifies a bound.
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<T extends D<dynamic>> {} class D<T extends D<T>> {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(cls.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBounded_function_typed_bound_complex_via_parameter_type() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T extends void Function(T)> {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBounded_function_typed_bound_complex_via_return_type() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T extends T Function()> {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBounded_function_typed_bound_simple() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T extends void Function()> {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(cls.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBounded_refers_to_circular_typedef() {
|
|
// C's type parameter T has a bound of F, which is a circular typedef. This
|
|
// is illegal in Dart, but we need to make sure it doesn't lead to a crash
|
|
// or infinite loop.
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<T extends F> {} typedef F(G value); typedef G(F value);');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot() {
|
|
var cls = serializeClassText('class C<T extends C> {}');
|
|
expect(cls.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot_complex_by_cycle() {
|
|
var cls =
|
|
serializeClassText('class C<T extends D> {} class D<T extends C> {}');
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot_complex_by_reference_to_cycle() {
|
|
var cls =
|
|
serializeClassText('class C<T extends D> {} class D<T extends D> {}');
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot_complex_by_use_of_parameter() {
|
|
var cls = serializeClassText('class C<T extends D<T>> {} class D<T> {}');
|
|
if (!skipFullyLinkedData) {
|
|
expect(
|
|
linked.units[0].notSimplyBounded, contains(cls.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot_simple_because_non_generic() {
|
|
// If no type parameters are specified, then the class is simply bounded, so
|
|
// there is no reason to assign it a slot.
|
|
var cls = serializeClassText('class C {}');
|
|
expect(cls.notSimplyBoundedSlot, 0);
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot_simple_by_lack_of_cycles() {
|
|
var cls = serializeClassText('class C<T extends D> {} class D<T> {}');
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(cls.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_class_notSimplyBoundedSlot_simple_by_syntax() {
|
|
// If no bounds are specified, then the class is simply bounded by syntax
|
|
// alone, so there is no reason to assign it a slot.
|
|
var cls = serializeClassText('class C<T> {}');
|
|
expect(cls.notSimplyBoundedSlot, 0);
|
|
}
|
|
|
|
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');
|
|
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];
|
|
}
|
|
// Strong mode infers a type for the closure of `() => Null`.
|
|
checkInferredTypeSlot(closure.inferredReturnTypeSlot, 'dart:core', 'Null');
|
|
}
|
|
|
|
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_compilationUnit_nnbd_disabled_via_dart_directive() {
|
|
featureSet = enableNnbd;
|
|
serializeLibraryText('''
|
|
// @dart=2.2
|
|
''');
|
|
expect(unlinkedUnits[0].isNNBD, false);
|
|
}
|
|
|
|
test_compilationUnit_nnbd_disabled_via_feature_set() {
|
|
featureSet = disableNnbd;
|
|
serializeLibraryText('');
|
|
expect(unlinkedUnits[0].isNNBD, false);
|
|
}
|
|
|
|
test_compilationUnit_nnbd_enabled() {
|
|
featureSet = enableNnbd;
|
|
serializeLibraryText('');
|
|
expect(unlinkedUnits[0].isNNBD, true);
|
|
}
|
|
|
|
test_constExpr_binary_add() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 1 + 2;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1 + 2', 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, 'true && false',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushFalse,
|
|
UnlinkedExprOperation.and
|
|
]);
|
|
}
|
|
|
|
test_constExpr_binary_bitAnd() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 1 & 2;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1 & 2', 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, '1 | 2', 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, '1 << 2', 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, '1 >> 2', operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.bitShiftRight
|
|
], ints: [
|
|
1,
|
|
2
|
|
]);
|
|
}
|
|
|
|
test_constExpr_binary_bitShiftRightLogical() {
|
|
featureSet = FeatureSet.forTesting(
|
|
sdkVersion: '2.2.2',
|
|
additionalFeatures: [
|
|
Feature.constant_update_2018,
|
|
Feature.triple_shift
|
|
]);
|
|
UnlinkedVariable variable = serializeVariableText('const v = 1 >>> 2;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1 >>> 2', operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.bitShiftRightLogical
|
|
], ints: [
|
|
1,
|
|
2
|
|
]);
|
|
}
|
|
|
|
test_constExpr_binary_bitXor() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 1 ^ 2;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1 ^ 2', 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, '1 / 2', 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, '1 == 2', 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, '1 != 2', 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, '1 ~/ 2', 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, '1 > 2', 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, '1 >= 2', 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, '1 < 2', 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, '1 <= 2', 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, '1 % 2', 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, '1 * 2', 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, 'false || true',
|
|
operators: [
|
|
UnlinkedExprOperation.pushFalse,
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.or
|
|
]);
|
|
}
|
|
|
|
test_constExpr_binary_qq() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 1 ?? 2;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1 ?? 2', 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, '1 - 2', 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, 'T',
|
|
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, 'true ? 1 : 2',
|
|
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, 'a',
|
|
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, 'T',
|
|
operators: [UnlinkedExprOperation.pushParameter], strings: ['T']);
|
|
}
|
|
|
|
test_constExpr_function_type_arg_nullability_suffix_none() {
|
|
featureSet = enableNnbd;
|
|
var variable =
|
|
serializeVariableText('const v = const <void Function()>[];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'const <void Function()>[]', operators: [
|
|
UnlinkedExprOperation.makeTypedList
|
|
], ints: [
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
expect(r.nullabilitySuffix, EntityRefNullabilitySuffix.none)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_function_type_arg_nullability_suffix_question() {
|
|
featureSet = enableNnbd;
|
|
var variable =
|
|
serializeVariableText('const v = const <void Function()?>[];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'const <void Function()?>[]',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedList
|
|
],
|
|
ints: [
|
|
0
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) =>
|
|
expect(r.nullabilitySuffix, EntityRefNullabilitySuffix.question)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_function_type_arg_nullability_suffix_star() {
|
|
featureSet = disableNnbd;
|
|
var variable =
|
|
serializeVariableText('const v = const <void Function()>[];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'const <void Function()>[]',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedList
|
|
],
|
|
ints: [
|
|
0
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => expect(
|
|
r.nullabilitySuffix, EntityRefNullabilitySuffix.starOrIrrelevant)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_functionExpression() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'dart:async';
|
|
var v = (f) async => await f;
|
|
''');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, 'await f',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.await
|
|
],
|
|
strings: ['f'],
|
|
ints: [],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
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, 'foo(5, () => 42)',
|
|
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, 'foo(5, () => 42, () => 43)',
|
|
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, '(() => 42)',
|
|
isValidConst: false,
|
|
operators: [UnlinkedExprOperation.pushLocalFunctionReference],
|
|
ints: [0, 0]);
|
|
assertUnlinkedConst(
|
|
executable.constantInitializers[1].expression, '(() => 43)',
|
|
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, 'const C<int, String>.named()',
|
|
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, 'const C<int, String>.named()',
|
|
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, 'const p.C<int, String>.named()',
|
|
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, 'const C<int, String>()',
|
|
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, 'const C<int, String>()',
|
|
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, 'const p.C<int, String>()',
|
|
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, 'const C.named()',
|
|
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, 'const C.named()',
|
|
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, 'const p.C.named()',
|
|
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,
|
|
"const C(11, 22, 3.3, '444', e: 55, g: '777', f: 66)",
|
|
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, 'const C()', 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, 'const p.C()',
|
|
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, 'const C.foo()',
|
|
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, 'const C.foo()',
|
|
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, 'const p.C.foo()',
|
|
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, 'const p.C.foo()',
|
|
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, 'const Foo()',
|
|
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, 'identical(42, null)',
|
|
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, 'C.length', 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, 'p.C.length',
|
|
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, 'a.length', 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, 'C.F.length',
|
|
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, 'a.length', 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, 'p.a.length',
|
|
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, '("abc" + "edf").length',
|
|
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, '("abc").length',
|
|
operators: [
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.extractProperty
|
|
],
|
|
strings: [
|
|
'abc',
|
|
'length'
|
|
]);
|
|
}
|
|
|
|
test_constExpr_length_stringLiteralTarget() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = "abc".length;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '"abc".length',
|
|
operators: [
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.extractProperty
|
|
],
|
|
strings: [
|
|
'abc',
|
|
'length'
|
|
]);
|
|
}
|
|
|
|
test_constExpr_list_if() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = [if (true) 1];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[if (true) 1]',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.ifElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [
|
|
1,
|
|
1
|
|
]);
|
|
}
|
|
|
|
test_constExpr_list_if_else() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = [if (true) 1 else 2];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[if (true) 1 else 2]',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.ifElseElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [
|
|
1,
|
|
2,
|
|
1
|
|
]);
|
|
}
|
|
|
|
test_constExpr_list_spread() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = [...[]];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[...[]]', operators: [
|
|
UnlinkedExprOperation.makeUntypedList,
|
|
UnlinkedExprOperation.spreadElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
], ints: [
|
|
0,
|
|
1
|
|
]);
|
|
}
|
|
|
|
test_constExpr_list_spread_null_aware() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = [...?[]];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[...?[]]', operators: [
|
|
UnlinkedExprOperation.makeUntypedList,
|
|
UnlinkedExprOperation.nullAwareSpreadElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
], ints: [
|
|
0,
|
|
1
|
|
]);
|
|
}
|
|
|
|
test_constExpr_makeSymbol() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = #a.bb.ccc;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '#a.bb.ccc',
|
|
operators: [UnlinkedExprOperation.makeSymbol], strings: ['a.bb.ccc']);
|
|
}
|
|
|
|
test_constExpr_makeTypedList() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = const <int>[11, 22, 33];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'const <int>[11, 22, 33]',
|
|
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, 'const <dynamic>[11, 22, 33]',
|
|
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, '<void Function(int)>[]',
|
|
operators: [UnlinkedExprOperation.makeTypedList],
|
|
ints: [
|
|
0 // Size of the list
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef reference) {
|
|
expect(reference, new TypeMatcher<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);
|
|
}
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_constExpr_makeTypedList_functionType_withTypeParameters() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'final v = <void Function<T>(Function<Q>(T, Q))>[];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr,
|
|
'<void Function<T>(Function<Q>(T, Q))>[]',
|
|
operators: [UnlinkedExprOperation.makeTypedList],
|
|
ints: [
|
|
0 // Size of the list
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef reference) {
|
|
expect(reference, new TypeMatcher<EntityRef>());
|
|
expect(reference.entityKind, EntityRefKind.genericFunctionType);
|
|
expect(reference.syntheticParams, hasLength(1));
|
|
{
|
|
final param = reference.syntheticParams[0];
|
|
expect(param.type, new TypeMatcher<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 TypeMatcher<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 TypeMatcher<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);
|
|
}
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_constExpr_makeTypedMap() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'const v = const <int, String>{11: "aaa", 22: "bbb", 33: "ccc"};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr,
|
|
'const <int, String>{11: "aaa", 22: "bbb", 33: "ccc"}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.makeTypedMap2
|
|
],
|
|
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,
|
|
'const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.makeTypedMap2
|
|
],
|
|
ints: [
|
|
11,
|
|
22,
|
|
33,
|
|
3
|
|
],
|
|
strings: [
|
|
'aaa',
|
|
'bbb',
|
|
'ccc'
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkDynamicTypeRef(r),
|
|
(EntityRef r) => checkDynamicTypeRef(r)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_makeTypedSet() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = const <int>{11, 22, 33};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr,
|
|
'const <int>{11, 22, 33}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeTypedSet
|
|
],
|
|
ints: [11, 22, 33, 3],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
);
|
|
}
|
|
|
|
test_constExpr_makeTypedSet_dynamic() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = const <dynamic>{11, 22, 33};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr,
|
|
'const <dynamic>{11, 22, 33}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeTypedSet
|
|
],
|
|
ints: [11, 22, 33, 3],
|
|
referenceValidators: [(EntityRef r) => checkDynamicTypeRef(r)],
|
|
);
|
|
}
|
|
|
|
test_constExpr_makeTypedSet_functionType() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('final v = <void Function(int)>{};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<void Function(int)>{}',
|
|
operators: [UnlinkedExprOperation.makeTypedSet],
|
|
ints: [
|
|
0 // Size of the list
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef reference) {
|
|
expect(reference, new TypeMatcher<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);
|
|
}
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_constExpr_makeTypedSet_functionType_withTypeParameters() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'final v = <void Function<T>(Function<Q>(T, Q))>{};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr,
|
|
'<void Function<T>(Function<Q>(T, Q))>{}',
|
|
operators: [UnlinkedExprOperation.makeTypedSet],
|
|
ints: [
|
|
0 // Size of the list
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef reference) {
|
|
expect(reference, new TypeMatcher<EntityRef>());
|
|
expect(reference.entityKind, EntityRefKind.genericFunctionType);
|
|
expect(reference.syntheticParams, hasLength(1));
|
|
{
|
|
final param = reference.syntheticParams[0];
|
|
expect(param.type, new TypeMatcher<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 TypeMatcher<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 TypeMatcher<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);
|
|
}
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_constExpr_makeUntypedList() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = const [11, 22, 33];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'const [11, 22, 33]',
|
|
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,
|
|
'const {11: "aaa", 22: "bbb", 33: "ccc"}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.makeUntypedSetOrMap
|
|
],
|
|
ints: [
|
|
11,
|
|
22,
|
|
33,
|
|
3
|
|
],
|
|
strings: [
|
|
'aaa',
|
|
'bbb',
|
|
'ccc'
|
|
]);
|
|
}
|
|
|
|
test_constExpr_makeUntypedSet() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = const {11, 22, 33};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr,
|
|
'const {11, 22, 33}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeUntypedSetOrMap
|
|
],
|
|
ints: [11, 22, 33, 3],
|
|
);
|
|
}
|
|
|
|
test_constExpr_map_if() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int, int>{if (true) 1 : 2};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '<int, int>{if (true) 1 : 2}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.ifElement,
|
|
UnlinkedExprOperation.makeTypedMap2
|
|
],
|
|
ints: [
|
|
1,
|
|
2,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_map_if_else() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'const v = <int, int>{if (true) 1 : 2 else 3 : 4};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '<int, int>{if (true) 1 : 2 else 3 : 4}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.ifElseElement,
|
|
UnlinkedExprOperation.makeTypedMap2
|
|
],
|
|
ints: [
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_map_spread() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int, String>{...<int, String>{}};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '<int, String>{...<int, String>{}}',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedMap2,
|
|
UnlinkedExprOperation.spreadElement,
|
|
UnlinkedExprOperation.makeTypedMap2
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_map_spread_null_aware() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int, String>{...?<int, String>{}};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '<int, String>{...?<int, String>{}}',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedMap2,
|
|
UnlinkedExprOperation.nullAwareSpreadElement,
|
|
UnlinkedExprOperation.makeTypedMap2
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_parenthesized() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = (1 + 2) * 3;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(1 + 2) * 3',
|
|
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, '~2', operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.complement
|
|
], ints: [
|
|
2
|
|
]);
|
|
}
|
|
|
|
test_constExpr_prefix_negate() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = -(2);');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '-(2)', operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.negate
|
|
], ints: [
|
|
2
|
|
]);
|
|
}
|
|
|
|
test_constExpr_prefix_not() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = !true;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '!true',
|
|
operators: [UnlinkedExprOperation.pushTrue, UnlinkedExprOperation.not]);
|
|
}
|
|
|
|
test_constExpr_pushDouble() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 123.4567;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '123.4567',
|
|
operators: [UnlinkedExprOperation.pushDouble], doubles: [123.4567]);
|
|
}
|
|
|
|
test_constExpr_pushFalse() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = false;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'false',
|
|
operators: [UnlinkedExprOperation.pushFalse]);
|
|
}
|
|
|
|
test_constExpr_pushInt() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 1;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [1]);
|
|
}
|
|
|
|
test_constExpr_pushInt_max() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 0xFFFFFFFF;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '0xFFFFFFFF',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
],
|
|
ints: [
|
|
0xFFFFFFFF
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushInt_negative() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = -5;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '-5', operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.negate
|
|
], ints: [
|
|
5
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushLongInt_maxNegative() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = 0xFFFFFFFFFFFFFFFF;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '0xFFFFFFFFFFFFFFFF',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.negate
|
|
],
|
|
ints: [
|
|
1
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushLongInt_maxPositive() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = 0x7FFFFFFFFFFFFFFF;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '0x7FFFFFFFFFFFFFFF',
|
|
operators: [UnlinkedExprOperation.pushLongInt],
|
|
ints: [2, 0x7FFFFFFF, 0xFFFFFFFF]);
|
|
}
|
|
|
|
test_constExpr_pushLongInt_min2() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = 0x100000000;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '0x100000000',
|
|
operators: [
|
|
UnlinkedExprOperation.pushLongInt
|
|
],
|
|
ints: [
|
|
2,
|
|
1,
|
|
0,
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushLongInt_tooLong() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = 0x10000000000000000;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '0x10000000000000000',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [0]);
|
|
}
|
|
|
|
test_constExpr_pushNull() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = null;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'null',
|
|
operators: [UnlinkedExprOperation.pushNull]);
|
|
}
|
|
|
|
test_constExpr_pushReference_class() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {}
|
|
const v = C;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'C', 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, 'C', 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, 'C.V1', 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, 'C.V1', 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, 'C.values', 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, 'C.values', 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, 'C.F', 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, 'C.F', 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, 'p.C.F', 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, 'b', 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, 'C.x', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'x',
|
|
expectedKind: ReferenceKind.propertyAccessor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_staticGetter_imported() {
|
|
addNamedSource('/a.dart', '''
|
|
class C {
|
|
static int get x => null;
|
|
}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart';
|
|
const v = C.x;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'C.x', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'x',
|
|
expectedKind: ReferenceKind.propertyAccessor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
|
|
absoluteUri: absUri('/a.dart'))
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_staticGetter_imported_withPrefix() {
|
|
addNamedSource('/a.dart', '''
|
|
class C {
|
|
static int get x => null;
|
|
}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
const v = p.C.x;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.C.x', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'x',
|
|
expectedKind: ReferenceKind.propertyAccessor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
|
|
absoluteUri: absUri('/a.dart')),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'p')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_staticMethod() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
static m() {}
|
|
}
|
|
const v = C.m;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'C.m', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.method,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_staticMethod_imported() {
|
|
addNamedSource('/a.dart', '''
|
|
class C {
|
|
static m() {}
|
|
}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart';
|
|
const v = C.m;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'C.m', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.method,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
|
|
absoluteUri: absUri('/a.dart'))
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_staticMethod_imported_withPrefix() {
|
|
addNamedSource('/a.dart', '''
|
|
class C {
|
|
static m() {}
|
|
}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
const v = p.C.m;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.C.m', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.method,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
|
|
absoluteUri: absUri('/a.dart')),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'p')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_staticMethod_simpleIdentifier() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
static const a = m;
|
|
static m() {}
|
|
}
|
|
''').fields[0];
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'm', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.method,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelFunction() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
f() {}
|
|
const v = f;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'f', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelFunction_imported() {
|
|
addNamedSource('/a.dart', '''
|
|
f() {}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart';
|
|
const v = f;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'f', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelFunction_imported_withPrefix() {
|
|
addNamedSource('/a.dart', '''
|
|
f() {}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
const v = p.f;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.f', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'p')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelGetter() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
int get x => null;
|
|
const v = x;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'x', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'x',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelGetter_imported() {
|
|
addNamedSource('/a.dart', 'int get x => null;');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart';
|
|
const v = x;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'x', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'x',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelGetter_imported_withPrefix() {
|
|
addNamedSource('/a.dart', 'int get x => null;');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
const v = p.x;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.x', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'x',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor,
|
|
expectedPrefix: 'p')
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelVariable() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
const int a = 1;
|
|
const v = a;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'a', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelVariable_imported() {
|
|
addNamedSource('/a.dart', 'const int a = 1;');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart';
|
|
const v = a;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'a', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_topLevelVariable_imported_withPrefix() {
|
|
addNamedSource('/a.dart', 'const int a = 1;');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
const v = p.a;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.a', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) {
|
|
return checkTypeRef(r, absUri('/a.dart'), 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor,
|
|
expectedPrefix: 'p');
|
|
}
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_typeParameter() {
|
|
String text = '''
|
|
class C<T> {
|
|
static const a = T;
|
|
}
|
|
''';
|
|
UnlinkedVariable variable =
|
|
serializeClassText(text, allowErrors: true).fields[0];
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'T', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) {
|
|
return checkParamTypeRef(r, 1);
|
|
}
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_unresolved_prefix0() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
const v = foo;
|
|
''', allowErrors: true);
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'foo', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'foo', expectedKind: ReferenceKind.unresolved)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_unresolved_prefix1() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {}
|
|
const v = C.foo;
|
|
''', allowErrors: true);
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'C.foo', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'foo',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushReference_unresolved_prefix2() {
|
|
addNamedSource('/a.dart', '''
|
|
class C {}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
const v = p.C.foo;
|
|
''', allowErrors: true);
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.C.foo', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], 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_pushString_adjacent() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = "aaa" "b" "ccc";');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '"aaa" "b" "ccc"',
|
|
operators: [UnlinkedExprOperation.pushString], strings: ['aaabccc']);
|
|
}
|
|
|
|
test_constExpr_pushString_adjacent_interpolation() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText(r'const v = "aaa" "bb ${42} bbb" "cccc";');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, r'"aaa" "bb ${42} bbb" "cccc"',
|
|
operators: [
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.concatenate,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.concatenate,
|
|
],
|
|
ints: [
|
|
42,
|
|
3,
|
|
3,
|
|
],
|
|
strings: [
|
|
'aaa',
|
|
'bb ',
|
|
' bbb',
|
|
'cccc'
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushString_interpolation() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText(r'const v = "aaa ${42} bbb";');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, r'"aaa ${42} bbb"',
|
|
operators: [
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.concatenate
|
|
],
|
|
ints: [
|
|
42,
|
|
3
|
|
],
|
|
strings: [
|
|
'aaa ',
|
|
' bbb'
|
|
]);
|
|
}
|
|
|
|
test_constExpr_pushString_simple() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = "abc";');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '"abc"',
|
|
operators: [UnlinkedExprOperation.pushString], strings: ['abc']);
|
|
}
|
|
|
|
test_constExpr_pushTrue() {
|
|
UnlinkedVariable variable = serializeVariableText('const v = true;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'true',
|
|
operators: [UnlinkedExprOperation.pushTrue]);
|
|
}
|
|
|
|
test_constExpr_set_if() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int>{if (true) 1};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{if (true) 1}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.ifElement,
|
|
UnlinkedExprOperation.makeTypedSet
|
|
],
|
|
ints: [
|
|
1,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_set_if_else() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int>{if (true) 1 else 2};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '<int>{if (true) 1 else 2}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushTrue,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.ifElseElement,
|
|
UnlinkedExprOperation.makeTypedSet
|
|
],
|
|
ints: [
|
|
1,
|
|
2,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_set_spread() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int>{...<int>{}};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{...<int>{}}',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedSet,
|
|
UnlinkedExprOperation.spreadElement,
|
|
UnlinkedExprOperation.makeTypedSet
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_set_spread_null_aware() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const v = <int>{...?<int>{}};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{...?<int>{}}',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedSet,
|
|
UnlinkedExprOperation.nullAwareSpreadElement,
|
|
UnlinkedExprOperation.makeTypedSet
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_arg_nullability_suffix_none() {
|
|
featureSet = enableNnbd;
|
|
var variable = serializeVariableText('const v = const <int>[];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'const <int>[]',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedList
|
|
],
|
|
ints: [
|
|
0
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.none)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_arg_nullability_suffix_question() {
|
|
featureSet = enableNnbd;
|
|
var variable = serializeVariableText('const v = const <int?>[];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'const <int?>[]',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedList
|
|
],
|
|
ints: [
|
|
0
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.question)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_arg_nullability_suffix_star() {
|
|
featureSet = disableNnbd;
|
|
var variable = serializeVariableText('const v = const <int>[];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'const <int>[]',
|
|
operators: [
|
|
UnlinkedExprOperation.makeTypedList
|
|
],
|
|
ints: [
|
|
0
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.starOrIrrelevant)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_nullability_suffix_none() {
|
|
featureSet = enableNnbd;
|
|
var variable = serializeVariableText('const v = int;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'int', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.none)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_nullability_suffix_question() {
|
|
// This is a placeholder for testing that `const v = int?;` is serialized
|
|
// correctly, if we decide that this syntax is allowed.
|
|
// TODO(paulberry): fill out this test if necessary.
|
|
// See https://github.com/dart-lang/language/issues/278
|
|
|
|
// var variable = serializeVariableText('const v = int?;', nnbd: true);
|
|
// assertUnlinkedConst(variable.initializer.bodyExpr, ...);
|
|
}
|
|
|
|
test_constExpr_type_nullability_suffix_star() {
|
|
featureSet = disableNnbd;
|
|
var variable = serializeVariableText('const v = int;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'int', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.starOrIrrelevant)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_prefixed_nullability_suffix_none() {
|
|
featureSet = enableNnbd;
|
|
var variable = serializeVariableText('const v = core.int;',
|
|
imports: 'import "dart:core" as core;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'core.int', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
prefixExpectations: [
|
|
_PrefixExpectation(ReferenceKind.prefix, 'core')
|
|
],
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.none)
|
|
]);
|
|
}
|
|
|
|
test_constExpr_type_prefixed_nullability_suffix_question() {
|
|
// This is a placeholder for testing that `const v = core.int?;` is
|
|
// serialized correctly, if we decide that this syntax is allowed.
|
|
// TODO(paulberry): fill out this test if necessary.
|
|
// See https://github.com/dart-lang/language/issues/278
|
|
|
|
// var variable = serializeVariableText('const v = core.int?;', imports: 'import "dart:core: as core;', nnbd: true);
|
|
// assertUnlinkedConst(variable.initializer.bodyExpr, ...);
|
|
}
|
|
|
|
test_constExpr_type_prefixed_nullability_suffix_star() {
|
|
featureSet = disableNnbd;
|
|
var variable = serializeVariableText('const v = core.int;',
|
|
imports: 'import "dart:core" as core;');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'core.int', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
prefixExpectations: [
|
|
_PrefixExpectation(ReferenceKind.prefix, 'core')
|
|
],
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.starOrIrrelevant)
|
|
]);
|
|
}
|
|
|
|
test_constructor() {
|
|
String text = 'class C { C(); }';
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(text).executables);
|
|
expect(executable.kind, UnlinkedExecutableKind.constructor);
|
|
expect(executable.returnType, isNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.nameOffset, text.indexOf('C();'));
|
|
expect(executable.periodOffset, 0);
|
|
expect(executable.nameEnd, 0);
|
|
expect(executable.isRedirectedConstructor, isFalse);
|
|
expect(executable.redirectedConstructor, isNull);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
expect(executable.visibleOffset, 0);
|
|
expect(executable.visibleLength, 0);
|
|
}
|
|
|
|
test_constructor_anonymous() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(); }').executables);
|
|
expect(executable.name, isEmpty);
|
|
}
|
|
|
|
test_constructor_const() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { const C(); }').executables);
|
|
expect(executable.isConst, isTrue);
|
|
expect(executable.isExternal, isFalse);
|
|
}
|
|
|
|
test_constructor_const_external() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { external const C(); }').executables);
|
|
expect(executable.isConst, isTrue);
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_constructor_documented() {
|
|
String text = '''
|
|
class C {
|
|
/**
|
|
* Docs
|
|
*/
|
|
C();
|
|
}''';
|
|
UnlinkedExecutable executable = serializeClassText(text).executables[0];
|
|
expect(executable.documentationComment, isNotNull);
|
|
checkDocumentationComment(executable.documentationComment, text);
|
|
}
|
|
|
|
test_constructor_external() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { external C(); }').executables);
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_constructor_factory() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { factory C() => null; }').executables);
|
|
expect(executable.isFactory, isTrue);
|
|
}
|
|
|
|
test_constructor_implicit() {
|
|
// Implicit constructors are not serialized.
|
|
UnlinkedExecutable executable = findExecutable(null,
|
|
executables: serializeClassText('class C { C(); }').executables,
|
|
failIfAbsent: false);
|
|
expect(executable, isNull);
|
|
}
|
|
|
|
test_constructor_initializers_assertInvocation() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
const C(int x) : assert(x >= 42);
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(
|
|
initializer.kind, UnlinkedConstructorInitializerKind.assertInvocation);
|
|
expect(initializer.name, '');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(1));
|
|
assertUnlinkedConst(initializer.arguments[0], 'x >= 42', operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.greaterEqual
|
|
], ints: [
|
|
42
|
|
], strings: [
|
|
'x'
|
|
]);
|
|
}
|
|
|
|
test_constructor_initializers_assertInvocation_message() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
const C(int x) : assert(x >= 42, 'foo');
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(
|
|
initializer.kind, UnlinkedConstructorInitializerKind.assertInvocation);
|
|
expect(initializer.name, '');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(2));
|
|
assertUnlinkedConst(initializer.arguments[0], 'x >= 42', operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.greaterEqual
|
|
], ints: [
|
|
42
|
|
], strings: [
|
|
'x',
|
|
]);
|
|
assertUnlinkedConst(initializer.arguments[1], "'foo'", operators: [
|
|
UnlinkedExprOperation.pushString,
|
|
], strings: [
|
|
'foo'
|
|
]);
|
|
}
|
|
|
|
test_constructor_initializers_field() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
final x;
|
|
const C() : x = 42;
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(initializer.kind, UnlinkedConstructorInitializerKind.field);
|
|
expect(initializer.name, 'x');
|
|
assertUnlinkedConst(initializer.expression, '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
expect(initializer.arguments, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializers_field_withParameter() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
final x;
|
|
const C(int p) : x = p;
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(initializer.kind, UnlinkedConstructorInitializerKind.field);
|
|
expect(initializer.name, 'x');
|
|
assertUnlinkedConst(initializer.expression, 'p',
|
|
operators: [UnlinkedExprOperation.pushParameter], strings: ['p']);
|
|
expect(initializer.arguments, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializers_notConst() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
final x;
|
|
C() : x = 42;
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializers_superInvocation_named() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class A {
|
|
const A.aaa(int p);
|
|
}
|
|
class C extends A {
|
|
const C() : super.aaa(42);
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(
|
|
initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
|
|
expect(initializer.name, 'aaa');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(1));
|
|
assertUnlinkedConst(initializer.arguments[0], '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_constructor_initializers_superInvocation_namedExpression() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class A {
|
|
const A(a, {int b, int c});
|
|
}
|
|
class C extends A {
|
|
const C() : super(1, b: 2, c: 3);
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(
|
|
initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
|
|
expect(initializer.name, '');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(3));
|
|
assertUnlinkedConst(initializer.arguments[0], '1',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [1]);
|
|
assertUnlinkedConst(initializer.arguments[1], '2',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [2]);
|
|
assertUnlinkedConst(initializer.arguments[2], '3',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [3]);
|
|
expect(initializer.argumentNames, ['b', 'c']);
|
|
}
|
|
|
|
test_constructor_initializers_superInvocation_unnamed() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('ccc', executables: serializeClassText(r'''
|
|
class A {
|
|
const A(int p);
|
|
}
|
|
class C extends A {
|
|
const C.ccc() : super(42);
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(
|
|
initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
|
|
expect(initializer.name, '');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(1));
|
|
assertUnlinkedConst(initializer.arguments[0], '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_constructor_initializers_thisInvocation_named() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
const C() : this.named(1, 'bbb');
|
|
const C.named(int a, String b);
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(initializer.kind, UnlinkedConstructorInitializerKind.thisInvocation);
|
|
expect(initializer.name, 'named');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(2));
|
|
assertUnlinkedConst(initializer.arguments[0], '1',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [1]);
|
|
assertUnlinkedConst(initializer.arguments[1], "'bbb'",
|
|
operators: [UnlinkedExprOperation.pushString], strings: ['bbb']);
|
|
}
|
|
|
|
test_constructor_initializers_thisInvocation_namedExpression() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
const C() : this.named(1, b: 2, c: 3);
|
|
const C.named(a, {int b, int c});
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(initializer.kind, UnlinkedConstructorInitializerKind.thisInvocation);
|
|
expect(initializer.name, 'named');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(3));
|
|
assertUnlinkedConst(initializer.arguments[0], '1',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [1]);
|
|
assertUnlinkedConst(initializer.arguments[1], '2',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [2]);
|
|
assertUnlinkedConst(initializer.arguments[2], '3',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [3]);
|
|
expect(initializer.argumentNames, ['b', 'c']);
|
|
}
|
|
|
|
test_constructor_initializers_thisInvocation_unnamed() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('named', executables: serializeClassText(r'''
|
|
class C {
|
|
const C.named() : this(1, 'bbb');
|
|
const C(int a, String b);
|
|
}
|
|
''').executables);
|
|
expect(executable.constantInitializers, hasLength(1));
|
|
UnlinkedConstructorInitializer initializer =
|
|
executable.constantInitializers[0];
|
|
expect(initializer.kind, UnlinkedConstructorInitializerKind.thisInvocation);
|
|
expect(initializer.name, '');
|
|
expect(initializer.expression, isNull);
|
|
expect(initializer.arguments, hasLength(2));
|
|
assertUnlinkedConst(initializer.arguments[0], '1',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [1]);
|
|
assertUnlinkedConst(initializer.arguments[1], "'bbb'",
|
|
operators: [UnlinkedExprOperation.pushString], strings: ['bbb']);
|
|
}
|
|
|
|
test_constructor_initializing_formal() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C(this.x); final x; }').executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.isInitializingFormal, isTrue);
|
|
}
|
|
|
|
test_constructor_initializing_formal_explicit_type() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(int this.x); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
checkTypeRef(parameter.type, 'dart:core', 'int');
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(this.x()); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.isFunctionTyped, isTrue);
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed_explicit_return_type() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C(int this.x()); Function x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
checkTypeRef(parameter.type, 'dart:core', 'int');
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed_implicit_return_type() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(this.x()); Function x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.isFunctionTyped, isTrue);
|
|
expect(parameter.type, isNull);
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed_no_parameters() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(this.x()); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.parameters, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed_parameter() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(this.x(a)); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.parameters, hasLength(1));
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed_parameter_order() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(this.x(a, b)); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.parameters, hasLength(2));
|
|
expect(parameter.parameters[0].name, 'a');
|
|
expect(parameter.parameters[1].name, 'b');
|
|
}
|
|
|
|
test_constructor_initializing_formal_function_typed_withDefault() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
C([this.x() = foo]);
|
|
final x;
|
|
}
|
|
int foo() => 0;
|
|
''').executables);
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.isFunctionTyped, isTrue);
|
|
expect(param.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(param.defaultValueCode, 'foo');
|
|
assertUnlinkedConst(param.initializer.bodyExpr, 'foo', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'foo',
|
|
expectedKind: ReferenceKind.topLevelFunction)
|
|
]);
|
|
}
|
|
|
|
test_constructor_initializing_formal_implicit_type() {
|
|
// Note: the implicit type of an initializing formal is the type of the
|
|
// field.
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C(this.x); int x; }').executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.type, isNull);
|
|
}
|
|
|
|
test_constructor_initializing_formal_name() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C(this.x); final x; }').executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.name, 'x');
|
|
}
|
|
|
|
test_constructor_initializing_formal_named() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C({this.x}); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.kind, UnlinkedParamKind.optionalNamed);
|
|
expect(parameter.initializer, isNull);
|
|
expect(parameter.defaultValueCode, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializing_formal_named_withDefault() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C({this.x: 42}); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.kind, UnlinkedParamKind.optionalNamed);
|
|
expect(parameter.initializer, isNotNull);
|
|
expect(parameter.defaultValueCode, '42');
|
|
_assertCodeRange(parameter.codeRange, 13, 10);
|
|
assertUnlinkedConst(parameter.initializer.bodyExpr, '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_constructor_initializing_formal_non_function_typed() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C(this.x); final x; }').executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.isFunctionTyped, isFalse);
|
|
}
|
|
|
|
test_constructor_initializing_formal_positional() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C([this.x]); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(parameter.initializer, isNull);
|
|
expect(parameter.defaultValueCode, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializing_formal_positional_withDefault() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C([this.x = 42]); final x; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(parameter.initializer, isNotNull);
|
|
expect(parameter.defaultValueCode, '42');
|
|
_assertCodeRange(parameter.codeRange, 13, 11);
|
|
assertUnlinkedConst(parameter.initializer.bodyExpr, '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_constructor_initializing_formal_required() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables:
|
|
serializeClassText('class C { C(this.x); final x; }').executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.kind, UnlinkedParamKind.requiredPositional);
|
|
}
|
|
|
|
test_constructor_initializing_formal_typedef() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText(
|
|
'typedef F<T>(T x); class C<X> { C(this.f); F<X> f; }')
|
|
.executables);
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
expect(parameter.isFunctionTyped, isFalse);
|
|
expect(parameter.parameters, isEmpty);
|
|
}
|
|
|
|
test_constructor_initializing_formal_withDefault() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('', executables: serializeClassText(r'''
|
|
class C {
|
|
C([this.x = 42]);
|
|
final int x;
|
|
}''').executables);
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(param.defaultValueCode, '42');
|
|
assertUnlinkedConst(param.initializer.bodyExpr, '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_constructor_named() {
|
|
String text = 'class C { C.foo(); }';
|
|
UnlinkedExecutable executable = findExecutable('foo',
|
|
executables: serializeClassText(text).executables);
|
|
expect(executable.name, 'foo');
|
|
expect(executable.nameOffset, text.indexOf('foo'));
|
|
expect(executable.periodOffset, text.indexOf('.foo'));
|
|
expect(executable.nameEnd, text.indexOf('()'));
|
|
_assertCodeRange(executable.codeRange, 10, 8);
|
|
}
|
|
|
|
test_constructor_non_const() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(); }').executables);
|
|
expect(executable.isConst, isFalse);
|
|
}
|
|
|
|
test_constructor_non_factory() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(); }').executables);
|
|
expect(executable.isFactory, isFalse);
|
|
}
|
|
|
|
test_constructor_param_inferred_type_explicit() {
|
|
UnlinkedExecutable ctor =
|
|
serializeClassText('class C { C(int v); }').executables[0];
|
|
expect(ctor.kind, UnlinkedExecutableKind.constructor);
|
|
expect(ctor.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_constructor_param_inferred_type_implicit() {
|
|
UnlinkedExecutable ctor =
|
|
serializeClassText('class C { C(v); }').executables[0];
|
|
expect(ctor.kind, UnlinkedExecutableKind.constructor);
|
|
expect(ctor.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_constructor_redirected_factory_named() {
|
|
String text = '''
|
|
class C {
|
|
factory C() = D.named;
|
|
C._();
|
|
}
|
|
class D extends C {
|
|
D.named() : super._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'D')
|
|
]);
|
|
}
|
|
|
|
test_constructor_redirected_factory_named_generic() {
|
|
String text = '''
|
|
class C<T, U> {
|
|
factory C() = D<U, T>.named;
|
|
C._();
|
|
}
|
|
class D<T, U> extends C<U, T> {
|
|
D.named() : super._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'D',
|
|
numTypeParameters: 2)
|
|
],
|
|
numTypeArguments: 2);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
|
|
}
|
|
|
|
test_constructor_redirected_factory_named_imported() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D extends C {
|
|
D.named() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart';
|
|
class C {
|
|
factory C() = D.named;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.classOrEnum,
|
|
'D',
|
|
absoluteUri: absUri('/foo.dart'),
|
|
)
|
|
]);
|
|
}
|
|
|
|
test_constructor_redirected_factory_named_imported_generic() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D<T, U> extends C<U, T> {
|
|
D.named() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart';
|
|
class C<T, U> {
|
|
factory C() = D<U, T>.named;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.classOrEnum,
|
|
'D',
|
|
numTypeParameters: 2,
|
|
absoluteUri: absUri('/foo.dart'),
|
|
)
|
|
],
|
|
numTypeArguments: 2);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
|
|
}
|
|
|
|
test_constructor_redirected_factory_named_prefixed() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D extends C {
|
|
D.named() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart' as foo;
|
|
class C {
|
|
factory C() = foo.D.named;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.classOrEnum,
|
|
'D',
|
|
absoluteUri: absUri('/foo.dart'),
|
|
),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'foo')
|
|
]);
|
|
}
|
|
|
|
test_constructor_redirected_factory_named_prefixed_generic() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D<T, U> extends C<U, T> {
|
|
D.named() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart' as foo;
|
|
class C<T, U> {
|
|
factory C() = foo.D<U, T>.named;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.classOrEnum,
|
|
'D',
|
|
numTypeParameters: 2,
|
|
absoluteUri: absUri('/foo.dart'),
|
|
),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'foo')
|
|
],
|
|
numTypeArguments: 2);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
|
|
}
|
|
|
|
test_constructor_redirected_factory_unnamed() {
|
|
String text = '''
|
|
class C {
|
|
factory C() = D;
|
|
C._();
|
|
}
|
|
class D extends C {
|
|
D() : super._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'D');
|
|
}
|
|
|
|
test_constructor_redirected_factory_unnamed_generic() {
|
|
String text = '''
|
|
class C<T, U> {
|
|
factory C() = D<U, T>;
|
|
C._();
|
|
}
|
|
class D<T, U> extends C<U, T> {
|
|
D() : super._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, null, 'D',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
|
|
}
|
|
|
|
test_constructor_redirected_factory_unnamed_imported() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D extends C {
|
|
D() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart';
|
|
class C {
|
|
factory C() = D;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, absUri('/foo.dart'), 'D');
|
|
}
|
|
|
|
test_constructor_redirected_factory_unnamed_imported_generic() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D<T, U> extends C<U, T> {
|
|
D() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart';
|
|
class C<T, U> {
|
|
factory C() = D<U, T>;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, absUri('/foo.dart'), 'D',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
|
|
}
|
|
|
|
test_constructor_redirected_factory_unnamed_prefixed() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D extends C {
|
|
D() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart' as foo;
|
|
class C {
|
|
factory C() = foo.D;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, absUri('/foo.dart'), 'D',
|
|
expectedPrefix: 'foo');
|
|
}
|
|
|
|
test_constructor_redirected_factory_unnamed_prefixed_generic() {
|
|
addNamedSource('/foo.dart', '''
|
|
import 'test.dart';
|
|
class D<T, U> extends C<U, T> {
|
|
D() : super._();
|
|
}
|
|
''');
|
|
String text = '''
|
|
import 'foo.dart' as foo;
|
|
class C<T, U> {
|
|
factory C() = foo.D<U, T>;
|
|
C._();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isTrue);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
checkTypeRef(executable.redirectedConstructor, absUri('/foo.dart'), 'D',
|
|
numTypeParameters: 2, expectedPrefix: 'foo', numTypeArguments: 2);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
|
|
checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
|
|
}
|
|
|
|
test_constructor_redirected_thisInvocation_named() {
|
|
String text = '''
|
|
class C {
|
|
C() : this.named();
|
|
C.named();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isFalse);
|
|
expect(executable.redirectedConstructorName, 'named');
|
|
expect(executable.redirectedConstructor, isNull);
|
|
}
|
|
|
|
test_constructor_redirected_thisInvocation_unnamed() {
|
|
String text = '''
|
|
class C {
|
|
C.named() : this();
|
|
C();
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable =
|
|
serializeClassText(text, className: 'C').executables[0];
|
|
expect(executable.isRedirectedConstructor, isTrue);
|
|
expect(executable.isFactory, isFalse);
|
|
expect(executable.redirectedConstructorName, isEmpty);
|
|
expect(executable.redirectedConstructor, isNull);
|
|
}
|
|
|
|
test_constructor_return_type() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C { C(); }').executables);
|
|
expect(executable.returnType, isNull);
|
|
}
|
|
|
|
test_constructor_return_type_parameterized() {
|
|
UnlinkedExecutable executable = findExecutable('',
|
|
executables: serializeClassText('class C<T, U> { C(); }').executables);
|
|
expect(executable.returnType, isNull);
|
|
}
|
|
|
|
test_constructor_withCycles_const() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = const D();
|
|
}
|
|
class D {
|
|
final x;
|
|
const D() : x = const C();
|
|
}
|
|
class E {
|
|
final x;
|
|
const E() : x = null;
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('D');
|
|
checkConstCycle('E', hasCycle: false);
|
|
}
|
|
|
|
test_constructor_withCycles_nonConst() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
C() : x = new D();
|
|
}
|
|
class D {
|
|
final x;
|
|
D() : x = new C();
|
|
}
|
|
''');
|
|
expect(findClass('C').executables[0].constCycleSlot, 0);
|
|
expect(findClass('D').executables[0].constCycleSlot, 0);
|
|
}
|
|
|
|
test_constructorCycle_redirectToImplicitConstructor() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
const factory C() = D;
|
|
}
|
|
class D extends C {}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_redirectToNonConstConstructor() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
class C {
|
|
const factory C() = D;
|
|
}
|
|
class D extends C {
|
|
D();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_redirectToSymbolConstructor() {
|
|
// The symbol constructor has some special case behaviors in analyzer.
|
|
// Make sure those special case behaviors don't cause problems.
|
|
serializeLibraryText('''
|
|
class C {
|
|
const factory C(String name) = Symbol;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToClass() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = C;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToEnum() {
|
|
serializeLibraryText('''
|
|
enum E { v }
|
|
class C {
|
|
final x;
|
|
const C() : x = E;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToEnumValue() {
|
|
serializeLibraryText('''
|
|
enum E { v }
|
|
class C {
|
|
final x;
|
|
const C() : x = E.v;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToEnumValues() {
|
|
serializeLibraryText('''
|
|
enum E { v }
|
|
class C {
|
|
final x;
|
|
const C() : x = E.values;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToGenericParameter() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
class C<T> {
|
|
final x;
|
|
const C() : x = T;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToGenericParameter_asSupertype() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
class C<T> extends T {
|
|
const C();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToStaticMethod_inOtherClass() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = D.f;
|
|
}
|
|
class D {
|
|
static void f() {}
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToStaticMethod_inSameClass() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
static void f() {}
|
|
const C() : x = f;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToTopLevelFunction() {
|
|
serializeLibraryText('''
|
|
void f() {}
|
|
class C {
|
|
final x;
|
|
const C() : x = f;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToTypedef() {
|
|
serializeLibraryText('''
|
|
typedef F();
|
|
class C {
|
|
final x;
|
|
const C() : x = F;
|
|
}
|
|
''');
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToUndefinedName() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = foo;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToUndefinedName_viaPrefix() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
addNamedSource('/a.dart', '');
|
|
serializeLibraryText('''
|
|
import 'a.dart' as a;
|
|
class C {
|
|
final x;
|
|
const C() : x = a.foo;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_referenceToUndefinedName_viaPrefix_nonExistentFile() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
allowMissingFiles = true;
|
|
serializeLibraryText('''
|
|
import 'a.dart' as a;
|
|
class C {
|
|
final x;
|
|
const C() : x = a.foo;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_trivial() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
const C() : this();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaFactoryRedirect() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
const C();
|
|
const factory C.named() = D;
|
|
}
|
|
class D extends C {
|
|
final x;
|
|
const D() : x = y;
|
|
}
|
|
const y = const C.named();
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
checkConstCycle('C', name: 'named');
|
|
checkConstCycle('D');
|
|
}
|
|
|
|
test_constructorCycle_viaFinalField() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x = const C();
|
|
const C();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaLength() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = y.length;
|
|
}
|
|
const y = const C();
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaNamedConstructor() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = const D.named();
|
|
}
|
|
class D {
|
|
final x;
|
|
const D.named() : x = const C();
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('D', name: 'named');
|
|
}
|
|
|
|
test_constructorCycle_viaOrdinaryRedirect() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : this.named();
|
|
const C.named() : x = const C();
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('C', name: 'named');
|
|
}
|
|
|
|
test_constructorCycle_viaOrdinaryRedirect_suppressSupertype() {
|
|
// Since C redirects to C.named, it doesn't implicitly refer to B's unnamed
|
|
// constructor. Therefore there is no cycle.
|
|
serializeLibraryText('''
|
|
class B {
|
|
final x;
|
|
const B() : x = const C();
|
|
const B.named() : x = null;
|
|
}
|
|
class C extends B {
|
|
const C() : this.named();
|
|
const C.named() : super.named();
|
|
}
|
|
''');
|
|
checkConstCycle('B', hasCycle: false);
|
|
checkConstCycle('B', name: 'named', hasCycle: false);
|
|
checkConstCycle('C', hasCycle: false);
|
|
checkConstCycle('C', name: 'named', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_viaRedirectArgument() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : this.named(y);
|
|
const C.named(this.x);
|
|
}
|
|
const y = const C();
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
checkConstCycle('C', name: 'named', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_viaStaticField_inOtherClass() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = D.y;
|
|
}
|
|
class D {
|
|
static const y = const C();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaStaticField_inSameClass() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
static const y = const C();
|
|
const C() : x = y;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaSuperArgument() {
|
|
serializeLibraryText('''
|
|
class B {
|
|
final x;
|
|
const B(this.x);
|
|
}
|
|
class C extends B {
|
|
const C() : super(y);
|
|
}
|
|
const y = const C();
|
|
''', allowErrors: true);
|
|
checkConstCycle('B', hasCycle: false);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaSupertype() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = const D();
|
|
}
|
|
class D extends C {
|
|
const D();
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('D');
|
|
}
|
|
|
|
test_constructorCycle_viaSupertype_Enum() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
enum E { v }
|
|
class C extends E {
|
|
const C();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_viaSupertype_explicit() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = const D();
|
|
const C.named() : x = const D.named();
|
|
}
|
|
class D extends C {
|
|
const D() : super();
|
|
const D.named() : super.named();
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('C', name: 'named');
|
|
checkConstCycle('D');
|
|
checkConstCycle('D', name: 'named');
|
|
}
|
|
|
|
test_constructorCycle_viaSupertype_explicit_undefined() {
|
|
// It's not valid Dart but we need to make sure it doesn't crash
|
|
// summary generation.
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = const D();
|
|
}
|
|
class D extends C {
|
|
const D() : super.named();
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C', hasCycle: false);
|
|
checkConstCycle('D', hasCycle: false);
|
|
}
|
|
|
|
test_constructorCycle_viaSupertype_withDefaultTypeArgument() {
|
|
serializeLibraryText('''
|
|
class C<T> {
|
|
final x;
|
|
const C() : x = const D();
|
|
}
|
|
class D extends C {
|
|
const D();
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('D');
|
|
}
|
|
|
|
test_constructorCycle_viaSupertype_withTypeArgument() {
|
|
serializeLibraryText('''
|
|
class C<T> {
|
|
final x;
|
|
const C() : x = const D();
|
|
}
|
|
class D extends C<int> {
|
|
const D();
|
|
}
|
|
''');
|
|
checkConstCycle('C');
|
|
checkConstCycle('D');
|
|
}
|
|
|
|
test_constructorCycle_viaTopLevelVariable() {
|
|
serializeLibraryText('''
|
|
class C {
|
|
final x;
|
|
const C() : x = y;
|
|
}
|
|
const y = const C();
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaTopLevelVariable_imported() {
|
|
addNamedSource('/a.dart', '''
|
|
import 'test.dart';
|
|
const y = const C();
|
|
''');
|
|
serializeLibraryText('''
|
|
import 'a.dart';
|
|
class C {
|
|
final x;
|
|
const C() : x = y;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_constructorCycle_viaTopLevelVariable_importedViaPrefix() {
|
|
addNamedSource('/a.dart', '''
|
|
import 'test.dart';
|
|
const y = const C();
|
|
''');
|
|
serializeLibraryText('''
|
|
import 'a.dart' as a;
|
|
class C {
|
|
final x;
|
|
const C() : x = a.y;
|
|
}
|
|
''', allowErrors: true);
|
|
checkConstCycle('C');
|
|
}
|
|
|
|
test_dependencies_export_to_export_unused() {
|
|
addNamedSource('/a.dart', 'export "b.dart";');
|
|
addNamedSource('/b.dart', '');
|
|
serializeLibraryText('export "a.dart";');
|
|
// The main test library depends on b.dart, even though it doesn't
|
|
// re-export any names defined in b.dart, because a change to b.dart might
|
|
// cause it to start exporting a name that the main test library *does*
|
|
// use.
|
|
checkHasDependency(absUri('/b.dart'));
|
|
}
|
|
|
|
test_dependencies_export_unused() {
|
|
addNamedSource('/a.dart', '');
|
|
serializeLibraryText('export "a.dart";');
|
|
// The main test library depends on a.dart, even though it doesn't
|
|
// re-export any names defined in a.dart, because a change to a.dart might
|
|
// cause it to start exporting a name that the main test library *will*
|
|
// re-export.
|
|
checkHasDependency(absUri('/a.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export() {
|
|
addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
|
|
addNamedSource('/b.dart', 'library b;');
|
|
serializeLibraryText('import "a.dart"; A a;');
|
|
checkHasDependency(absUri('/a.dart'));
|
|
// The main test library depends on b.dart, because names defined in
|
|
// b.dart are exported by a.dart.
|
|
checkHasDependency(absUri('/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export_in_subdirs_absolute_export() {
|
|
addNamedSource('/a/a.dart',
|
|
'library a; export "${absUri('/a/b/b.dart')}"; class A {}');
|
|
addNamedSource('/a/b/b.dart', 'library b;');
|
|
serializeLibraryText('import "a/a.dart"; A a;');
|
|
checkHasDependency(absUri('/a/a.dart'));
|
|
// The main test library depends on b.dart, because names defined in
|
|
// b.dart are exported by a.dart.
|
|
checkHasDependency(absUri('/a/b/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export_in_subdirs_absolute_import() {
|
|
addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
|
|
addNamedSource('/a/b/b.dart', 'library b;');
|
|
serializeLibraryText('import "${absUri('/a/a.dart')}"; A a;');
|
|
checkHasDependency(absUri('/a/a.dart'));
|
|
// The main test library depends on b.dart, because names defined in
|
|
// b.dart are exported by a.dart.
|
|
checkHasDependency(absUri('/a/b/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export_in_subdirs_relative() {
|
|
addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
|
|
addNamedSource('/a/b/b.dart', 'library b;');
|
|
serializeLibraryText('import "a/a.dart"; A a;');
|
|
checkHasDependency(absUri('/a/a.dart'));
|
|
// The main test library depends on b.dart, because names defined in
|
|
// b.dart are exported by a.dart.
|
|
checkHasDependency(absUri('/a/b/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export_loop() {
|
|
addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
|
|
addNamedSource('/b.dart', 'library b; export "a.dart";');
|
|
serializeLibraryText('import "a.dart"; A a;');
|
|
checkHasDependency(absUri('/a.dart'));
|
|
// Serialization should have been able to walk the transitive export
|
|
// dependencies to b.dart without going into an infinite loop.
|
|
checkHasDependency(absUri('/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export_transitive_closure() {
|
|
addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
|
|
addNamedSource('/b.dart', 'library b; export "c.dart";');
|
|
addNamedSource('/c.dart', 'library c;');
|
|
serializeLibraryText('import "a.dart"; A a;');
|
|
checkHasDependency(absUri('/a.dart'));
|
|
// The main test library depends on c.dart, because names defined in
|
|
// c.dart are exported by b.dart and then re-exported by a.dart.
|
|
checkHasDependency(absUri('/c.dart'));
|
|
}
|
|
|
|
test_dependencies_import_to_export_unused() {
|
|
addNamedSource('/a.dart', 'export "b.dart";');
|
|
addNamedSource('/b.dart', '');
|
|
serializeLibraryText('import "a.dart";', allowErrors: true);
|
|
// The main test library depends on b.dart, even though it doesn't use any
|
|
// names defined in b.dart, because a change to b.dart might cause it to
|
|
// start exporting a name that the main test library *does* use.
|
|
checkHasDependency(absUri('/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_transitive_closure() {
|
|
addNamedSource(
|
|
'/a.dart', 'library a; import "b.dart"; class A extends B {}');
|
|
addNamedSource('/b.dart', 'library b; class B {}');
|
|
serializeLibraryText('import "a.dart"; A a;');
|
|
checkHasDependency(absUri('/a.dart'));
|
|
// The main test library doesn't depend on b.dart, because no change to
|
|
// b.dart can possibly affect the serialized element model for it.
|
|
checkLacksDependency(absUri('/b.dart'));
|
|
}
|
|
|
|
test_dependencies_import_unused() {
|
|
addNamedSource('/a.dart', '');
|
|
serializeLibraryText('import "a.dart";', allowErrors: true);
|
|
// The main test library depends on a.dart, even though it doesn't use any
|
|
// names defined in a.dart, because a change to a.dart might cause it to
|
|
// start exporting a name that the main test library *does* use.
|
|
checkHasDependency(absUri('/a.dart'));
|
|
}
|
|
|
|
test_dependencies_parts() {
|
|
addNamedSource(
|
|
'/a.dart', 'library a; part "b.dart"; part "c.dart"; class A {}');
|
|
addNamedSource('/b.dart', 'part of a;');
|
|
addNamedSource('/c.dart', 'part of a;');
|
|
serializeLibraryText('import "a.dart"; A a;');
|
|
int dep = checkHasDependency(absUri('/a.dart'));
|
|
checkDependencyParts(
|
|
linked.dependencies[dep], [absUri('/b.dart'), absUri('/c.dart')]);
|
|
}
|
|
|
|
test_dependencies_parts_relative_to_importing_library() {
|
|
addNamedSource('/a/b.dart', 'export "c/d.dart";');
|
|
addNamedSource('/a/c/d.dart',
|
|
'library d; part "e/f.dart"; part "g/h.dart"; class D {}');
|
|
addNamedSource('/a/c/e/f.dart', 'part of d;');
|
|
addNamedSource('/a/c/g/h.dart', 'part of d;');
|
|
serializeLibraryText('import "a/b.dart"; D d;');
|
|
int dep = checkHasDependency(absUri('/a/c/d.dart'));
|
|
checkDependencyParts(linked.dependencies[dep],
|
|
[absUri('/a/c/e/f.dart'), absUri('/a/c/g/h.dart')]);
|
|
}
|
|
|
|
test_elements_in_part() {
|
|
addNamedSource('/part1.dart', '''
|
|
part of my.lib;
|
|
|
|
class C {}
|
|
enum E { v }
|
|
var v;
|
|
f() {}
|
|
typedef F();
|
|
''');
|
|
serializeLibraryText('library my.lib; part "part1.dart";');
|
|
UnlinkedUnit unit = unlinkedUnits[1];
|
|
expect(findClass('C', unit: unit), isNotNull);
|
|
expect(findEnum('E', unit: unit), isNotNull);
|
|
expect(findVariable('v', variables: unit.variables), isNotNull);
|
|
expect(findExecutable('f', executables: unit.executables), isNotNull);
|
|
expect(findTypedef('F', unit: unit), isNotNull);
|
|
}
|
|
|
|
test_enum() {
|
|
String text = 'enum E { v1 }';
|
|
UnlinkedEnum e = serializeEnumText(text);
|
|
expect(e.name, 'E');
|
|
expect(e.nameOffset, text.indexOf('E'));
|
|
expect(e.values, hasLength(1));
|
|
expect(e.values[0].name, 'v1');
|
|
expect(e.values[0].nameOffset, text.indexOf('v1'));
|
|
_assertCodeRange(e.codeRange, 0, 13);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
|
|
ReferenceKind.classOrEnum);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'E');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(2));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].kind,
|
|
ReferenceKind.propertyAccessor);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'values');
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].numTypeParameters,
|
|
0);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[1].kind,
|
|
ReferenceKind.propertyAccessor);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[1].name, 'v1');
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[1].numTypeParameters,
|
|
0);
|
|
}
|
|
|
|
test_enum_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
enum E { v }''';
|
|
UnlinkedEnum enm = serializeEnumText(text);
|
|
expect(enm.documentationComment, isNotNull);
|
|
checkDocumentationComment(enm.documentationComment, text);
|
|
}
|
|
|
|
test_enum_order() {
|
|
UnlinkedEnum e = serializeEnumText('enum E { v1, v2 }');
|
|
expect(e.values, hasLength(2));
|
|
expect(e.values[0].name, 'v1');
|
|
expect(e.values[1].name, 'v2');
|
|
}
|
|
|
|
test_enum_private() {
|
|
serializeEnumText('enum _E { v1 }', '_E');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
}
|
|
|
|
test_enum_value_documented() {
|
|
String text = '''
|
|
enum E {
|
|
/**
|
|
* Docs
|
|
*/
|
|
v
|
|
}''';
|
|
UnlinkedEnumValue value = serializeEnumText(text).values[0];
|
|
expect(value.documentationComment, isNotNull);
|
|
checkDocumentationComment(value.documentationComment, text);
|
|
}
|
|
|
|
test_enum_value_private() {
|
|
serializeEnumText('enum E { _v }', 'E');
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'values');
|
|
}
|
|
|
|
test_executable_abstract() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('abstract class C { f(); }').executables[0];
|
|
expect(executable.isAbstract, isTrue);
|
|
}
|
|
|
|
test_executable_concrete() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('abstract class C { f() {} }').executables[0];
|
|
expect(executable.isAbstract, isFalse);
|
|
}
|
|
|
|
test_executable_function() {
|
|
String text = ' f() {}';
|
|
UnlinkedExecutable executable = serializeExecutableText(text);
|
|
expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
|
|
expect(executable.returnType, isNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.nameOffset, text.indexOf('f'));
|
|
expect(executable.visibleOffset, 0);
|
|
expect(executable.visibleLength, 0);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
|
|
ReferenceKind.topLevelFunction);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
|
|
}
|
|
|
|
test_executable_function_async() {
|
|
UnlinkedExecutable executable = serializeExecutableText(r'''
|
|
import 'dart:async';
|
|
Future f() async {}
|
|
''');
|
|
expect(executable.isAsynchronous, isTrue);
|
|
expect(executable.isGenerator, isFalse);
|
|
}
|
|
|
|
test_executable_function_asyncStar() {
|
|
UnlinkedExecutable executable = serializeExecutableText(r'''
|
|
import 'dart:async';
|
|
Stream f() async* {}
|
|
''');
|
|
expect(executable.isAsynchronous, isTrue);
|
|
expect(executable.isGenerator, isTrue);
|
|
}
|
|
|
|
test_executable_function_explicit_return() {
|
|
UnlinkedExecutable executable =
|
|
serializeExecutableText('dynamic f() => null;');
|
|
checkDynamicTypeRef(executable.returnType);
|
|
}
|
|
|
|
test_executable_function_external() {
|
|
UnlinkedExecutable executable = serializeExecutableText('external f();');
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_executable_function_private() {
|
|
serializeExecutableText('_f() {}', executableName: '_f');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
}
|
|
|
|
test_executable_getter() {
|
|
String text = 'int get f => 1;';
|
|
UnlinkedExecutable executable = serializeExecutableText(text);
|
|
expect(executable.kind, UnlinkedExecutableKind.getter);
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.nameOffset, text.indexOf('f'));
|
|
expect(findVariable('f'), isNull);
|
|
expect(findExecutable('f='), isNull);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
|
|
}
|
|
|
|
test_executable_getter_external() {
|
|
UnlinkedExecutable executable =
|
|
serializeExecutableText('external int get f;');
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_executable_getter_private() {
|
|
serializeExecutableText('int get _f => 1;', executableName: '_f');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
}
|
|
|
|
test_executable_getter_type() {
|
|
UnlinkedExecutable executable = serializeExecutableText('int get f => 1;');
|
|
checkTypeRef(executable.returnType, 'dart:core', 'int');
|
|
expect(executable.parameters, isEmpty);
|
|
}
|
|
|
|
test_executable_getter_type_implicit() {
|
|
UnlinkedExecutable executable = serializeExecutableText('get f => 1;');
|
|
expect(executable.returnType, isNull);
|
|
expect(executable.parameters, isEmpty);
|
|
}
|
|
|
|
test_executable_localFunctions() {
|
|
String code = r'''
|
|
f() {
|
|
f1() {}
|
|
{
|
|
f2() {}
|
|
}
|
|
}
|
|
''';
|
|
UnlinkedExecutable executable = serializeExecutableText(code);
|
|
List<UnlinkedExecutable> functions = executable.localFunctions;
|
|
expect(functions, isEmpty);
|
|
}
|
|
|
|
test_executable_member_function() {
|
|
UnlinkedExecutable executable = findExecutable('f',
|
|
executables: serializeClassText('class C { f() {} }').executables);
|
|
expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
|
|
expect(executable.returnType, isNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.visibleOffset, 0);
|
|
expect(executable.visibleLength, 0);
|
|
_assertCodeRange(executable.codeRange, 10, 6);
|
|
}
|
|
|
|
test_executable_member_function_async() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f', executables: serializeClassText(r'''
|
|
import 'dart:async';
|
|
class C {
|
|
Future f() async {}
|
|
}
|
|
''').executables);
|
|
expect(executable.isAsynchronous, isTrue);
|
|
expect(executable.isGenerator, isFalse);
|
|
}
|
|
|
|
test_executable_member_function_asyncStar() {
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f', executables: serializeClassText(r'''
|
|
import 'dart:async';
|
|
class C {
|
|
Stream f() async* {}
|
|
}
|
|
''').executables);
|
|
expect(executable.isAsynchronous, isTrue);
|
|
expect(executable.isGenerator, isTrue);
|
|
}
|
|
|
|
test_executable_member_function_explicit_return() {
|
|
UnlinkedExecutable executable = findExecutable('f',
|
|
executables:
|
|
serializeClassText('class C { dynamic f() => null; }').executables);
|
|
expect(executable.returnType, isNotNull);
|
|
}
|
|
|
|
test_executable_member_function_external() {
|
|
UnlinkedExecutable executable = findExecutable('f',
|
|
executables:
|
|
serializeClassText('class C { external f(); }').executables);
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_executable_member_getter() {
|
|
UnlinkedClass cls = serializeClassText('class C { int get f => 1; }');
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f', executables: cls.executables, failIfAbsent: true);
|
|
expect(executable.kind, UnlinkedExecutableKind.getter);
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.isStatic, isFalse);
|
|
_assertCodeRange(executable.codeRange, 10, 15);
|
|
expect(findVariable('f', variables: cls.fields), isNull);
|
|
expect(findExecutable('f=', executables: cls.executables), isNull);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, isEmpty);
|
|
}
|
|
|
|
test_executable_member_getter_external() {
|
|
UnlinkedClass cls = serializeClassText('class C { external int get f; }');
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f', executables: cls.executables, failIfAbsent: true);
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_executable_member_getter_static() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C { static int get f => 1; }');
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f', executables: cls.executables, failIfAbsent: true);
|
|
expect(executable.isStatic, isTrue);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'f');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].kind,
|
|
ReferenceKind.propertyAccessor);
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].numTypeParameters,
|
|
0);
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].members, isEmpty);
|
|
}
|
|
|
|
test_executable_member_setter() {
|
|
UnlinkedClass cls = serializeClassText('class C { void set f(value) {} }');
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f=', executables: cls.executables, failIfAbsent: true);
|
|
expect(executable.kind, UnlinkedExecutableKind.setter);
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
_assertCodeRange(executable.codeRange, 10, 20);
|
|
expect(findVariable('f', variables: cls.fields), isNull);
|
|
expect(findExecutable('f', executables: cls.executables), isNull);
|
|
}
|
|
|
|
test_executable_member_setter_external() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C { external void set f(value); }');
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f=', executables: cls.executables, failIfAbsent: true);
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_executable_member_setter_implicit_return() {
|
|
UnlinkedClass cls = serializeClassText('class C { set f(value) {} }');
|
|
UnlinkedExecutable executable =
|
|
findExecutable('f=', executables: cls.executables, failIfAbsent: true);
|
|
expect(executable.returnType, isNull);
|
|
}
|
|
|
|
test_executable_name() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f() {}');
|
|
expect(executable.name, 'f');
|
|
}
|
|
|
|
test_executable_no_flags() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f() {}');
|
|
expect(executable.isAbstract, isFalse);
|
|
expect(executable.isConst, isFalse);
|
|
expect(executable.isFactory, isFalse);
|
|
expect(executable.isStatic, isFalse);
|
|
}
|
|
|
|
test_executable_non_static() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { f() {} }').executables[0];
|
|
expect(executable.isStatic, isFalse);
|
|
}
|
|
|
|
test_executable_non_static_top_level() {
|
|
// Top level executables are considered non-static.
|
|
UnlinkedExecutable executable = serializeExecutableText('f() {}');
|
|
expect(executable.isStatic, isFalse);
|
|
}
|
|
|
|
test_executable_operator() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { C operator+(C c) => null; }')
|
|
.executables[0];
|
|
expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
|
|
expect(executable.name, '+');
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAbstract, false);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isConst, false);
|
|
expect(executable.isFactory, false);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.isStatic, false);
|
|
expect(executable.parameters, hasLength(1));
|
|
checkTypeRef(executable.returnType, null, 'C');
|
|
expect(executable.typeParameters, isEmpty);
|
|
expect(executable.isExternal, false);
|
|
}
|
|
|
|
test_executable_operator_abstract() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { C operator+(C c); }', allowErrors: true)
|
|
.executables[0];
|
|
expect(executable.isAbstract, true);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, false);
|
|
expect(executable.isGenerator, isFalse);
|
|
}
|
|
|
|
test_executable_operator_equal() {
|
|
UnlinkedExecutable executable = serializeClassText(
|
|
'class C { bool operator==(Object other) => false; }')
|
|
.executables[0];
|
|
expect(executable.name, '==');
|
|
}
|
|
|
|
test_executable_operator_external() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { external C operator+(C c); }')
|
|
.executables[0];
|
|
expect(executable.isAbstract, false);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, true);
|
|
expect(executable.isGenerator, isFalse);
|
|
}
|
|
|
|
test_executable_operator_greater_equal() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { bool operator>=(C other) => false; }')
|
|
.executables[0];
|
|
expect(executable.name, '>=');
|
|
}
|
|
|
|
test_executable_operator_index() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { bool operator[](int i) => null; }')
|
|
.executables[0];
|
|
expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
|
|
expect(executable.name, '[]');
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAbstract, false);
|
|
expect(executable.isConst, false);
|
|
expect(executable.isFactory, false);
|
|
expect(executable.isStatic, false);
|
|
expect(executable.parameters, hasLength(1));
|
|
checkTypeRef(executable.returnType, 'dart:core', 'bool');
|
|
expect(executable.typeParameters, isEmpty);
|
|
}
|
|
|
|
test_executable_operator_index_set() {
|
|
UnlinkedExecutable executable = serializeClassText(
|
|
'class C { void operator[]=(int i, bool v) => null; }')
|
|
.executables[0];
|
|
expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
|
|
expect(executable.name, '[]=');
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAbstract, false);
|
|
expect(executable.isConst, false);
|
|
expect(executable.isFactory, false);
|
|
expect(executable.isStatic, false);
|
|
expect(executable.parameters, hasLength(2));
|
|
checkVoidTypeRef(executable.returnType);
|
|
expect(executable.typeParameters, isEmpty);
|
|
}
|
|
|
|
test_executable_operator_less_equal() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { bool operator<=(C other) => false; }')
|
|
.executables[0];
|
|
expect(executable.name, '<=');
|
|
}
|
|
|
|
test_executable_param_codeRange() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(int x) {}');
|
|
UnlinkedParam parameter = executable.parameters[0];
|
|
_assertCodeRange(parameter.codeRange, 2, 5);
|
|
}
|
|
|
|
test_executable_param_function_typed() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
|
|
expect(executable.parameters[0].isFunctionTyped, isTrue);
|
|
expect(executable.parameters[0].type, isNull);
|
|
}
|
|
|
|
test_executable_param_function_typed_explicit_return_type() {
|
|
UnlinkedExecutable executable =
|
|
serializeExecutableText('f(dynamic g()) {}');
|
|
expect(executable.parameters[0].type, isNotNull);
|
|
}
|
|
|
|
test_executable_param_function_typed_param() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(g(x)) {}');
|
|
expect(executable.parameters[0].parameters, hasLength(1));
|
|
}
|
|
|
|
test_executable_param_function_typed_param_none() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
|
|
expect(executable.parameters[0].parameters, isEmpty);
|
|
}
|
|
|
|
test_executable_param_function_typed_param_order() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(g(x, y)) {}');
|
|
expect(executable.parameters[0].parameters, hasLength(2));
|
|
expect(executable.parameters[0].parameters[0].name, 'x');
|
|
expect(executable.parameters[0].parameters[1].name, 'y');
|
|
}
|
|
|
|
test_executable_param_function_typed_return_type() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(int g()) {}');
|
|
checkTypeRef(executable.parameters[0].type, 'dart:core', 'int');
|
|
}
|
|
|
|
test_executable_param_function_typed_return_type_implicit() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
|
|
expect(executable.parameters[0].isFunctionTyped, isTrue);
|
|
expect(executable.parameters[0].type, isNull);
|
|
}
|
|
|
|
test_executable_param_function_typed_return_type_void() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(void g()) {}');
|
|
checkVoidTypeRef(executable.parameters[0].type);
|
|
}
|
|
|
|
test_executable_param_function_typed_withDefault() {
|
|
UnlinkedExecutable executable = serializeExecutableText(r'''
|
|
f([int p(int a2, String b2) = foo]) {}
|
|
int foo(int a, String b) => 0;
|
|
''');
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(param.initializer, isNotNull);
|
|
expect(param.defaultValueCode, 'foo');
|
|
assertUnlinkedConst(param.initializer.bodyExpr, 'foo', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'foo',
|
|
expectedKind: ReferenceKind.topLevelFunction)
|
|
]);
|
|
}
|
|
|
|
test_executable_param_isFinal() {
|
|
String text = 'f(x, final y) {}';
|
|
UnlinkedExecutable executable = serializeExecutableText(text);
|
|
expect(executable.parameters, hasLength(2));
|
|
expect(executable.parameters[0].name, 'x');
|
|
expect(executable.parameters[0].isFinal, isFalse);
|
|
expect(executable.parameters[1].name, 'y');
|
|
expect(executable.parameters[1].isFinal, isTrue);
|
|
}
|
|
|
|
test_executable_param_kind_named() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.optionalNamed);
|
|
expect(param.initializer, isNull);
|
|
expect(param.defaultValueCode, isEmpty);
|
|
}
|
|
|
|
test_executable_param_kind_named_withDefault() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f({x: 42}) {}');
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.optionalNamed);
|
|
expect(param.initializer, isNotNull);
|
|
expect(param.defaultValueCode, '42');
|
|
_assertCodeRange(param.codeRange, 3, 5);
|
|
assertUnlinkedConst(param.initializer.bodyExpr, '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_executable_param_kind_positional() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(param.initializer, isNull);
|
|
expect(param.defaultValueCode, isEmpty);
|
|
}
|
|
|
|
test_executable_param_kind_positional_withDefault() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f([x = 42]) {}');
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.optionalPositional);
|
|
expect(param.initializer, isNotNull);
|
|
expect(param.defaultValueCode, '42');
|
|
_assertCodeRange(param.codeRange, 3, 6);
|
|
assertUnlinkedConst(param.initializer.bodyExpr, '42',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [42]);
|
|
}
|
|
|
|
test_executable_param_kind_required() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
|
|
UnlinkedParam param = executable.parameters[0];
|
|
expect(param.kind, UnlinkedParamKind.requiredPositional);
|
|
expect(param.initializer, isNull);
|
|
expect(param.defaultValueCode, isEmpty);
|
|
}
|
|
|
|
test_executable_param_name() {
|
|
String text = 'f(x) {}';
|
|
UnlinkedExecutable executable = serializeExecutableText(text);
|
|
expect(executable.parameters, hasLength(1));
|
|
expect(executable.parameters[0].name, 'x');
|
|
expect(executable.parameters[0].nameOffset, text.indexOf('x'));
|
|
}
|
|
|
|
test_executable_param_no_flags() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
|
|
expect(executable.parameters[0].isFunctionTyped, isFalse);
|
|
expect(executable.parameters[0].isInitializingFormal, isFalse);
|
|
}
|
|
|
|
test_executable_param_non_function_typed() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(g) {}');
|
|
expect(executable.parameters[0].isFunctionTyped, isFalse);
|
|
}
|
|
|
|
test_executable_param_none() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f() {}');
|
|
expect(executable.parameters, isEmpty);
|
|
}
|
|
|
|
test_executable_param_of_constructor_no_covariance() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { C(x); }').executables[0];
|
|
expect(executable.parameters[0].inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_executable_param_of_method_covariance() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { m(x) {} }').executables[0];
|
|
expect(executable.parameters[0].inheritsCovariantSlot, isNot(0));
|
|
}
|
|
|
|
test_executable_param_of_param_no_covariance() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { m(f(x)) {} }').executables[0];
|
|
expect(executable.parameters[0].parameters[0].inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_executable_param_of_setter_covariance() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { void set s(x) {} }').executables[0];
|
|
expect(executable.parameters[0].inheritsCovariantSlot, isNot(0));
|
|
}
|
|
|
|
test_executable_param_of_static_method_no_covariance() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { static m(x) {} }').executables[0];
|
|
expect(executable.parameters[0].inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_executable_param_of_top_level_function_no_covariance() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
|
|
expect(executable.parameters[0].inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_executable_param_order() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(x, y) {}');
|
|
expect(executable.parameters, hasLength(2));
|
|
expect(executable.parameters[0].name, 'x');
|
|
expect(executable.parameters[1].name, 'y');
|
|
}
|
|
|
|
test_executable_param_type_explicit() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(dynamic x) {}');
|
|
checkDynamicTypeRef(executable.parameters[0].type);
|
|
}
|
|
|
|
test_executable_param_type_implicit() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
|
|
expect(executable.parameters[0].type, isNull);
|
|
}
|
|
|
|
test_executable_param_type_typedef() {
|
|
UnlinkedExecutable executable = serializeExecutableText(r'''
|
|
typedef MyFunction(int p);
|
|
f(MyFunction myFunction) {}
|
|
''');
|
|
expect(executable.parameters[0].isFunctionTyped, isFalse);
|
|
checkTypeRef(executable.parameters[0].type, null, 'MyFunction',
|
|
expectedKind: ReferenceKind.typedef);
|
|
}
|
|
|
|
test_executable_return_type() {
|
|
UnlinkedExecutable executable = serializeExecutableText('int f() => 1;');
|
|
checkTypeRef(executable.returnType, 'dart:core', 'int');
|
|
}
|
|
|
|
test_executable_return_type_implicit() {
|
|
UnlinkedExecutable executable = serializeExecutableText('f() {}');
|
|
expect(executable.returnType, isNull);
|
|
}
|
|
|
|
test_executable_return_type_void() {
|
|
UnlinkedExecutable executable = serializeExecutableText('void f() {}');
|
|
checkVoidTypeRef(executable.returnType);
|
|
}
|
|
|
|
test_executable_setter() {
|
|
String text = 'void set f(value) {}';
|
|
UnlinkedExecutable executable =
|
|
serializeExecutableText(text, executableName: 'f=');
|
|
expect(executable.kind, UnlinkedExecutableKind.setter);
|
|
expect(executable.returnType, isNotNull);
|
|
expect(executable.isAsynchronous, isFalse);
|
|
expect(executable.isExternal, isFalse);
|
|
expect(executable.isGenerator, isFalse);
|
|
expect(executable.nameOffset, text.indexOf('f'));
|
|
expect(findVariable('f'), isNull);
|
|
expect(findExecutable('f'), isNull);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f=');
|
|
}
|
|
|
|
test_executable_setter_external() {
|
|
UnlinkedExecutable executable = serializeExecutableText(
|
|
'external void set f(value);',
|
|
executableName: 'f=');
|
|
expect(executable.isExternal, isTrue);
|
|
}
|
|
|
|
test_executable_setter_implicit_return() {
|
|
UnlinkedExecutable executable =
|
|
serializeExecutableText('set f(value) {}', executableName: 'f=');
|
|
expect(executable.returnType, isNull);
|
|
}
|
|
|
|
test_executable_setter_private() {
|
|
serializeExecutableText('void set _f(value) {}', executableName: '_f=');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
}
|
|
|
|
test_executable_setter_type() {
|
|
UnlinkedExecutable executable = serializeExecutableText(
|
|
'void set f(int value) {}',
|
|
executableName: 'f=');
|
|
checkVoidTypeRef(executable.returnType);
|
|
expect(executable.parameters, hasLength(1));
|
|
expect(executable.parameters[0].name, 'value');
|
|
checkTypeRef(executable.parameters[0].type, 'dart:core', 'int');
|
|
}
|
|
|
|
test_executable_static() {
|
|
UnlinkedExecutable executable =
|
|
serializeClassText('class C { static f() {} }').executables[0];
|
|
expect(executable.isStatic, isTrue);
|
|
}
|
|
|
|
test_executable_type_param_f_bound_function() {
|
|
UnlinkedExecutable ex =
|
|
serializeExecutableText('void f<T, U extends List<T>>() {}');
|
|
EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
|
|
checkParamTypeRef(typeArgument, 2);
|
|
}
|
|
|
|
test_executable_type_param_f_bound_method() {
|
|
UnlinkedExecutable ex =
|
|
serializeMethodText('void f<T, U extends List<T>>() {}');
|
|
EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
|
|
checkParamTypeRef(typeArgument, 2);
|
|
}
|
|
|
|
test_executable_type_param_f_bound_self_ref_function() {
|
|
UnlinkedExecutable ex =
|
|
serializeExecutableText('void f<T, U extends List<U>>() {}');
|
|
EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
|
|
checkParamTypeRef(typeArgument, 1);
|
|
}
|
|
|
|
test_executable_type_param_f_bound_self_ref_method() {
|
|
UnlinkedExecutable ex =
|
|
serializeMethodText('void f<T, U extends List<U>>() {}');
|
|
EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
|
|
checkParamTypeRef(typeArgument, 1);
|
|
}
|
|
|
|
test_executable_type_param_in_parameter_function() {
|
|
UnlinkedExecutable ex = serializeExecutableText('void f<T>(T t) {}');
|
|
checkParamTypeRef(ex.parameters[0].type, 1);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
|
|
}
|
|
|
|
test_executable_type_param_in_parameter_method() {
|
|
UnlinkedExecutable ex = serializeMethodText('void f<T>(T t) {}');
|
|
checkParamTypeRef(ex.parameters[0].type, 1);
|
|
}
|
|
|
|
test_executable_type_param_in_return_type_function() {
|
|
UnlinkedExecutable ex = serializeExecutableText('T f<T>() => null;');
|
|
checkParamTypeRef(ex.returnType, 1);
|
|
}
|
|
|
|
test_executable_type_param_in_return_type_method() {
|
|
UnlinkedExecutable ex = serializeMethodText('T f<T>() => null;');
|
|
checkParamTypeRef(ex.returnType, 1);
|
|
}
|
|
|
|
test_export_class() {
|
|
addNamedSource('/a.dart', 'class C {}');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'C',
|
|
ReferenceKind.classOrEnum);
|
|
}
|
|
|
|
test_export_class_alias() {
|
|
addNamedSource(
|
|
'/a.dart', 'class C extends _D with _E {} class _D {} class _E {}');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'C',
|
|
ReferenceKind.classOrEnum);
|
|
}
|
|
|
|
test_export_configurations() {
|
|
addNamedSource('/foo.dart', 'class A {}');
|
|
addNamedSource('/foo_io.dart', 'class A {}');
|
|
addNamedSource('/foo_html.dart', 'class A {}');
|
|
String libraryText = r'''
|
|
export 'foo.dart'
|
|
if (dart.library.io) 'foo_io.dart'
|
|
if (dart.flavor == 'html') 'foo_html.dart';
|
|
|
|
class B extends A {}
|
|
''';
|
|
serializeLibraryText(libraryText);
|
|
UnlinkedExportPublic exp = unlinkedUnits[0].publicNamespace.exports[0];
|
|
expect(exp.configurations, hasLength(2));
|
|
{
|
|
UnlinkedConfiguration configuration = exp.configurations[0];
|
|
expect(configuration.name, 'dart.library.io');
|
|
expect(configuration.value, 'true');
|
|
expect(configuration.uri, 'foo_io.dart');
|
|
}
|
|
{
|
|
UnlinkedConfiguration configuration = exp.configurations[1];
|
|
expect(configuration.name, 'dart.flavor');
|
|
expect(configuration.value, 'html');
|
|
expect(configuration.uri, 'foo_html.dart');
|
|
}
|
|
}
|
|
|
|
test_export_dependency() {
|
|
serializeLibraryText('export "dart:async";');
|
|
expect(unlinkedUnits[0].exports, hasLength(1));
|
|
checkDependency(linked.exportDependencies[0], 'dart:async');
|
|
}
|
|
|
|
test_export_enum() {
|
|
addNamedSource('/a.dart', 'enum E { v }');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'E',
|
|
ReferenceKind.classOrEnum);
|
|
}
|
|
|
|
test_export_from_part() {
|
|
addNamedSource('/a.dart', 'library foo; part "b.dart";');
|
|
addNamedSource('/b.dart', 'part of foo; f() {}');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f',
|
|
ReferenceKind.topLevelFunction,
|
|
expectedTargetUnit: 1);
|
|
}
|
|
|
|
test_export_function() {
|
|
addNamedSource('/a.dart', 'f() {}');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f',
|
|
ReferenceKind.topLevelFunction);
|
|
}
|
|
|
|
test_export_getter() {
|
|
addNamedSource('/a.dart', 'get f => null');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f',
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
}
|
|
|
|
test_export_hide() {
|
|
addNamedSource('/a.dart', 'f() {} g() {}');
|
|
serializeLibraryText('export "a.dart" hide g;');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f',
|
|
ReferenceKind.topLevelFunction);
|
|
}
|
|
|
|
test_export_hide_order() {
|
|
serializeLibraryText('export "dart:async" hide Future, Stream;');
|
|
expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
|
|
isEmpty);
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
|
|
hasLength(2));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[0],
|
|
'Future');
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[1],
|
|
'Stream');
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.exports[0].combinators[0].offset, 0);
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].end, 0);
|
|
expect(linked.exportNames, isNotEmpty);
|
|
}
|
|
|
|
test_export_missing() {
|
|
// Unresolved exports are included since this is necessary for proper
|
|
// dependency tracking.
|
|
allowMissingFiles = true;
|
|
serializeLibraryText('export "foo.dart";', allowErrors: true);
|
|
expect(unlinkedUnits[0].imports, hasLength(1));
|
|
checkDependency(linked.exportDependencies[0], absUri('/foo.dart'));
|
|
}
|
|
|
|
test_export_names_excludes_names_from_library() {
|
|
addNamedSource('/a.dart', 'part of my.lib; int y; int _y;');
|
|
serializeLibraryText('library my.lib; part "a.dart"; int x; int _x;');
|
|
expect(linked.exportNames, isEmpty);
|
|
}
|
|
|
|
test_export_no_combinators() {
|
|
serializeLibraryText('export "dart:async";');
|
|
expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators, isEmpty);
|
|
}
|
|
|
|
test_export_not_shadowed_by_prefix() {
|
|
addNamedSource('/a.dart', 'f() {}');
|
|
serializeLibraryText('export "a.dart"; import "dart:core" as f; f.int _x;');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f',
|
|
ReferenceKind.topLevelFunction);
|
|
}
|
|
|
|
test_export_offset() {
|
|
String libraryText = ' export "dart:async";';
|
|
serializeLibraryText(libraryText);
|
|
expect(unlinkedUnits[0].exports[0].uriOffset,
|
|
libraryText.indexOf('"dart:async"'));
|
|
expect(unlinkedUnits[0].exports[0].uriEnd, libraryText.indexOf(';'));
|
|
expect(unlinkedUnits[0].exports[0].offset, libraryText.indexOf('export'));
|
|
}
|
|
|
|
test_export_private() {
|
|
// Private names should not be exported.
|
|
addNamedSource('/a.dart', '_f() {}');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, isEmpty);
|
|
}
|
|
|
|
test_export_setter() {
|
|
addNamedSource('/a.dart', 'void set f(value) {}');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f=',
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
}
|
|
|
|
test_export_shadowed() {
|
|
// f() is not shown in exportNames because it is already defined at top
|
|
// level in the library.
|
|
addNamedSource('/a.dart', 'f() {}');
|
|
serializeLibraryText('export "a.dart"; f() {}');
|
|
expect(linked.exportNames, isEmpty);
|
|
}
|
|
|
|
test_export_shadowed_variable() {
|
|
// Neither `v` nor `v=` is shown in exportNames because both are defined at
|
|
// top level in the library by the declaration `var v;`.
|
|
addNamedSource('/a.dart', 'var v;');
|
|
serializeLibraryText('export "a.dart"; var v;');
|
|
expect(linked.exportNames, isEmpty);
|
|
}
|
|
|
|
test_export_shadowed_variable_const() {
|
|
// `v=` is shown in exportNames because the top level declaration
|
|
// `const v = 0;` only shadows `v`, not `v=`.
|
|
addNamedSource('/a.dart', 'var v;');
|
|
serializeLibraryText('export "a.dart"; const v = 0;');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'v=',
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
}
|
|
|
|
test_export_shadowed_variable_final() {
|
|
// `v=` is shown in exportNames because the top level declaration
|
|
// `final v = 0;` only shadows `v`, not `v=`.
|
|
addNamedSource('/a.dart', 'var v;');
|
|
serializeLibraryText('export "a.dart"; final v = 0;');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'v=',
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
}
|
|
|
|
test_export_show() {
|
|
addNamedSource('/a.dart', 'f() {} g() {}');
|
|
serializeLibraryText('export "a.dart" show f;');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'f',
|
|
ReferenceKind.topLevelFunction);
|
|
}
|
|
|
|
test_export_show_order() {
|
|
String libraryText = 'export "dart:async" show Future, Stream;';
|
|
serializeLibraryText(libraryText);
|
|
expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
|
|
hasLength(2));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
|
|
isEmpty);
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[0],
|
|
'Future');
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[1],
|
|
'Stream');
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].offset,
|
|
libraryText.indexOf('show'));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].end,
|
|
libraryText.indexOf(';'));
|
|
}
|
|
|
|
test_export_typedef() {
|
|
addNamedSource('/a.dart', 'typedef F();');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(
|
|
linked.exportNames[0], absUri('/a.dart'), 'F', ReferenceKind.typedef);
|
|
}
|
|
|
|
test_export_typedef_genericFunction() {
|
|
addNamedSource('/a.dart', 'typedef F<S> = S Function<T>(T x);');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(1));
|
|
checkExportName(linked.exportNames[0], absUri('/a.dart'), 'F',
|
|
ReferenceKind.genericFunctionTypedef);
|
|
}
|
|
|
|
test_export_uri() {
|
|
addNamedSource('/a.dart', 'library my.lib;');
|
|
String uriString = '"a.dart"';
|
|
String libraryText = 'export $uriString;';
|
|
serializeLibraryText(libraryText);
|
|
var unlinkedExports = unlinkedUnits[0].publicNamespace.exports;
|
|
expect(unlinkedExports, hasLength(1));
|
|
expect(unlinkedExports[0].uri, 'a.dart');
|
|
expect(unlinkedExports[0].configurations, isEmpty);
|
|
}
|
|
|
|
test_export_uri_invalid() {
|
|
String uriString = ':[invalid uri]';
|
|
String libraryText = 'export "$uriString";';
|
|
serializeLibraryText(libraryText);
|
|
expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].uri, uriString);
|
|
}
|
|
|
|
test_export_uri_nullStringValue() {
|
|
String libraryText = r'''
|
|
export "${'a'}.dart";
|
|
''';
|
|
serializeLibraryText(libraryText);
|
|
var unlinkedExports = unlinkedUnits[0].publicNamespace.exports;
|
|
expect(unlinkedExports, hasLength(1));
|
|
expect(unlinkedExports[0].uri, '');
|
|
expect(unlinkedExports[0].configurations, isEmpty);
|
|
}
|
|
|
|
test_export_variable() {
|
|
addNamedSource('/a.dart', 'var v;');
|
|
serializeLibraryText('export "a.dart";');
|
|
expect(linked.exportNames, hasLength(2));
|
|
LinkedExportName getter =
|
|
linked.exportNames.firstWhere((e) => e.name == 'v');
|
|
expect(getter, isNotNull);
|
|
checkExportName(
|
|
getter, absUri('/a.dart'), 'v', ReferenceKind.topLevelPropertyAccessor);
|
|
LinkedExportName setter =
|
|
linked.exportNames.firstWhere((e) => e.name == 'v=');
|
|
expect(setter, isNotNull);
|
|
checkExportName(setter, absUri('/a.dart'), 'v=',
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
}
|
|
|
|
test_expr_assignOperator_assign() {
|
|
_assertAssignmentOperator(
|
|
'(a = 1 + 2) + 3', UnlinkedExprAssignOperator.assign);
|
|
}
|
|
|
|
test_expr_assignOperator_bitAnd() {
|
|
_assertAssignmentOperator(
|
|
'(a &= 1 + 2) + 3', UnlinkedExprAssignOperator.bitAnd);
|
|
}
|
|
|
|
test_expr_assignOperator_bitOr() {
|
|
_assertAssignmentOperator(
|
|
'(a |= 1 + 2) + 3', UnlinkedExprAssignOperator.bitOr);
|
|
}
|
|
|
|
test_expr_assignOperator_bitXor() {
|
|
_assertAssignmentOperator(
|
|
'(a ^= 1 + 2) + 3', UnlinkedExprAssignOperator.bitXor);
|
|
}
|
|
|
|
test_expr_assignOperator_divide() {
|
|
_assertAssignmentOperator(
|
|
'(a /= 1 + 2) + 3', UnlinkedExprAssignOperator.divide);
|
|
}
|
|
|
|
test_expr_assignOperator_floorDivide() {
|
|
_assertAssignmentOperator(
|
|
'(a ~/= 1 + 2) + 3', UnlinkedExprAssignOperator.floorDivide);
|
|
}
|
|
|
|
test_expr_assignOperator_ifNull() {
|
|
_assertAssignmentOperator(
|
|
'(a ??= 1 + 2) + 3', UnlinkedExprAssignOperator.ifNull);
|
|
}
|
|
|
|
test_expr_assignOperator_minus() {
|
|
_assertAssignmentOperator(
|
|
'(a -= 1 + 2) + 3', UnlinkedExprAssignOperator.minus);
|
|
}
|
|
|
|
test_expr_assignOperator_modulo() {
|
|
_assertAssignmentOperator(
|
|
'(a %= 1 + 2) + 3', UnlinkedExprAssignOperator.modulo);
|
|
}
|
|
|
|
test_expr_assignOperator_multiply() {
|
|
_assertAssignmentOperator(
|
|
'(a *= 1 + 2) + 3', UnlinkedExprAssignOperator.multiply);
|
|
}
|
|
|
|
test_expr_assignOperator_plus() {
|
|
_assertAssignmentOperator(
|
|
'(a += 1 + 2) + 3', UnlinkedExprAssignOperator.plus);
|
|
}
|
|
|
|
test_expr_assignOperator_shiftLeft() {
|
|
_assertAssignmentOperator(
|
|
'(a <<= 1 + 2) + 3', UnlinkedExprAssignOperator.shiftLeft);
|
|
}
|
|
|
|
test_expr_assignOperator_shiftRight() {
|
|
_assertAssignmentOperator(
|
|
'(a >>= 1 + 2) + 3', UnlinkedExprAssignOperator.shiftRight);
|
|
}
|
|
|
|
test_expr_assignToIndex_ofFieldSequence() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class A {
|
|
B b;
|
|
}
|
|
class B {
|
|
C c;
|
|
}
|
|
class C {
|
|
List<int> f = <int>[0, 1, 2];
|
|
}
|
|
A a = new A();
|
|
final v = (a.b.c.f[1] = 5);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(a.b.c.f[1] = 5)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToIndex,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [5, 1],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'f',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'c'),
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'b'),
|
|
new _PrefixExpectation(
|
|
ReferenceKind.topLevelPropertyAccessor, 'a')
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToIndex_ofIndexExpression() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class A {
|
|
List<B> b;
|
|
}
|
|
class B {
|
|
List<C> c;
|
|
}
|
|
class C {
|
|
List<int> f = <int>[0, 1, 2];
|
|
}
|
|
A a = new A();
|
|
final v = (a.b[1].c[2].f[3] = 5);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(a.b[1].c[2].f[3] = 5)',
|
|
isValidConst: false,
|
|
operators: [
|
|
// 5
|
|
UnlinkedExprOperation.pushInt,
|
|
// a.b[1]
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.extractIndex,
|
|
// c[2]
|
|
UnlinkedExprOperation.extractProperty,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.extractIndex,
|
|
// f[3] = 5
|
|
UnlinkedExprOperation.extractProperty,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToIndex,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
5,
|
|
1,
|
|
2,
|
|
3,
|
|
],
|
|
strings: ['c', 'f'],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'b',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.topLevelPropertyAccessor, 'a')
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToIndex_ofTopLevelVariable() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
List<int> a = <int>[0, 1, 2];
|
|
final v = (a[1] = 5);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(a[1] = 5)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToIndex,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
5,
|
|
1,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToProperty_ofInstanceCreation() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
int f;
|
|
}
|
|
final v = (new C().f = 5);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(new C().f = 5)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
UnlinkedExprOperation.assignToProperty,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
5,
|
|
0,
|
|
0,
|
|
],
|
|
strings: ['f'],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToRef_classStaticField() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
static int f;
|
|
}
|
|
final v = (C.f = 1);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(C.f = 1)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
1,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'f',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToRef_fieldSequence() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class A {
|
|
B b;
|
|
}
|
|
class B {
|
|
C c;
|
|
}
|
|
class C {
|
|
int f;
|
|
}
|
|
A a = new A();
|
|
final v = (a.b.c.f = 1);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(a.b.c.f = 1)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
1,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'f',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'c'),
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'b'),
|
|
new _PrefixExpectation(
|
|
ReferenceKind.topLevelPropertyAccessor, 'a')
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToRef_postfixDecrement() {
|
|
_assertRefPrefixPostfixIncrementDecrement(
|
|
'a-- + 2', UnlinkedExprAssignOperator.postfixDecrement);
|
|
}
|
|
|
|
test_expr_assignToRef_postfixIncrement() {
|
|
_assertRefPrefixPostfixIncrementDecrement(
|
|
'a++ + 2', UnlinkedExprAssignOperator.postfixIncrement);
|
|
}
|
|
|
|
test_expr_assignToRef_prefixDecrement() {
|
|
_assertRefPrefixPostfixIncrementDecrement(
|
|
'--a + 2', UnlinkedExprAssignOperator.prefixDecrement);
|
|
}
|
|
|
|
test_expr_assignToRef_prefixIncrement() {
|
|
_assertRefPrefixPostfixIncrementDecrement(
|
|
'++a + 2', UnlinkedExprAssignOperator.prefixIncrement);
|
|
}
|
|
|
|
test_expr_assignToRef_topLevelVariable() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
int a = 0;
|
|
final v = (a = 1);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(a = 1)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
1,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToRef_topLevelVariable_imported() {
|
|
addNamedSource('/a.dart', '''
|
|
int a = 0;
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart';
|
|
final v = (a = 1);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(a = 1)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
1,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_assignToRef_topLevelVariable_imported_withPrefix() {
|
|
addNamedSource('/a.dart', '''
|
|
int a = 0;
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
final v = (p.a = 1);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '(p.a = 1)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
],
|
|
assignmentOperators: [(UnlinkedExprAssignOperator.assign)],
|
|
ints: [
|
|
1,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) {
|
|
return checkTypeRef(r, absUri('/a.dart'), 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor,
|
|
expectedPrefix: 'p');
|
|
}
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_cascadeSection_assignToIndex() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
List<int> items;
|
|
}
|
|
final C c = new C();
|
|
final v = c.items..[1] = 2;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'c.items..[1] = 2',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushReference,
|
|
],
|
|
assignmentOperators: [],
|
|
ints: [],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'items',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.topLevelPropertyAccessor, 'c'),
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_cascadeSection_assignToProperty() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
int f1 = 0;
|
|
int f2 = 0;
|
|
}
|
|
final v = new C()..f1 = 1..f2 += 2;
|
|
''');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'new C()..f1 = 1..f2 += 2',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
],
|
|
assignmentOperators: [],
|
|
ints: [0, 0],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_cascadeSection_embedded() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class A {
|
|
int fa1;
|
|
B b;
|
|
int fa2;
|
|
}
|
|
class B {
|
|
int fb;
|
|
}
|
|
final v = new A()
|
|
..fa1 = 1
|
|
..b = (new B()..fb = 2)
|
|
..fa2 = 3;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr,
|
|
'new A()..fa1 = 1..b = (new B()..fb = 2)..fa2 = 3',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
],
|
|
assignmentOperators: [],
|
|
ints: [
|
|
0,
|
|
0,
|
|
],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'A',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_cascadeSection_invokeMethod() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class A {
|
|
int m(int _) => 0;
|
|
}
|
|
final A a = new A();
|
|
final v = a..m(5).abs()..m(6);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'a..m(5).abs()..m(6)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushReference,
|
|
],
|
|
ints: [],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_extractIndex_ofClassField() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
List<int> get items => null;
|
|
}
|
|
final v = new C().items[5];
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'new C().items[5]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
UnlinkedExprOperation.extractProperty,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.extractIndex,
|
|
],
|
|
ints: [0, 0, 5],
|
|
strings: ['items'],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_extractProperty_ofInvokeConstructor() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
int f = 0;
|
|
}
|
|
final v = new C().f;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'new C().f',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
UnlinkedExprOperation.extractProperty,
|
|
],
|
|
ints: [0, 0],
|
|
strings: ['f'],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_functionExpression_asArgument() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = foo(5, () => 42);
|
|
foo(a, b) {}
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'foo(5, () => 42)',
|
|
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)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_functionExpression_asArgument_multiple() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = foo(5, () => 42, () => 43);
|
|
foo(a, b, c) {}
|
|
''');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'foo(5, () => 42, () => 43)',
|
|
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)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_functionExpression_withBlockBody() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = () { return 42; };
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '() { return 42; }',
|
|
isValidConst: false,
|
|
operators: [UnlinkedExprOperation.pushLocalFunctionReference],
|
|
ints: [0, 0],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_functionExpression_withExpressionBody() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = () => 42;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '() => 42',
|
|
isValidConst: false,
|
|
operators: [UnlinkedExprOperation.pushLocalFunctionReference],
|
|
ints: [0, 0],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_functionExpressionInvocation_withBlockBody() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = ((a, b) {return 42;})(1, 2);
|
|
''');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '((a, b) {return 42;})(1, 2)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushLocalFunctionReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.invokeMethod
|
|
],
|
|
ints: [0, 0, 1, 2, 0, 2, 0],
|
|
strings: ['call'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_functionExpressionInvocation_withExpressionBody() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = ((a, b) => 42)(1, 2);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '((a, b) => 42)(1, 2)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushLocalFunctionReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.invokeMethod
|
|
],
|
|
ints: [0, 0, 1, 2, 0, 2, 0],
|
|
strings: ['call'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = () => 1;');
|
|
assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr, '1',
|
|
operators: [UnlinkedExprOperation.pushInt],
|
|
ints: [1],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_noTypeInferenceNeeded() {
|
|
// We don't serialize closure body expressions for closures that don't need
|
|
// to participate in type inference.
|
|
UnlinkedVariable variable = serializeVariableText('Object v = () => 1;');
|
|
expect(variable.initializer.localFunctions[0].bodyExpr, isNull);
|
|
}
|
|
|
|
test_expr_inClosure_refersToOuterParam() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = (x) => (y) => x;');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].localFunctions[0].bodyExpr, 'x',
|
|
operators: [UnlinkedExprOperation.pushParameter],
|
|
strings: ['x'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = (x) => x;');
|
|
assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr, 'x',
|
|
operators: [UnlinkedExprOperation.pushParameter],
|
|
strings: ['x'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_methodCall() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = (x) => x.f();');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, 'x.f()',
|
|
operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.invokeMethod
|
|
],
|
|
strings: ['x', 'f'],
|
|
ints: [0, 0, 0],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_methodCall_prefixed() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = (x) => x.y.f();');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, 'x.y.f()',
|
|
operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.extractProperty,
|
|
UnlinkedExprOperation.invokeMethod
|
|
],
|
|
strings: ['x', 'y', 'f'],
|
|
ints: [0, 0, 0],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_outOfScope() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var x; var v = (b) => (b ? (x) => x : x);');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, '(b ? (x) => x : x)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushLocalFunctionReference,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.conditional,
|
|
],
|
|
strings: ['b'],
|
|
ints: [0, 0],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'x',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_prefixedIdentifier() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = (x) => x.y;');
|
|
assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr, 'x.y',
|
|
operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.extractProperty
|
|
],
|
|
strings: ['x', 'y'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_prefixedIdentifier_assign() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = (x) => x.y = null;');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, 'x.y = null',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushNull,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.assignToProperty
|
|
],
|
|
strings: ['x', 'y'],
|
|
assignmentOperators: [UnlinkedExprAssignOperator.assign],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_prefixedPrefixedIdentifier() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = (x) => x.y.z;');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, 'x.y.z',
|
|
operators: [
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.extractProperty,
|
|
UnlinkedExprOperation.extractProperty
|
|
],
|
|
strings: ['x', 'y', 'z'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_inClosure_refersToParam_prefixedPrefixedIdentifier_assign() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = (x) => x.y.z = null;');
|
|
assertUnlinkedConst(
|
|
variable.initializer.localFunctions[0].bodyExpr, 'x.y.z = null',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushNull,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.extractProperty,
|
|
UnlinkedExprOperation.assignToProperty
|
|
],
|
|
strings: ['x', 'y', 'z'],
|
|
assignmentOperators: [UnlinkedExprAssignOperator.assign],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_invalid_typeParameter_asPrefix() {
|
|
var variable = serializeClassText('''
|
|
class C<T> {
|
|
final f = T.k;
|
|
}
|
|
''').fields[0];
|
|
if (containsNonConstExprs) {
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'T.k',
|
|
isValidConst: false, operators: []);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
}
|
|
|
|
test_expr_invokeMethod_instance() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
int m(a, {b, c}) => 42;
|
|
}
|
|
final v = new C().m(1, b: 2, c: 3);
|
|
''');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'new C().m(1, b: 2, c: 3)',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.invokeMethod,
|
|
],
|
|
ints: [0, 0, 1, 2, 3, 2, 1, 0],
|
|
strings: ['b', 'c', 'm'],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_invokeMethod_withTypeParameters() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C {
|
|
f<T, U>() => null;
|
|
}
|
|
final v = new C().f<int, String>();
|
|
''');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, 'new C().f<int, String>()',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
UnlinkedExprOperation.invokeMethod
|
|
],
|
|
ints: [0, 0, 0, 0, 2],
|
|
strings: ['f'],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'C'),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int'),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String')
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_invokeMethodRef_instance() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class A {
|
|
B b;
|
|
}
|
|
class B {
|
|
C c;
|
|
}
|
|
class C {
|
|
int m(int a, int b) => a + b;
|
|
}
|
|
A a = new A();
|
|
final v = a.b.c.m(10, 20);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'a.b.c.m(10, 20)',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.invokeMethodRef,
|
|
],
|
|
ints: [10, 20, 0, 2, 0],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'c'),
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'b'),
|
|
new _PrefixExpectation(
|
|
ReferenceKind.topLevelPropertyAccessor, 'a')
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_invokeMethodRef_static_importedWithPrefix() {
|
|
addNamedSource('/a.dart', '''
|
|
class C {
|
|
static int m() => 42;
|
|
}
|
|
''');
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
import 'a.dart' as p;
|
|
final v = p.C.m();
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'p.C.m()',
|
|
operators: [
|
|
UnlinkedExprOperation.invokeMethodRef,
|
|
],
|
|
ints: [0, 0, 0],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.method,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
|
|
absoluteUri: absUri('/a.dart')),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'p')
|
|
])
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_invokeMethodRef_with_reference_arg() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
f(x) => null;
|
|
final u = null;
|
|
final v = f(u);
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'f(u)',
|
|
operators: [
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.invokeMethodRef
|
|
],
|
|
ints: [0, 1, 0],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'u',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_invokeMethodRef_withTypeParameters() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
f<T, U>() => null;
|
|
final v = f<int, String>();
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'f<int, String>()',
|
|
operators: [UnlinkedExprOperation.invokeMethodRef],
|
|
ints: [0, 0, 2],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction,
|
|
numTypeParameters: 2),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int'),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String')
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_list_for() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i; var v = [for (i = 0; i < 10; i++) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (i = 0; i < 10; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.assign,
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
10,
|
|
1,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_each_with_declaration_typed() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = [for (int i in []) i];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[for (int i in []) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.makeUntypedList,
|
|
UnlinkedExprOperation.forEachPartsWithTypedDeclaration,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
strings: [
|
|
'i',
|
|
'i'
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int')
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_each_with_declaration_untyped() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = [for (var i in []) i];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[for (var i in []) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.makeUntypedList,
|
|
UnlinkedExprOperation.forEachPartsWithUntypedDeclaration,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
strings: [
|
|
'i',
|
|
'i'
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_each_with_identifier() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i; var v = [for (i in []) i];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[for (i in []) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.makeUntypedList,
|
|
UnlinkedExprOperation.forEachPartsWithIdentifier,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_each_with_identifier_await() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i; var v = [await for (i in []) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[await for (i in []) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.makeUntypedList,
|
|
UnlinkedExprOperation.forEachPartsWithIdentifier,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElementWithAwait,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_empty_condition() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i; var v = [for (i = 0;; i++) i];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[for (i = 0;; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushEmptyExpression,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.assign,
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
1,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_empty_initializer() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i; var v = [for (; i < 10; i++) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (; i < 10; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushEmptyExpression,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
10,
|
|
1,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_two_updaters() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'int i; int j; var v = [for (i = 0; i < 10; i++, j++) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (i = 0; i < 10; i++, j++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.assign,
|
|
UnlinkedExprAssignOperator.postfixIncrement,
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
10,
|
|
2,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'j',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_with_one_declaration_typed() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = [for (int i = 0; i < 10; i++) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (int i = 0; i < 10; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.variableDeclarationStart,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.variableDeclaration,
|
|
UnlinkedExprOperation.forInitializerDeclarationsTyped,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToParameter,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
0,
|
|
1,
|
|
10,
|
|
1,
|
|
1
|
|
],
|
|
strings: [
|
|
'i',
|
|
'i',
|
|
'i',
|
|
'i'
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int')
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_with_one_declaration_untyped() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = [for (var i = 0; i < 10; i++) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (var i = 0; i < 10; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.variableDeclarationStart,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.variableDeclaration,
|
|
UnlinkedExprOperation.forInitializerDeclarationsUntyped,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToParameter,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
0,
|
|
1,
|
|
10,
|
|
1,
|
|
1
|
|
],
|
|
strings: [
|
|
'i',
|
|
'i',
|
|
'i',
|
|
'i'
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_with_two_declarations_untyped() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'var v = [for (var i = 0, j = 0; i < 10; i++) i];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr,
|
|
'[for (var i = 0, j = 0; i < 10; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.variableDeclarationStart,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.variableDeclaration,
|
|
UnlinkedExprOperation.variableDeclarationStart,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.variableDeclaration,
|
|
UnlinkedExprOperation.forInitializerDeclarationsUntyped,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToParameter,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
2,
|
|
10,
|
|
1,
|
|
1
|
|
],
|
|
strings: [
|
|
'i',
|
|
'j',
|
|
'i',
|
|
'i',
|
|
'i'
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_with_uninitialized_declaration_untyped() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = [for (var i; i < 10; i++) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (var i; i < 10; i++) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.variableDeclarationStart,
|
|
UnlinkedExprOperation.pushEmptyExpression,
|
|
UnlinkedExprOperation.variableDeclaration,
|
|
UnlinkedExprOperation.forInitializerDeclarationsUntyped,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToParameter,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushParameter,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
0,
|
|
1,
|
|
10,
|
|
1,
|
|
1
|
|
],
|
|
strings: [
|
|
'i',
|
|
'i',
|
|
'i',
|
|
'i'
|
|
]);
|
|
}
|
|
|
|
test_expr_list_for_zero_updaters() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i; var v = [for (i = 0; i < 10;) i];');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '[for (i = 0; i < 10;) i]',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.assign
|
|
],
|
|
ints: [
|
|
0,
|
|
10,
|
|
0,
|
|
1
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_makeTypedList() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = <int>[11, 22, 33];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<int>[11, 22, 33]',
|
|
operators: [UnlinkedExprOperation.makeTypedList],
|
|
ints: [0],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_makeTypedMap() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'var v = <int, String>{11: "aaa", 22: "bbb", 33: "ccc"};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr,
|
|
'<int, String>{11: "aaa", 22: "bbb", 33: "ccc"}',
|
|
operators: [UnlinkedExprOperation.makeTypedMap2],
|
|
ints: [0],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum),
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_makeTypedSet() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = <int>{11, 22, 33};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{11, 22, 33}',
|
|
operators: [UnlinkedExprOperation.makeTypedSet],
|
|
ints: [0],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_makeUntypedList() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = [11, 22, 33];');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '[11, 22, 33]',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeUntypedList
|
|
],
|
|
ints: [11, 22, 33, 3],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_makeUntypedMap() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('var v = {11: "aaa", 22: "bbb", 33: "ccc"};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '{11: "aaa", 22: "bbb", 33: "ccc"}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushString,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.makeUntypedSetOrMap
|
|
],
|
|
ints: [11, 22, 33, 3],
|
|
strings: ['aaa', 'bbb', 'ccc'],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_makeUntypedSet() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = {11, 22, 33};');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '{11, 22, 33}',
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeUntypedSetOrMap
|
|
],
|
|
ints: [11, 22, 33, 3],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_map_for() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'int i; var v = {1: 2, for (i = 0; i < 10; i++) i: i};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '{1: 2, for (i = 0; i < 10; i++) i: i}',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.makeMapLiteralEntry,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedSetOrMap
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.assign,
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
1,
|
|
2,
|
|
0,
|
|
10,
|
|
1,
|
|
2
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_set_for() {
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'int i; var v = {1, for (i = 0; i < 10; i++) i};');
|
|
assertUnlinkedConst(
|
|
variable.initializer.bodyExpr, '{1, for (i = 0; i < 10; i++) i}',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.less,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.forParts,
|
|
UnlinkedExprOperation.pushReference,
|
|
UnlinkedExprOperation.forElement,
|
|
UnlinkedExprOperation.makeUntypedSetOrMap
|
|
],
|
|
assignmentOperators: [
|
|
UnlinkedExprAssignOperator.assign,
|
|
UnlinkedExprAssignOperator.postfixIncrement
|
|
],
|
|
ints: [
|
|
1,
|
|
0,
|
|
10,
|
|
1,
|
|
2
|
|
],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor),
|
|
(EntityRef r) => checkTypeRef(r, null, 'i',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_expr_super() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = super;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'super',
|
|
operators: [
|
|
UnlinkedExprOperation.pushSuper,
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_this() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = this;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'this',
|
|
operators: [
|
|
UnlinkedExprOperation.pushThis,
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_throwException() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = throw 1 + 2;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, 'throw 1 + 2',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.add,
|
|
UnlinkedExprOperation.throwException,
|
|
],
|
|
ints: [1, 2],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_typeCast() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = 42 as num;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '42 as num',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.typeCast,
|
|
],
|
|
ints: [42],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'num',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_expr_typeCheck() {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = 42 is num;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '42 is num',
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.typeCheck,
|
|
],
|
|
ints: [42],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, 'dart:core', 'num',
|
|
expectedKind: ReferenceKind.classOrEnum)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
test_field() {
|
|
UnlinkedClass cls = serializeClassText('class C { int i; }');
|
|
UnlinkedVariable variable = findVariable('i', variables: cls.fields);
|
|
expect(variable, isNotNull);
|
|
expect(variable.isConst, isFalse);
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isFalse);
|
|
expect(variable.isFinal, isFalse);
|
|
expect(variable.initializer, isNull);
|
|
expect(variable.inheritsCovariantSlot, isNot(0));
|
|
expect(findExecutable('i', executables: cls.executables), isNull);
|
|
expect(findExecutable('i=', executables: cls.executables), isNull);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, isEmpty);
|
|
}
|
|
|
|
test_field_const() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static const int i = 0; }').fields[0];
|
|
expect(variable.isConst, isTrue);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '0',
|
|
operators: [UnlinkedExprOperation.pushInt], ints: [0]);
|
|
}
|
|
|
|
test_field_documented() {
|
|
String text = '''
|
|
class C {
|
|
/**
|
|
* Docs
|
|
*/
|
|
var v;
|
|
}''';
|
|
UnlinkedVariable variable = serializeClassText(text).fields[0];
|
|
expect(variable.documentationComment, isNotNull);
|
|
checkDocumentationComment(variable.documentationComment, text);
|
|
}
|
|
|
|
test_field_final_notConstExpr() {
|
|
UnlinkedVariable variable = serializeClassText(r'''
|
|
class C {
|
|
final f = 1 + m();
|
|
static int m() => 42;
|
|
}''').fields[0];
|
|
expect(variable.isFinal, isTrue);
|
|
if (containsNonConstExprs) {
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '1 + m()', operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.invokeMethodRef,
|
|
UnlinkedExprOperation.add,
|
|
], ints: [
|
|
1,
|
|
0,
|
|
0,
|
|
0
|
|
], strings: [], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'm',
|
|
expectedKind: ReferenceKind.method,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
|
|
])
|
|
]);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
}
|
|
|
|
test_field_final_typeParameter() {
|
|
UnlinkedVariable variable = serializeClassText(r'''
|
|
class C<T> {
|
|
final f = <T>[];
|
|
}''').fields[0];
|
|
expect(variable.isFinal, isTrue);
|
|
if (containsNonConstExprs) {
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, '<T>[]',
|
|
operators: [UnlinkedExprOperation.makeTypedList],
|
|
ints: [0],
|
|
referenceValidators: [(EntityRef r) => checkParamTypeRef(r, 1)]);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
}
|
|
|
|
test_field_formal_param_inferred_type_explicit() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C extends D { var v; C(int this.v); }'
|
|
' abstract class D { num get v; }',
|
|
className: 'C');
|
|
checkInferredTypeSlot(cls.fields[0].inferredTypeSlot, 'dart:core', 'num');
|
|
expect(cls.executables[0].kind, UnlinkedExecutableKind.constructor);
|
|
expect(cls.executables[0].parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_field_formal_param_inferred_type_implicit() {
|
|
// Both the field `v` and the constructor argument `this.v` will have their
|
|
// type inferred by strong mode. But only the field should have its
|
|
// inferred type stored in the summary, since the standard rules for field
|
|
// formal parameters will take care of the rest (they implicitly inherit
|
|
// the type of the associated field).
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C extends D { var v; C(this.v); }'
|
|
' abstract class D { int get v; }',
|
|
className: 'C');
|
|
checkInferredTypeSlot(cls.fields[0].inferredTypeSlot, 'dart:core', 'int');
|
|
expect(cls.executables[0].kind, UnlinkedExecutableKind.constructor);
|
|
expect(cls.executables[0].parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_field_inferred_type_nonstatic_explicit_initialized() {
|
|
UnlinkedVariable v = serializeClassText('class C { num v = 0; }').fields[0];
|
|
expect(v.inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_field_inferred_type_nonstatic_explicit_uninitialized() {
|
|
UnlinkedVariable v = serializeClassText(
|
|
'class C extends D { num v; } abstract class D { int get v; }',
|
|
className: 'C',
|
|
allowErrors: true)
|
|
.fields[0];
|
|
expect(v.inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_field_inferred_type_nonstatic_implicit_initialized() {
|
|
UnlinkedVariable v = serializeClassText('class C { var v = 0; }').fields[0];
|
|
checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_field_inferred_type_nonstatic_implicit_uninitialized() {
|
|
UnlinkedVariable v = serializeClassText(
|
|
'class C extends D { var v; } abstract class D { int get v; }',
|
|
className: 'C')
|
|
.fields[0];
|
|
checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_field_inferred_type_static_explicit_initialized() {
|
|
UnlinkedVariable v =
|
|
serializeClassText('class C { static int v = 0; }').fields[0];
|
|
expect(v.inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_field_inferred_type_static_implicit_initialized() {
|
|
UnlinkedVariable v =
|
|
serializeClassText('class C { static var v = 0; }').fields[0];
|
|
checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_field_inferred_type_static_implicit_uninitialized() {
|
|
UnlinkedVariable v =
|
|
serializeClassText('class C { static var v; }').fields[0];
|
|
expect(v.inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_constConstructor_typed() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
int x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, isNot(0));
|
|
}
|
|
|
|
test_field_initializer_final_constConstructor_typed() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
final int x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_final_constConstructor_untyped() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
final x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_final_typed() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { final int x = 0; }').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_final_untyped() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { final x = 0; }').fields[0];
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_static_constConstructor_typed() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
static int x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_static_constConstructor_untyped() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
static var x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_static_final_constConstructor_typed() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
static final int x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_static_final_constConstructor_untyped() {
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C {
|
|
static final x = 0;
|
|
const C();
|
|
}
|
|
''').fields[0];
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_initializer_typed() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { int x = 0; }').fields[0];
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, isNot(0));
|
|
}
|
|
|
|
test_field_initializer_untyped() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { var x = 0; }').fields[0];
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
expect(variable.inheritsCovariantSlot, isNot(0));
|
|
}
|
|
|
|
test_field_late() {
|
|
featureSet = enableNnbd;
|
|
UnlinkedClass cls = serializeClassText('class C { late int i; }');
|
|
UnlinkedVariable variable = findVariable('i', variables: cls.fields);
|
|
expect(variable, isNotNull);
|
|
expect(variable.isConst, isFalse);
|
|
expect(variable.isLate, isTrue);
|
|
expect(variable.isStatic, isFalse);
|
|
expect(variable.isFinal, isFalse);
|
|
expect(variable.initializer, isNull);
|
|
expect(variable.inheritsCovariantSlot, isNot(0));
|
|
expect(findExecutable('i', executables: cls.executables), isNull);
|
|
expect(findExecutable('i=', executables: cls.executables), isNull);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, isEmpty);
|
|
}
|
|
|
|
test_field_static() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static int i; }').fields[0];
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isTrue);
|
|
expect(variable.initializer, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'i');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].kind,
|
|
ReferenceKind.propertyAccessor);
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].numTypeParameters,
|
|
0);
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].members, isEmpty);
|
|
}
|
|
|
|
test_field_static_final() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static final int i = 0; }').fields[0];
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isTrue);
|
|
expect(variable.isFinal, isTrue);
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_static_final_late() {
|
|
featureSet = enableNnbd;
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static late final int i = 0; }')
|
|
.fields[0];
|
|
expect(variable.isLate, isTrue);
|
|
expect(variable.isStatic, isTrue);
|
|
expect(variable.isFinal, isTrue);
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_static_final_untyped() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static final x = 0; }').fields[0];
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
}
|
|
|
|
test_field_static_late() {
|
|
featureSet = enableNnbd;
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static late int i; }').fields[0];
|
|
expect(variable.isLate, isTrue);
|
|
expect(variable.isStatic, isTrue);
|
|
expect(variable.initializer, isNull);
|
|
expect(variable.inheritsCovariantSlot, 0);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'i');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].members[0].kind,
|
|
ReferenceKind.propertyAccessor);
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].numTypeParameters,
|
|
0);
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].members[0].members, isEmpty);
|
|
}
|
|
|
|
test_fully_linked_references_follow_other_references() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
serializeLibraryText('final x = 0; String y;');
|
|
checkLinkedTypeSlot(
|
|
unlinkedUnits[0].variables[0].inferredTypeSlot, 'dart:core', 'int');
|
|
checkTypeRef(unlinkedUnits[0].variables[1].type, 'dart:core', 'String');
|
|
// Even though the definition of y follows the definition of x, the linked
|
|
// type reference for x should use a higher numbered reference than the
|
|
// unlinked type reference for y.
|
|
EntityRef propagatedType =
|
|
getTypeRefForSlot(unlinkedUnits[0].variables[0].inferredTypeSlot);
|
|
expect(unlinkedUnits[0].variables[1].type.reference,
|
|
lessThan(propagatedType.reference));
|
|
}
|
|
|
|
test_function_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
f() {}''';
|
|
UnlinkedExecutable executable = serializeExecutableText(text);
|
|
expect(executable.documentationComment, isNotNull);
|
|
checkDocumentationComment(executable.documentationComment, text);
|
|
}
|
|
|
|
test_function_inferred_type_implicit_param() {
|
|
UnlinkedExecutable f = serializeExecutableText('void f(value) {}');
|
|
expect(f.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_function_inferred_type_implicit_return() {
|
|
UnlinkedExecutable f = serializeExecutableText('f() => null;');
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_function_type_nullability_suffix_none() {
|
|
featureSet = enableNnbd;
|
|
EntityRef typeRef = serializeTypeText('void Function()');
|
|
expect(typeRef.entityKind, EntityRefKind.genericFunctionType);
|
|
expect(typeRef.nullabilitySuffix, EntityRefNullabilitySuffix.none);
|
|
}
|
|
|
|
test_function_type_nullability_suffix_question() {
|
|
featureSet = enableNnbd;
|
|
EntityRef typeRef = serializeTypeText('void Function()?');
|
|
expect(typeRef.entityKind, EntityRefKind.genericFunctionType);
|
|
expect(typeRef.nullabilitySuffix, EntityRefNullabilitySuffix.question);
|
|
}
|
|
|
|
test_function_type_nullability_suffix_star() {
|
|
featureSet = disableNnbd;
|
|
EntityRef typeRef = serializeTypeText('void Function()');
|
|
expect(typeRef.entityKind, EntityRefKind.genericFunctionType);
|
|
expect(
|
|
typeRef.nullabilitySuffix, EntityRefNullabilitySuffix.starOrIrrelevant);
|
|
}
|
|
|
|
test_generic_method_in_generic_class() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<T, U> { void m<V, W>(T t, U u, V v, W w) {} }');
|
|
List<UnlinkedParam> params = cls.executables[0].parameters;
|
|
checkParamTypeRef(params[0].type, 4);
|
|
checkParamTypeRef(params[1].type, 3);
|
|
checkParamTypeRef(params[2].type, 2);
|
|
checkParamTypeRef(params[3].type, 1);
|
|
}
|
|
|
|
test_getter_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
get f => null;''';
|
|
UnlinkedExecutable executable = serializeExecutableText(text);
|
|
expect(executable.documentationComment, isNotNull);
|
|
checkDocumentationComment(executable.documentationComment, text);
|
|
}
|
|
|
|
test_getter_inferred_type_nonstatic_explicit_return() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { num get f => null; }'
|
|
' abstract class D { int get f; }',
|
|
className: 'C',
|
|
allowErrors: true)
|
|
.executables[0];
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_getter_inferred_type_nonstatic_implicit_return() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { get f => null; } abstract class D { int get f; }',
|
|
className: 'C')
|
|
.executables[0];
|
|
checkInferredTypeSlot(f.inferredReturnTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_getter_inferred_type_static_implicit_return() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { static get f => null; }'
|
|
' class D { static int get f => null; }',
|
|
className: 'C')
|
|
.executables[0];
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_implicit_dependencies_follow_other_dependencies() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
addNamedSource('/a.dart', 'import "b.dart"; class C {} D f() => null;');
|
|
addNamedSource('/b.dart', 'class D {}');
|
|
serializeLibraryText('import "a.dart"; final x = f(); C y;');
|
|
// The dependency on b.dart is implicit, so it should be placed at the end
|
|
// of the dependency list, after a.dart, even though the code that refers
|
|
// to b.dart comes before the code that refers to a.dart.
|
|
int aDep = checkHasDependency(absUri('/a.dart'), fullyLinked: false);
|
|
int bDep = checkHasDependency(absUri('/b.dart'), fullyLinked: true);
|
|
expect(aDep, lessThan(bDep));
|
|
}
|
|
|
|
test_import_configurations() {
|
|
addNamedSource('/foo.dart', 'bar() {}');
|
|
addNamedSource('/foo_io.dart', 'bar() {}');
|
|
addNamedSource('/foo_html.dart', 'bar() {}');
|
|
String libraryText = r'''
|
|
import 'foo.dart'
|
|
if (dart.library.io) 'foo_io.dart'
|
|
if (dart.flavor == 'html') 'foo_html.dart';
|
|
''';
|
|
serializeLibraryText(libraryText);
|
|
UnlinkedImport imp = unlinkedUnits[0].imports[0];
|
|
expect(imp.configurations, hasLength(2));
|
|
{
|
|
UnlinkedConfiguration configuration = imp.configurations[0];
|
|
expect(configuration.name, 'dart.library.io');
|
|
expect(configuration.value, 'true');
|
|
expect(configuration.uri, 'foo_io.dart');
|
|
}
|
|
{
|
|
UnlinkedConfiguration configuration = imp.configurations[1];
|
|
expect(configuration.name, 'dart.flavor');
|
|
expect(configuration.value, 'html');
|
|
expect(configuration.uri, 'foo_html.dart');
|
|
}
|
|
}
|
|
|
|
test_import_deferred() {
|
|
serializeLibraryText(
|
|
'import "dart:async" deferred as a; main() { print(a.Future); }');
|
|
expect(unlinkedUnits[0].imports[0].isDeferred, isTrue);
|
|
}
|
|
|
|
test_import_dependency() {
|
|
serializeLibraryText('import "dart:async"; Future x;');
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
checkDependency(linked.importDependencies[0], 'dart:async');
|
|
}
|
|
|
|
test_import_explicit() {
|
|
serializeLibraryText('import "dart:core"; int i;');
|
|
expect(unlinkedUnits[0].imports, hasLength(1));
|
|
expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
|
|
}
|
|
|
|
test_import_hide_order() {
|
|
serializeLibraryText(
|
|
'import "dart:async" hide Future, Stream; Completer c;');
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].shows, isEmpty);
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].hides, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].hides[0], 'Future');
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].hides[1], 'Stream');
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].offset, 0);
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].end, 0);
|
|
}
|
|
|
|
test_import_implicit() {
|
|
// The implicit import of dart:core is represented in the model.
|
|
serializeLibraryText('');
|
|
expect(unlinkedUnits[0].imports, hasLength(1));
|
|
checkDependency(linked.importDependencies[0], 'dart:core');
|
|
expect(unlinkedUnits[0].imports[0].uri, isEmpty);
|
|
expect(unlinkedUnits[0].imports[0].uriOffset, 0);
|
|
expect(unlinkedUnits[0].imports[0].uriEnd, 0);
|
|
expect(unlinkedUnits[0].imports[0].prefixReference, 0);
|
|
expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
|
|
expect(unlinkedUnits[0].imports[0].isImplicit, isTrue);
|
|
}
|
|
|
|
test_import_missing() {
|
|
// Unresolved imports are included since this is necessary for proper
|
|
// dependency tracking.
|
|
allowMissingFiles = true;
|
|
serializeLibraryText('import "foo.dart";', allowErrors: true);
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
checkDependency(linked.importDependencies[0], absUri('/foo.dart'));
|
|
}
|
|
|
|
test_import_no_combinators() {
|
|
serializeLibraryText('import "dart:async"; Future x;');
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
|
|
}
|
|
|
|
test_import_no_flags() {
|
|
serializeLibraryText('import "dart:async"; Future x;');
|
|
expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
|
|
expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
|
|
}
|
|
|
|
test_import_non_deferred() {
|
|
serializeLibraryText(
|
|
'import "dart:async" as a; main() { print(a.Future); }');
|
|
expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
|
|
}
|
|
|
|
test_import_of_file_with_missing_part() {
|
|
// Other references in foo.dart should be resolved even though foo.dart's
|
|
// part declaration for bar.dart refers to a non-existent file.
|
|
allowMissingFiles = true;
|
|
addNamedSource('/foo.dart', 'part "bar.dart"; class C {}');
|
|
serializeLibraryText('import "foo.dart"; C x;');
|
|
checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'C');
|
|
}
|
|
|
|
test_import_of_missing_export() {
|
|
// Other references in foo.dart should be resolved even though foo.dart's
|
|
// re-export of bar.dart refers to a non-existent file.
|
|
allowMissingFiles = true;
|
|
addNamedSource('/foo.dart', 'export "bar.dart"; class C {}');
|
|
serializeLibraryText('import "foo.dart"; C x;');
|
|
checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'C');
|
|
}
|
|
|
|
test_import_offset() {
|
|
String libraryText = ' import "dart:async"; Future x;';
|
|
serializeLibraryText(libraryText);
|
|
expect(unlinkedUnits[0].imports[0].offset, libraryText.indexOf('import'));
|
|
expect(unlinkedUnits[0].imports[0].uriOffset,
|
|
libraryText.indexOf('"dart:async"'));
|
|
expect(unlinkedUnits[0].imports[0].uriEnd, libraryText.indexOf('; Future'));
|
|
}
|
|
|
|
test_import_prefix_name() {
|
|
String libraryText = 'import "dart:async" as a; a.Future x;';
|
|
serializeLibraryText(libraryText);
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
checkPrefix(unlinkedUnits[0].imports[0].prefixReference, 'a');
|
|
expect(unlinkedUnits[0].imports[0].prefixOffset, libraryText.indexOf('a;'));
|
|
}
|
|
|
|
test_import_prefix_none() {
|
|
serializeLibraryText('import "dart:async"; Future x;');
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].prefixReference, 0);
|
|
}
|
|
|
|
test_import_prefix_not_in_public_namespace() {
|
|
serializeLibraryText('import "dart:async" as a; a.Future v;');
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'v');
|
|
expect(unlinkedUnits[0].publicNamespace.names[1].name, 'v=');
|
|
}
|
|
|
|
test_import_prefix_reference() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('import "dart:async" as a; a.Future v;');
|
|
checkTypeRef(variable.type, 'dart:async', 'Future',
|
|
expectedPrefix: 'a', numTypeParameters: 1);
|
|
}
|
|
|
|
test_import_prefixes_take_precedence_over_imported_names() {
|
|
addNamedSource('/a.dart', 'class b {} class A');
|
|
addNamedSource('/b.dart', 'class Cls {}');
|
|
addNamedSource('/c.dart', 'class Cls {}');
|
|
addNamedSource('/d.dart', 'class c {} class D');
|
|
serializeLibraryText('''
|
|
import 'a.dart';
|
|
import 'b.dart' as b;
|
|
import 'c.dart' as c;
|
|
import 'd.dart';
|
|
A aCls;
|
|
b.Cls bCls;
|
|
c.Cls cCls;
|
|
D dCls;
|
|
''');
|
|
checkTypeRef(findVariable('aCls').type, absUri('/a.dart'), 'A');
|
|
checkTypeRef(findVariable('bCls').type, absUri('/b.dart'), 'Cls',
|
|
expectedPrefix: 'b');
|
|
checkTypeRef(findVariable('cCls').type, absUri('/c.dart'), 'Cls',
|
|
expectedPrefix: 'c');
|
|
checkTypeRef(findVariable('dCls').type, absUri('/d.dart'), 'D');
|
|
}
|
|
|
|
test_import_reference() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('import "dart:async"; Future v;');
|
|
checkTypeRef(variable.type, 'dart:async', 'Future', numTypeParameters: 1);
|
|
}
|
|
|
|
test_import_reference_merged_no_prefix() {
|
|
serializeLibraryText('''
|
|
import "dart:async" show Future;
|
|
import "dart:async" show Stream;
|
|
|
|
Future f;
|
|
Stream s;
|
|
''');
|
|
{
|
|
EntityRef typeRef = findVariable('f').type;
|
|
checkTypeRef(typeRef, 'dart:async', 'Future', numTypeParameters: 1);
|
|
}
|
|
{
|
|
EntityRef typeRef = findVariable('s').type;
|
|
checkTypeRef(typeRef, 'dart:async', 'Stream',
|
|
expectedTargetUnit: 1, numTypeParameters: 1);
|
|
}
|
|
}
|
|
|
|
test_import_reference_merged_prefixed() {
|
|
serializeLibraryText('''
|
|
import "dart:async" as a show Future;
|
|
import "dart:async" as a show Stream;
|
|
|
|
a.Future f;
|
|
a.Stream s;
|
|
''');
|
|
{
|
|
EntityRef typeRef = findVariable('f').type;
|
|
checkTypeRef(typeRef, 'dart:async', 'Future',
|
|
expectedPrefix: 'a', numTypeParameters: 1);
|
|
}
|
|
{
|
|
EntityRef typeRef = findVariable('s').type;
|
|
checkTypeRef(typeRef, 'dart:async', 'Stream',
|
|
expectedTargetUnit: 1, expectedPrefix: 'a', numTypeParameters: 1);
|
|
}
|
|
}
|
|
|
|
test_import_reference_merged_prefixed_separate_libraries() {
|
|
addNamedSource('/a.dart', 'class A {}');
|
|
addNamedSource('/b.dart', 'class B {}');
|
|
serializeLibraryText('''
|
|
import 'a.dart' as p;
|
|
import 'b.dart' as p;
|
|
|
|
p.A a;
|
|
p.B b;
|
|
''');
|
|
checkTypeRef(findVariable('a').type, absUri('/a.dart'), 'A',
|
|
expectedPrefix: 'p');
|
|
checkTypeRef(findVariable('b').type, absUri('/b.dart'), 'B',
|
|
expectedPrefix: 'p');
|
|
}
|
|
|
|
test_import_self() {
|
|
serializeLibraryText('''
|
|
import 'test.dart' as p;
|
|
class C {}
|
|
class D extends p.C {} // Prevent "unused import" warning
|
|
''');
|
|
expect(unlinkedUnits[0].imports[0].uri, 'test.dart');
|
|
checkDependency(linked.importDependencies[0], absUri('/test.dart'));
|
|
checkTypeRef(
|
|
unlinkedUnits[0].classes[1].supertype, absUri('/test.dart'), 'C',
|
|
expectedPrefix: 'p');
|
|
}
|
|
|
|
test_import_show_order() {
|
|
String libraryText =
|
|
'import "dart:async" show Future, Stream; Future x; Stream y;';
|
|
serializeLibraryText(libraryText);
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].shows, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].hides, isEmpty);
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].shows[0], 'Future');
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].shows[1], 'Stream');
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].offset,
|
|
libraryText.indexOf('show'));
|
|
expect(unlinkedUnits[0].imports[0].combinators[0].end,
|
|
libraryText.indexOf('; Future'));
|
|
}
|
|
|
|
test_import_uri() {
|
|
String uriString = '"dart:async"';
|
|
String libraryText = 'import $uriString; Future x;';
|
|
serializeLibraryText(libraryText);
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
|
|
}
|
|
|
|
test_import_uri_invalid() {
|
|
String uriString = ':[invalid uri]';
|
|
String libraryText = 'import "$uriString";';
|
|
serializeLibraryText(libraryText);
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].uri, uriString);
|
|
}
|
|
|
|
test_import_uri_nullStringValue() {
|
|
String libraryText = r'''
|
|
import "${'a'}.dart";
|
|
''';
|
|
serializeLibraryText(libraryText);
|
|
// Second import is the implicit import of dart:core
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].uri, '');
|
|
}
|
|
|
|
test_inferred_function_type_parameter_type_with_unrelated_type_param() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass c = serializeClassText('''
|
|
abstract class B<T> {
|
|
void f(void g());
|
|
}
|
|
class C<T> extends B<T> {
|
|
void f(g) {}
|
|
}
|
|
''');
|
|
expect(c.executables, hasLength(1));
|
|
UnlinkedExecutable f = c.executables[0];
|
|
expect(f.parameters, hasLength(1));
|
|
UnlinkedParam g = f.parameters[0];
|
|
expect(g.name, 'g');
|
|
EntityRef typeRef = getTypeRefForSlot(g.inferredTypeSlot);
|
|
|
|
// The type that is inferred for C.f's parameter g is "() -> void".
|
|
// Therefore it has no type arguments. However, the associated element for
|
|
// that function type is B.f's parameter g, and B has a type parameter, so
|
|
// the inferred type *may* safely record that T as a type parameter, in
|
|
// which case this assertion can be altered accordingly.
|
|
checkTypeRef(typeRef, null, 'f',
|
|
numTypeArguments: 0, entityKind: EntityRefKind.genericFunctionType);
|
|
}
|
|
|
|
test_inferred_type_keeps_leading_dynamic() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C { final x = <dynamic, int>{}; }');
|
|
EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
|
|
// Check that x has inferred type `Map<dynamic, int>`.
|
|
checkLinkedTypeRef(type, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkLinkedTypeRef(type.typeArguments[0], null, 'dynamic');
|
|
checkLinkedTypeRef(type.typeArguments[1], 'dart:core', 'int');
|
|
}
|
|
|
|
test_inferred_type_reference_shared_prefixed() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
// Variable `y` has an inferred type of `p.C`. Verify that the reference
|
|
// used by the explicit type of `x` is re-used for the inferred type.
|
|
addNamedSource('/a.dart', 'class C {}');
|
|
serializeLibraryText('import "a.dart" as p; p.C x; var y = new p.C();');
|
|
EntityRef xType = findVariable('x').type;
|
|
EntityRef yType = getTypeRefForSlot(findVariable('y').inferredTypeSlot);
|
|
expect(yType.reference, xType.reference);
|
|
}
|
|
|
|
test_inferred_type_refers_to_bound_type_param() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<T> extends D<int, T> { var v; }'
|
|
' abstract class D<U, V> { Map<V, U> get v; }',
|
|
className: 'C');
|
|
EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
|
|
// Check that v has inferred type Map<T, int>.
|
|
checkLinkedTypeRef(type, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkParamTypeRef(type.typeArguments[0], 1);
|
|
checkLinkedTypeRef(type.typeArguments[1], 'dart:core', 'int');
|
|
}
|
|
|
|
test_inferred_type_refers_to_function_typed_param_of_typedef() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedVariable v = serializeVariableText('''
|
|
typedef void F(int g(String s));
|
|
F h() => null;
|
|
var v = h();
|
|
''');
|
|
EntityRef typeRef = getTypeRefForSlot(v.inferredTypeSlot);
|
|
checkLinkedTypeRef(typeRef, null, 'F', expectedKind: ReferenceKind.typedef);
|
|
expect(typeRef.implicitFunctionTypeIndices, isEmpty);
|
|
}
|
|
|
|
test_inferred_type_refers_to_function_typed_parameter_type_generic_class() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<T, U> extends D<U, int> { void f(int x, g) {} }'
|
|
' abstract class D<V, W> { void f(int x, W g(V s)); }',
|
|
className: 'C');
|
|
EntityRef type =
|
|
getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
|
|
// Check that parameter g's inferred type is the type implied by D.f's 1st
|
|
// (zero-based) parameter.
|
|
expect(type.implicitFunctionTypeIndices, isEmpty);
|
|
expect(type.paramReference, 0);
|
|
// Note: this *may* legally have two type arguments (V, W), but for the
|
|
// moment does not in practice, so we assert isEmpty.
|
|
expect(type.typeArguments, isEmpty);
|
|
expect(type.entityKind, EntityRefKind.syntheticFunction);
|
|
expect(type.syntheticParams, hasLength(1));
|
|
checkParamTypeRef(type.syntheticParams[0].type, 1);
|
|
checkLinkedTypeRef(type.syntheticReturnType, 'dart:core', 'int');
|
|
}
|
|
|
|
test_inferred_type_refers_to_function_typed_parameter_type_other_lib() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
addNamedSource('/a.dart', 'import "b.dart"; abstract class D extends E {}');
|
|
addNamedSource(
|
|
'/b.dart', 'abstract class E { void f(int x, int g(String s)); }');
|
|
UnlinkedClass cls = serializeClassText(
|
|
'import "a.dart"; class C extends D { void f(int x, g) {} }');
|
|
EntityRef type =
|
|
getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
|
|
expect(type.implicitFunctionTypeIndices, isEmpty);
|
|
expect(type.paramReference, 0);
|
|
// Note: this *may* legally have two type arguments (V, W), but for the
|
|
// moment does not in practice, so we assert isEmpty.
|
|
expect(type.typeArguments, isEmpty);
|
|
expect(type.entityKind, EntityRefKind.syntheticFunction);
|
|
expect(type.syntheticParams, hasLength(1));
|
|
checkLinkedTypeRef(type.syntheticReturnType, 'dart:core', 'int');
|
|
checkLinkedTypeRef(type.syntheticParams[0].type, 'dart:core', 'String');
|
|
}
|
|
|
|
test_inferred_type_refers_to_method_function_typed_parameter_type() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C extends D { void f(int x, g) {} }'
|
|
' abstract class D { void f(int x, int g(String s)); }',
|
|
className: 'C');
|
|
EntityRef type =
|
|
getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
|
|
|
|
expect(type.implicitFunctionTypeIndices, isEmpty);
|
|
expect(type.paramReference, 0);
|
|
// Note: this *may* legally have two type arguments (V, W), but for the
|
|
// moment does not in practice, so we assert isEmpty.
|
|
expect(type.typeArguments, isEmpty);
|
|
expect(type.entityKind, EntityRefKind.syntheticFunction);
|
|
expect(type.syntheticParams, hasLength(1));
|
|
checkLinkedTypeRef(type.syntheticReturnType, 'dart:core', 'int');
|
|
checkLinkedTypeRef(type.syntheticParams[0].type, 'dart:core', 'String');
|
|
}
|
|
|
|
test_inferred_type_refers_to_nested_function_typed_param() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedVariable v = serializeVariableText('''
|
|
dynamic f(void g(int x, void h())) => null;
|
|
T extract<T>(dynamic f2(void g2(int x2, T h2)) => null;
|
|
var v = extract(f);
|
|
''');
|
|
EntityRef typeRef = getTypeRefForSlot(v.inferredTypeSlot);
|
|
checkLinkedTypeRef(typeRef, null, 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction);
|
|
expect(typeRef.implicitFunctionTypeIndices, [0, 1]);
|
|
}
|
|
|
|
test_inferred_type_refers_to_nested_function_typed_param_named() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedVariable v = serializeVariableText('''
|
|
dynamic f({void g(int x, void h())}) => null;
|
|
T extract<T>(dynamic f2({void g(int x2, T h2)})) => null;
|
|
var v = extract(f);
|
|
''');
|
|
EntityRef typeRef = getTypeRefForSlot(v.inferredTypeSlot);
|
|
checkLinkedTypeRef(typeRef, null, 'f',
|
|
expectedKind: ReferenceKind.topLevelFunction);
|
|
expect(typeRef.implicitFunctionTypeIndices, [0, 1]);
|
|
}
|
|
|
|
test_inferred_type_refers_to_setter_function_typed_parameter_type() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C extends D { void set f(g) {} }'
|
|
' abstract class D { void set f(int g(String s)); }',
|
|
className: 'C');
|
|
EntityRef type =
|
|
getTypeRefForSlot(cls.executables[0].parameters[0].inferredTypeSlot);
|
|
// Check that parameter g's inferred type is the type implied by D.f's 1st
|
|
// (zero-based) parameter.
|
|
expect(type.implicitFunctionTypeIndices, [0]);
|
|
expect(type.paramReference, 0);
|
|
expect(type.typeArguments, isEmpty);
|
|
expect(type.reference,
|
|
greaterThanOrEqualTo(unlinkedUnits[0].references.length));
|
|
LinkedReference linkedReference =
|
|
linked.units[0].references[type.reference];
|
|
expect(linkedReference.dependency, 0);
|
|
expect(linkedReference.kind, ReferenceKind.propertyAccessor);
|
|
expect(linkedReference.name, 'f=');
|
|
expect(linkedReference.numTypeParameters, 0);
|
|
expect(linkedReference.unit, 0);
|
|
expect(linkedReference.containingReference, isNot(0));
|
|
expect(linkedReference.containingReference, lessThan(type.reference));
|
|
checkReferenceIndex(linkedReference.containingReference, null, 'D');
|
|
}
|
|
|
|
test_inferred_type_skips_trailing_dynamic() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C { final x = <int, dynamic>{}; }');
|
|
EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
|
|
// Check that x has inferred type `Map<int, dynamic>`.
|
|
checkLinkedTypeRef(type, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkLinkedTypeRef(type.typeArguments[0], 'dart:core', 'int');
|
|
checkLinkedDynamicTypeRef(type.typeArguments[1]);
|
|
}
|
|
|
|
test_inferred_type_skips_unnecessary_dynamic() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedClass cls = serializeClassText('class C { final x = []; }');
|
|
EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
|
|
// Check that x has inferred type `List<dynamic>`.
|
|
checkLinkedTypeRef(type, 'dart:core', 'List',
|
|
numTypeParameters: 1, numTypeArguments: 1);
|
|
}
|
|
|
|
test_inferred_type_undefined() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedVariable v = serializeVariableText('var v = <Undefined>[];');
|
|
var typeRef = getTypeRefForSlot(v.inferredTypeSlot);
|
|
checkLinkedTypeRef(typeRef, 'dart:core', 'List',
|
|
numTypeArguments: 1, numTypeParameters: 1);
|
|
checkLinkedDynamicTypeRef(typeRef.typeArguments[0]);
|
|
}
|
|
|
|
test_initializer_executable_with_bottom_return_type() {
|
|
// The synthetic executable for `v` has type `() => Bottom`.
|
|
UnlinkedVariable variable = serializeVariableText('int v = null;');
|
|
expect(variable.initializer.returnType, isNull);
|
|
checkInferredTypeSlot(
|
|
variable.initializer.inferredReturnTypeSlot, null, 'Never',
|
|
onlyInStrongMode: false);
|
|
}
|
|
|
|
test_initializer_executable_with_imported_return_type() {
|
|
addNamedSource('/a.dart', 'class C { D d; } class D {}');
|
|
// The synthetic executable for `v` has type `() => D`; `D` is defined in
|
|
// a library that is imported. Note: `v` is mis-typed as `int` to prevent
|
|
// type propagation, which would complicate the test.
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'import "a.dart"; int v = new C().d;',
|
|
allowErrors: true);
|
|
expect(variable.initializer.returnType, isNull);
|
|
checkInferredTypeSlot(
|
|
variable.initializer.inferredReturnTypeSlot, absUri('/a.dart'), 'D',
|
|
onlyInStrongMode: false);
|
|
checkHasDependency(absUri('/a.dart'), fullyLinked: false);
|
|
}
|
|
|
|
test_initializer_executable_with_return_type_from_closure() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
// The synthetic executable for `v` has type `() => () => int`, where the
|
|
// `() => int` part refers to the closure declared inside the initializer
|
|
// for v. Note: `v` is mis-typed as `int` to prevent type propagation,
|
|
// which would complicate the test.
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int v = () => 0;', allowErrors: true);
|
|
EntityRef closureType =
|
|
getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
|
|
checkLinkedTypeRef(closureType, null, '',
|
|
expectedKind: ReferenceKind.function);
|
|
int initializerIndex =
|
|
definingUnit.references[closureType.reference].containingReference;
|
|
checkReferenceIndex(initializerIndex, null, '',
|
|
expectedKind: ReferenceKind.function);
|
|
int variableIndex =
|
|
definingUnit.references[initializerIndex].containingReference;
|
|
checkReferenceIndex(variableIndex, null, 'v',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor);
|
|
expect(definingUnit.references[variableIndex].containingReference, 0);
|
|
}
|
|
|
|
test_initializer_executable_with_return_type_from_closure_field() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
// The synthetic executable for `v` has type `() => () => int`, where the
|
|
// `() => int` part refers to the closure declared inside the initializer
|
|
// for v. Note: `v` is mis-typed as `int` to prevent type propagation,
|
|
// which would complicate the test.
|
|
UnlinkedClass cls = serializeClassText('''
|
|
class C {
|
|
int v = () => 0;
|
|
}
|
|
''', allowErrors: true);
|
|
UnlinkedVariable variable = cls.fields[0];
|
|
EntityRef closureType =
|
|
getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
|
|
checkLinkedTypeRef(closureType, null, '',
|
|
expectedKind: ReferenceKind.function);
|
|
int initializerIndex =
|
|
definingUnit.references[closureType.reference].containingReference;
|
|
checkReferenceIndex(initializerIndex, null, '',
|
|
expectedKind: ReferenceKind.function);
|
|
int variableIndex =
|
|
definingUnit.references[initializerIndex].containingReference;
|
|
checkReferenceIndex(variableIndex, null, 'v',
|
|
expectedKind: ReferenceKind.propertyAccessor);
|
|
int classIndex = definingUnit.references[variableIndex].containingReference;
|
|
checkReferenceIndex(classIndex, null, 'C');
|
|
expect(definingUnit.references[classIndex].containingReference, 0);
|
|
}
|
|
|
|
test_initializer_executable_with_unimported_return_type() {
|
|
addNamedSource('/a.dart', 'import "b.dart"; class C { D d; }');
|
|
addNamedSource('/b.dart', 'class D {}');
|
|
// The synthetic executable for `v` has type `() => D`; `D` is defined in
|
|
// a library that is not imported. Note: `v` is mis-typed as `int` to
|
|
// prevent type propagation, which would complicate the test.
|
|
UnlinkedVariable variable = serializeVariableText(
|
|
'import "a.dart"; int v = new C().d;',
|
|
allowErrors: true);
|
|
expect(variable.initializer.returnType, isNull);
|
|
checkInferredTypeSlot(
|
|
variable.initializer.inferredReturnTypeSlot, absUri('/b.dart'), 'D',
|
|
onlyInStrongMode: false);
|
|
if (!skipFullyLinkedData) {
|
|
checkHasDependency('b.dart', fullyLinked: true);
|
|
}
|
|
}
|
|
|
|
test_library_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
library foo;''';
|
|
serializeLibraryText(text);
|
|
expect(unlinkedUnits[0].libraryDocumentationComment, isNotNull);
|
|
checkDocumentationComment(
|
|
unlinkedUnits[0].libraryDocumentationComment, text);
|
|
}
|
|
|
|
test_library_name_with_spaces() {
|
|
String text = 'library foo . bar ;';
|
|
serializeLibraryText(text);
|
|
expect(unlinkedUnits[0].libraryName, 'foo.bar');
|
|
expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo . bar'));
|
|
expect(unlinkedUnits[0].libraryNameLength, 'foo . bar'.length);
|
|
}
|
|
|
|
test_library_named() {
|
|
String text = 'library foo.bar;';
|
|
serializeLibraryText(text);
|
|
expect(unlinkedUnits[0].libraryName, 'foo.bar');
|
|
expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo.bar'));
|
|
expect(unlinkedUnits[0].libraryNameLength, 'foo.bar'.length);
|
|
}
|
|
|
|
test_library_unnamed() {
|
|
serializeLibraryText('');
|
|
expect(unlinkedUnits[0].libraryName, isEmpty);
|
|
expect(unlinkedUnits[0].libraryNameOffset, 0);
|
|
expect(unlinkedUnits[0].libraryNameLength, 0);
|
|
}
|
|
|
|
test_library_with_missing_part() {
|
|
// References to other parts should still be resolved.
|
|
allowMissingFiles = true;
|
|
addNamedSource('/bar.dart', 'part of my.lib; class C {}');
|
|
serializeLibraryText(
|
|
'library my.lib; part "foo.dart"; part "bar.dart"; C c;',
|
|
allowErrors: true);
|
|
checkTypeRef(findVariable('c').type, null, 'C', expectedTargetUnit: 2);
|
|
}
|
|
|
|
test_lineStarts() {
|
|
String text = '''
|
|
int foo;
|
|
class Test {}
|
|
|
|
int bar;'''
|
|
.replaceAll('\r\n', '\n');
|
|
serializeLibraryText(text);
|
|
expect(unlinkedUnits[0].lineStarts, [0, 9, 23, 24]);
|
|
}
|
|
|
|
test_linked_reference_reuse() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
// When the reference for a linked type is the same as an explicitly
|
|
// referenced type, the explicit reference should be re-used.
|
|
addNamedSource('/a.dart', 'class C {}');
|
|
addNamedSource('/b.dart', 'import "a.dart"; C f() => null;');
|
|
serializeLibraryText(
|
|
'import "a.dart"; import "b.dart"; C c1; final c2 = f();');
|
|
int explicitReference = findVariable('c1').type.reference;
|
|
expect(getTypeRefForSlot(findVariable('c2').inferredTypeSlot).reference,
|
|
explicitReference);
|
|
}
|
|
|
|
test_linked_type_dependency_reuse() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
// When the dependency for a linked type is the same as an explicit
|
|
// dependency, the explicit dependency should be re-used.
|
|
addNamedSource('/a.dart', 'class C {} class D {}');
|
|
addNamedSource('/b.dart', 'import "a.dart"; D f() => null;');
|
|
serializeLibraryText(
|
|
'import "a.dart"; import "b.dart"; C c; final d = f();');
|
|
int cReference = findVariable('c').type.reference;
|
|
int explicitDependency = linked.units[0].references[cReference].dependency;
|
|
int dReference =
|
|
getTypeRefForSlot(findVariable('d').inferredTypeSlot).reference;
|
|
expect(
|
|
linked.units[0].references[dReference].dependency, explicitDependency);
|
|
}
|
|
|
|
test_local_names_take_precedence_over_imported_names() {
|
|
addNamedSource('/a.dart', 'class C {} class D {}');
|
|
serializeLibraryText('''
|
|
import 'a.dart';
|
|
class C {}
|
|
C c;
|
|
D d;''');
|
|
checkTypeRef(findVariable('c').type, null, 'C');
|
|
checkTypeRef(findVariable('d').type, absUri('/a.dart'), 'D');
|
|
}
|
|
|
|
test_localNameShadowsImportPrefix() {
|
|
serializeLibraryText('import "dart:async" as a; class a {}; a x;');
|
|
checkTypeRef(findVariable('x').type, null, 'a');
|
|
}
|
|
|
|
test_metadata_classDeclaration() {
|
|
checkAnnotationA(
|
|
serializeClassText('const a = null; @a class C {}').annotations);
|
|
}
|
|
|
|
test_metadata_classTypeAlias() {
|
|
checkAnnotationA(serializeClassText(
|
|
'const a = null; @a class C = D with E; class D {} class E {}',
|
|
className: 'C')
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_constructor_call_named() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class A { const A.named(); } @A.named() class C {}');
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'A.named()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'A')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_named_prefixed() {
|
|
addNamedSource('/foo.dart', 'class A { const A.named(); }');
|
|
UnlinkedClass cls = serializeClassText(
|
|
'import "foo.dart" as foo; @foo.A.named() class C {}');
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'foo.A.named()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'named',
|
|
expectedKind: ReferenceKind.constructor,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.classOrEnum,
|
|
'A',
|
|
absoluteUri: absUri('/foo.dart'),
|
|
),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'foo')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_named_prefixed_unresolved_class() {
|
|
addNamedSource('/foo.dart', '');
|
|
UnlinkedClass cls = serializeClassText(
|
|
'import "foo.dart" as foo; @foo.A.named() class C {}',
|
|
allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'foo.A.named()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'named',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'A'),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'foo')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_named_prefixed_unresolved_constructor() {
|
|
addNamedSource('/foo.dart', 'class A {}');
|
|
UnlinkedClass cls = serializeClassText(
|
|
'import "foo.dart" as foo; @foo.A.named() class C {}',
|
|
allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'foo.A.named()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'named',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(
|
|
ReferenceKind.classOrEnum,
|
|
'A',
|
|
absoluteUri: absUri('/foo.dart'),
|
|
),
|
|
new _PrefixExpectation(ReferenceKind.prefix, 'foo')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_named_unresolved_class() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('@A.named() class C {}', allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'A.named()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'named',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.unresolved, 'A')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_named_unresolved_constructor() {
|
|
UnlinkedClass cls = serializeClassText('class A {} @A.named() class C {}',
|
|
allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'A.named()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'named',
|
|
expectedKind: ReferenceKind.unresolved,
|
|
prefixExpectations: [
|
|
new _PrefixExpectation(ReferenceKind.classOrEnum, 'A')
|
|
])
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_unnamed() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class A { const A(); } @A() class C {}');
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'A()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'A', expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_unnamed_prefixed() {
|
|
addNamedSource('/foo.dart', 'class A { const A(); }');
|
|
UnlinkedClass cls =
|
|
serializeClassText('import "foo.dart" as foo; @foo.A() class C {}');
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'foo.A()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/foo.dart'), 'A',
|
|
expectedKind: ReferenceKind.classOrEnum, expectedPrefix: 'foo')
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_unnamed_prefixed_unresolved() {
|
|
addNamedSource('/foo.dart', '');
|
|
UnlinkedClass cls = serializeClassText(
|
|
'import "foo.dart" as foo; @foo.A() class C {}',
|
|
allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'foo.A()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'A',
|
|
expectedKind: ReferenceKind.unresolved, expectedPrefix: 'foo')
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_unnamed_unresolved() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('@A() class C {}', allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'A()', operators: [
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
0
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'A', expectedKind: ReferenceKind.unresolved)
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructor_call_with_args() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class A { const A(x); } @A(null) class C {}');
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'A(null)', operators: [
|
|
UnlinkedExprOperation.pushNull,
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
1
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'A', expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_metadata_constructorDeclaration_named() {
|
|
checkAnnotationA(
|
|
serializeClassText('const a = null; class C { @a C.named(); }')
|
|
.executables[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_constructorDeclaration_unnamed() {
|
|
checkAnnotationA(serializeClassText('const a = null; class C { @a C(); }')
|
|
.executables[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_enumConstantDeclaration() {
|
|
checkAnnotationA(serializeEnumText('const a = null; enum E { @a v }')
|
|
.values[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_enumDeclaration() {
|
|
checkAnnotationA(
|
|
serializeEnumText('const a = null; @a enum E { v }').annotations);
|
|
}
|
|
|
|
test_metadata_exportDirective() {
|
|
addNamedSource('/foo.dart', '');
|
|
serializeLibraryText('@a export "foo.dart"; const a = null;');
|
|
checkAnnotationA(unlinkedUnits[0].exports[0].annotations);
|
|
}
|
|
|
|
test_metadata_fieldDeclaration() {
|
|
checkAnnotationA(serializeClassText('const a = null; class C { @a int x; }')
|
|
.fields[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_fieldFormalParameter() {
|
|
checkAnnotationA(
|
|
serializeClassText('const a = null; class C { var x; C(@a this.x); }')
|
|
.executables[0]
|
|
.parameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_fieldFormalParameter_withDefault() {
|
|
checkAnnotationA(serializeClassText(
|
|
'const a = null; class C { var x; C([@a this.x = null]); }')
|
|
.executables[0]
|
|
.parameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_functionDeclaration_function() {
|
|
checkAnnotationA(
|
|
serializeExecutableText('const a = null; @a f() {}').annotations);
|
|
}
|
|
|
|
test_metadata_functionDeclaration_getter() {
|
|
checkAnnotationA(
|
|
serializeExecutableText('const a = null; @a get f => null;')
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_functionDeclaration_setter() {
|
|
checkAnnotationA(serializeExecutableText(
|
|
'const a = null; @a set f(value) {}',
|
|
executableName: 'f=')
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_functionTypeAlias() {
|
|
checkAnnotationA(
|
|
serializeTypedefText('const a = null; @a typedef F();').annotations);
|
|
}
|
|
|
|
test_metadata_functionTypedFormalParameter() {
|
|
checkAnnotationA(serializeExecutableText('const a = null; f(@a g()) {}')
|
|
.parameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_functionTypedFormalParameter_withDefault() {
|
|
checkAnnotationA(
|
|
serializeExecutableText('const a = null; f([@a g() = null]) {}')
|
|
.parameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_importDirective() {
|
|
addNamedSource('/foo.dart', 'const b = null;');
|
|
serializeLibraryText('@a import "foo.dart"; const a = b;');
|
|
checkAnnotationA(unlinkedUnits[0].imports[0].annotations);
|
|
}
|
|
|
|
test_metadata_invalid_assignable() {
|
|
// Verify that the following does not cause an exception to be thrown.
|
|
serializeLibraryText('@a(-b=""c');
|
|
expect(unlinkedUnits, hasLength(1));
|
|
List<UnlinkedVariable> variables = unlinkedUnits[0].variables;
|
|
if (Parser.useFasta) {
|
|
// Fasta recovers by appending `)` after `c`
|
|
expect(variables, isEmpty);
|
|
} else {
|
|
expect(variables, hasLength(1));
|
|
List<UnlinkedExpr> annotations = variables[0].annotations;
|
|
expect(annotations, hasLength(1));
|
|
expect(annotations[0].isValidConst, isFalse);
|
|
}
|
|
}
|
|
|
|
test_metadata_invalid_instanceCreation_argument_super() {
|
|
List<UnlinkedExpr> annotations = serializeClassText('''
|
|
class A {
|
|
const A(_);
|
|
}
|
|
|
|
@A(super)
|
|
class C {}
|
|
''').annotations;
|
|
expect(annotations, hasLength(1));
|
|
assertUnlinkedConst(annotations[0], 'A(super)', operators: [
|
|
UnlinkedExprOperation.pushSuper,
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
1
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'A', expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_metadata_invalid_instanceCreation_argument_this() {
|
|
List<UnlinkedExpr> annotations = serializeClassText('''
|
|
class A {
|
|
const A(_);
|
|
}
|
|
|
|
@A(this)
|
|
class C {}
|
|
''').annotations;
|
|
expect(annotations, hasLength(1));
|
|
assertUnlinkedConst(annotations[0], 'A(this)', operators: [
|
|
UnlinkedExprOperation.pushThis,
|
|
UnlinkedExprOperation.invokeConstructor,
|
|
], ints: [
|
|
0,
|
|
1
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'A', expectedKind: ReferenceKind.classOrEnum)
|
|
]);
|
|
}
|
|
|
|
test_metadata_libraryDirective() {
|
|
serializeLibraryText('@a library L; const a = null;');
|
|
checkAnnotationA(unlinkedUnits[0].libraryAnnotations);
|
|
}
|
|
|
|
test_metadata_methodDeclaration_getter() {
|
|
checkAnnotationA(
|
|
serializeClassText('const a = null; class C { @a get m => null; }')
|
|
.executables[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_methodDeclaration_method() {
|
|
checkAnnotationA(serializeClassText('const a = null; class C { @a m() {} }')
|
|
.executables[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_methodDeclaration_setter() {
|
|
checkAnnotationA(
|
|
serializeClassText('const a = null; class C { @a set m(value) {} }')
|
|
.executables[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_mixinDeclaration() {
|
|
checkAnnotationA(
|
|
serializeMixinText('const a = null; @a mixin M {}').annotations);
|
|
}
|
|
|
|
test_metadata_multiple_annotations() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('const a = null, b = null; @a @b class C {}');
|
|
List<UnlinkedExpr> annotations = cls.annotations;
|
|
expect(annotations, hasLength(2));
|
|
assertUnlinkedConst(annotations[0], 'a', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
assertUnlinkedConst(annotations[1], 'b', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'b',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
]);
|
|
}
|
|
|
|
test_metadata_partDirective() {
|
|
addNamedSource('/foo.dart', 'part of L;');
|
|
serializeLibraryText('library L; @a part "foo.dart"; const a = null;');
|
|
checkAnnotationA(unlinkedUnits[0].parts[0].annotations);
|
|
}
|
|
|
|
test_metadata_prefixed_variable() {
|
|
addNamedSource('/a.dart', 'const b = null;');
|
|
UnlinkedClass cls =
|
|
serializeClassText('import "a.dart" as a; @a.b class C {}');
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'a.b', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'b',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor,
|
|
expectedPrefix: 'a')
|
|
]);
|
|
}
|
|
|
|
test_metadata_prefixed_variable_unresolved() {
|
|
addNamedSource('/a.dart', '');
|
|
UnlinkedClass cls = serializeClassText(
|
|
'import "a.dart" as a; @a.b class C {}',
|
|
allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'a.b', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'b',
|
|
expectedKind: ReferenceKind.unresolved, expectedPrefix: 'a')
|
|
]);
|
|
}
|
|
|
|
test_metadata_simpleFormalParameter() {
|
|
checkAnnotationA(serializeExecutableText('const a = null; f(@a x) {}')
|
|
.parameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_simpleFormalParameter_withDefault() {
|
|
checkAnnotationA(
|
|
serializeExecutableText('const a = null; f([@a x = null]) {}')
|
|
.parameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_topLevelVariableDeclaration() {
|
|
checkAnnotationA(
|
|
serializeVariableText('const a = null; @a int v;').annotations);
|
|
}
|
|
|
|
test_metadata_typeParameter_ofClass() {
|
|
checkAnnotationA(serializeClassText('const a = null; class C<@a T> {}')
|
|
.typeParameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_typeParameter_ofClassTypeAlias() {
|
|
checkAnnotationA(serializeClassText(
|
|
'const a = null; class C<@a T> = D with E; class D {} class E {}',
|
|
className: 'C')
|
|
.typeParameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_typeParameter_ofFunction() {
|
|
checkAnnotationA(serializeExecutableText('const a = null; f<@a T>() {}')
|
|
.typeParameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_typeParameter_ofTypedef() {
|
|
checkAnnotationA(serializeTypedefText('const a = null; typedef F<@a T>();')
|
|
.typeParameters[0]
|
|
.annotations);
|
|
}
|
|
|
|
test_metadata_variable_unresolved() {
|
|
UnlinkedClass cls = serializeClassText('@a class C {}', allowErrors: true);
|
|
expect(cls.annotations, hasLength(1));
|
|
assertUnlinkedConst(cls.annotations[0], 'a', operators: [
|
|
UnlinkedExprOperation.pushReference
|
|
], referenceValidators: [
|
|
(EntityRef r) =>
|
|
checkTypeRef(r, null, 'a', expectedKind: ReferenceKind.unresolved)
|
|
]);
|
|
}
|
|
|
|
test_method_documented() {
|
|
String text = '''
|
|
class C {
|
|
/**
|
|
* Docs
|
|
*/
|
|
f() {}
|
|
}''';
|
|
UnlinkedExecutable executable = serializeClassText(text).executables[0];
|
|
expect(executable.documentationComment, isNotNull);
|
|
checkDocumentationComment(executable.documentationComment, text);
|
|
}
|
|
|
|
test_method_inferred_type_nonstatic_explicit_param() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { void f(num value) {} }'
|
|
' abstract class D { void f(int value); }',
|
|
className: 'C')
|
|
.executables[0];
|
|
expect(f.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_method_inferred_type_nonstatic_explicit_return() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { num f() => null; } abstract class D { int f(); }',
|
|
className: 'C',
|
|
allowErrors: true)
|
|
.executables[0];
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_method_inferred_type_nonstatic_implicit_param() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { void f(value) {} }'
|
|
' abstract class D { void f(int value); }',
|
|
className: 'C')
|
|
.executables[0];
|
|
checkInferredTypeSlot(f.parameters[0].inferredTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_method_inferred_type_nonstatic_implicit_return() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { f() => null; } abstract class D { int f(); }',
|
|
className: 'C')
|
|
.executables[0];
|
|
checkInferredTypeSlot(f.inferredReturnTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_method_inferred_type_static_implicit_param() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { static void f(value) {} }'
|
|
' class D { static void f(int value) {} }',
|
|
className: 'C')
|
|
.executables[0];
|
|
expect(f.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_method_inferred_type_static_implicit_return() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { static f() => null; }'
|
|
' class D { static int f() => null; }',
|
|
className: 'C')
|
|
.executables[0];
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_mixin() {
|
|
UnlinkedClass mixin = serializeMixinText('mixin M {}');
|
|
expect(mixin.name, 'M');
|
|
expect(mixin.nameOffset, 6);
|
|
|
|
expect(mixin.executables, isEmpty);
|
|
expect(mixin.interfaces, isEmpty);
|
|
expect(mixin.mixins, isEmpty);
|
|
expect(mixin.superclassConstraints, isEmpty);
|
|
}
|
|
|
|
test_mixin_codeRange() {
|
|
UnlinkedClass mixin = serializeMixinText(' mixin M {}');
|
|
_assertCodeRange(mixin.codeRange, 1, 10);
|
|
}
|
|
|
|
test_mixin_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
mixin M {}''';
|
|
UnlinkedClass mixin = serializeMixinText(text);
|
|
expect(mixin.documentationComment, isNotNull);
|
|
checkDocumentationComment(mixin.documentationComment, text);
|
|
}
|
|
|
|
test_mixin_documented_tripleSlash() {
|
|
String text = '''
|
|
/// aaa
|
|
/// bbbb
|
|
/// cc
|
|
mixin M {}''';
|
|
UnlinkedClass mixin = serializeMixinText(text);
|
|
UnlinkedDocumentationComment comment = mixin.documentationComment;
|
|
expect(comment, isNotNull);
|
|
expect(comment.text, '/// aaa\n/// bbbb\n/// cc');
|
|
}
|
|
|
|
test_mixin_executables() {
|
|
UnlinkedClass mixin = serializeMixinText(r'''
|
|
mixin M {
|
|
double f;
|
|
int get g => 0;
|
|
set s(int v) {}
|
|
int m(int v) => 0;
|
|
}
|
|
''');
|
|
expect(mixin.fields, hasLength(1));
|
|
expect(mixin.fields[0].name, 'f');
|
|
checkTypeRef(mixin.fields[0].type, 'dart:core', 'double');
|
|
|
|
expect(mixin.executables, hasLength(3));
|
|
|
|
expect(mixin.executables[0].name, 'g');
|
|
expect(mixin.executables[0].kind, UnlinkedExecutableKind.getter);
|
|
checkTypeRef(mixin.executables[0].returnType, 'dart:core', 'int');
|
|
|
|
expect(mixin.executables[1].name, 's=');
|
|
expect(mixin.executables[1].kind, UnlinkedExecutableKind.setter);
|
|
|
|
expect(mixin.executables[2].name, 'm');
|
|
expect(mixin.executables[2].kind, UnlinkedExecutableKind.functionOrMethod);
|
|
checkTypeRef(mixin.executables[2].returnType, 'dart:core', 'int');
|
|
}
|
|
|
|
test_mixin_implements() {
|
|
UnlinkedClass mixin = serializeMixinText(r'''
|
|
class A {}
|
|
class B {}
|
|
mixin M implements A, B {}
|
|
''');
|
|
expect(mixin.executables, isEmpty);
|
|
expect(mixin.mixins, isEmpty);
|
|
expect(mixin.superclassConstraints, isEmpty);
|
|
|
|
expect(mixin.interfaces, hasLength(2));
|
|
checkTypeRef(mixin.interfaces[0], null, 'A');
|
|
checkTypeRef(mixin.interfaces[1], null, 'B');
|
|
}
|
|
|
|
test_mixin_superclassConstraints() {
|
|
UnlinkedClass mixin = serializeMixinText(r'''
|
|
class A {}
|
|
class B {}
|
|
class C {}
|
|
class D {}
|
|
mixin M on A, B implements C, D {}
|
|
''');
|
|
expect(mixin.executables, isEmpty);
|
|
expect(mixin.mixins, isEmpty);
|
|
|
|
expect(mixin.superclassConstraints, hasLength(2));
|
|
checkTypeRef(mixin.superclassConstraints[0], null, 'A');
|
|
checkTypeRef(mixin.superclassConstraints[1], null, 'B');
|
|
|
|
expect(mixin.interfaces, hasLength(2));
|
|
checkTypeRef(mixin.interfaces[0], null, 'C');
|
|
checkTypeRef(mixin.interfaces[1], null, 'D');
|
|
}
|
|
|
|
test_mixin_superInvokedNames_methodInvocation() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super.a();
|
|
super.b().c();
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['a', 'b']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_operator_binary() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super + 1;
|
|
super - 2;
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['+', '-']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_operator_index() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super[0];
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['[]']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_operator_index_indexEq() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super[0] += 1;
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['[]', '[]=']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_operator_indexEq() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super[0] = 1;
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['[]=']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_operator_prefix() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
~super;
|
|
-super;
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['~', 'unary-']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_propertyAccess_get() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super.a;
|
|
super.b.c;
|
|
|
|
~super.e;
|
|
-super.d;
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['a', 'b', 'd', 'e']));
|
|
}
|
|
|
|
test_mixin_superInvokedNames_propertyAccess_get_set() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super.a++;
|
|
--super.b;
|
|
super.c += 1;
|
|
}
|
|
}
|
|
''');
|
|
expect(
|
|
mixin.superInvokedNames,
|
|
unorderedEquals(['a', 'b', 'c', 'a=', 'b=', 'c=']),
|
|
);
|
|
}
|
|
|
|
test_mixin_superInvokedNames_propertyAccess_set() {
|
|
UnlinkedClass mixin = serializeMixinText('''
|
|
mixin M {
|
|
void x() {
|
|
super.a = 1;
|
|
}
|
|
}
|
|
''');
|
|
expect(mixin.superInvokedNames, unorderedEquals(['a=']));
|
|
}
|
|
|
|
test_mixin_typeParameters() {
|
|
UnlinkedClass mixin = serializeMixinText('mixin M<T extends num, U> {}');
|
|
expect(mixin.typeParameters, hasLength(2));
|
|
|
|
expect(mixin.typeParameters[0].name, 'T');
|
|
checkTypeRef(mixin.typeParameters[0].bound, 'dart:core', 'num');
|
|
|
|
expect(mixin.typeParameters[1].name, 'U');
|
|
expect(mixin.typeParameters[1].bound, isNull);
|
|
}
|
|
|
|
test_nested_generic_functions() {
|
|
UnlinkedExecutable executable = serializeVariableText('''
|
|
var v = (() {
|
|
void f<T, U>() {
|
|
void g<V, W>() {
|
|
void h<X, Y>(T t, U u, V v W w, X x, Y y) {
|
|
}
|
|
}
|
|
}
|
|
});
|
|
''').initializer.localFunctions[0].localFunctions[0];
|
|
expect(executable.typeParameters, hasLength(2));
|
|
expect(executable.localFunctions[0].typeParameters, hasLength(2));
|
|
expect(executable.localFunctions[0].localFunctions[0].typeParameters,
|
|
hasLength(2));
|
|
List<UnlinkedParam> parameters =
|
|
executable.localFunctions[0].localFunctions[0].parameters;
|
|
checkParamTypeRef(findParameter(parameters, 't').type, 6);
|
|
checkParamTypeRef(findParameter(parameters, 'u').type, 5);
|
|
checkParamTypeRef(findParameter(parameters, 'v').type, 4);
|
|
checkParamTypeRef(findParameter(parameters, 'w').type, 3);
|
|
checkParamTypeRef(findParameter(parameters, 'x').type, 2);
|
|
checkParamTypeRef(findParameter(parameters, 'y').type, 1);
|
|
}
|
|
|
|
test_new_typedef_notSimplyBoundedSlot() {
|
|
var typedef =
|
|
serializeTypedefText('typedef F<T extends F> = void Function();');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_new_typedef_notSimplyBoundedSlot_simple_no_bounds() {
|
|
// If no bounds are specified, then the typedef is simply bounded, however
|
|
// it still gets a slot because all typedefs are assigned a slot.
|
|
var typedef = serializeTypedefText('typedef F<T> = void Function();');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(typedef.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_new_typedef_notSimplyBoundedSlot_simple_non_generic() {
|
|
// If no type parameters are specified, then the typedef is simply bounded,
|
|
// however it still gets a slot because all typedefs are assigned a slot.
|
|
var typedef = serializeTypedefText('typedef F = void Function();');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(typedef.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_old_typedef_notSimplyBoundedSlot() {
|
|
var typedef = serializeTypedefText('typedef void F<T extends F>();');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_old_typedef_notSimplyBoundedSlot_simple_because_non_generic() {
|
|
// If no type parameters are specified, then the typedef is simply bounded,
|
|
// however it still gets a slot because all typedefs are assigned a slot.
|
|
var typedef = serializeTypedefText('typedef void F();');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(typedef.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_old_typedef_notSimplyBoundedSlot_simple_no_bounds() {
|
|
// If no bounds are specified, then the typedef is simply bounded, however
|
|
// it still gets a slot because all typedefs are assigned a slot.
|
|
var typedef = serializeTypedefText('typedef void F<T>();');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
isNot(contains(typedef.notSimplyBoundedSlot)));
|
|
}
|
|
}
|
|
|
|
test_parameter_visibleRange_abstractMethod() {
|
|
UnlinkedExecutable m = findExecutable('m',
|
|
executables:
|
|
serializeClassText('abstract class C { m(p); }').executables,
|
|
failIfAbsent: true);
|
|
_assertParameterZeroVisibleRange(m.parameters[0]);
|
|
}
|
|
|
|
test_parameter_visibleRange_function_blockBody() {
|
|
String text = r'''
|
|
var v = (() {
|
|
f(x) { // 1
|
|
f2(y) { // 2
|
|
} // 3
|
|
} // 4
|
|
});
|
|
''';
|
|
var closure = serializeVariableText(text).initializer.localFunctions[0];
|
|
UnlinkedExecutable f = closure.localFunctions[0];
|
|
UnlinkedExecutable f2 = f.localFunctions[0];
|
|
_assertParameterVisible(text, f.parameters[0], '{ // 1', '} // 4');
|
|
_assertParameterVisible(text, f2.parameters[0], '{ // 2', '} // 3');
|
|
}
|
|
|
|
test_parameter_visibleRange_function_emptyBody() {
|
|
UnlinkedExecutable f = serializeExecutableText('external f(x);');
|
|
_assertParameterZeroVisibleRange(f.parameters[0]);
|
|
}
|
|
|
|
test_parameter_visibleRange_function_expressionBody() {
|
|
String text = r'''
|
|
f(x) => 42;
|
|
''';
|
|
UnlinkedExecutable f = serializeExecutableText(text);
|
|
_assertParameterVisible(text, f.parameters[0], '=>', ';');
|
|
}
|
|
|
|
test_parameter_visibleRange_inFunctionTypedParameter() {
|
|
String text = 'f(g(p)) {}';
|
|
UnlinkedExecutable f = serializeExecutableText(text);
|
|
UnlinkedParam g = f.parameters[0];
|
|
UnlinkedParam p = g.parameters[0];
|
|
expect(g.name, 'g');
|
|
expect(p.name, 'p');
|
|
_assertParameterVisible(text, g, '{', '}');
|
|
_assertParameterZeroVisibleRange(p);
|
|
}
|
|
|
|
test_parameter_visibleRange_invalid_fieldFormalParameter() {
|
|
UnlinkedExecutable m =
|
|
findExecutable('m', executables: serializeClassText(r'''
|
|
class C {
|
|
int foo;
|
|
void m(this.foo) {}
|
|
}
|
|
''').executables);
|
|
_assertParameterZeroVisibleRange(m.parameters[0]);
|
|
}
|
|
|
|
test_parameter_visibleRange_typedef() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F(x);');
|
|
_assertParameterZeroVisibleRange(type.parameters[0]);
|
|
}
|
|
|
|
test_part_declaration() {
|
|
addNamedSource('/a.dart', 'part of my.lib;');
|
|
String text = 'library my.lib; part "a.dart"; // <-part';
|
|
serializeLibraryText(text);
|
|
expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.parts[0], 'a.dart');
|
|
expect(unlinkedUnits[0].parts, hasLength(1));
|
|
expect(unlinkedUnits[0].parts[0].uriOffset, text.indexOf('"a.dart"'));
|
|
expect(unlinkedUnits[0].parts[0].uriEnd, text.indexOf('; // <-part'));
|
|
}
|
|
|
|
test_part_declaration_invalidUri_nullStringValue() {
|
|
addNamedSource('/a.dart', 'part of my.lib;');
|
|
String text = r'''
|
|
library my.lib;
|
|
part "${'a'}.dart"; // <-part
|
|
''';
|
|
serializeLibraryText(text);
|
|
expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.parts[0], '');
|
|
expect(unlinkedUnits[0].parts, hasLength(1));
|
|
expect(unlinkedUnits[0].parts[0].uriOffset, text.indexOf(r'"${'));
|
|
expect(unlinkedUnits[0].parts[0].uriEnd, text.indexOf('; // <-part'));
|
|
}
|
|
|
|
test_part_isPartOf() {
|
|
addNamedSource('/a.dart', 'part of foo; class C {}');
|
|
serializeLibraryText('library foo; part "a.dart";');
|
|
expect(unlinkedUnits[0].isPartOf, isFalse);
|
|
expect(unlinkedUnits[1].isPartOf, isTrue);
|
|
}
|
|
|
|
test_part_uri_invalid() {
|
|
String uriString = ':[invalid uri]';
|
|
String libraryText = 'part "$uriString";';
|
|
serializeLibraryText(libraryText);
|
|
expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.parts[0], uriString);
|
|
}
|
|
|
|
test_parts_defining_compilation_unit() {
|
|
serializeLibraryText('');
|
|
expect(linked.units, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.parts, isEmpty);
|
|
}
|
|
|
|
test_parts_included() {
|
|
addNamedSource('/part1.dart', 'part of my.lib;');
|
|
String partString = '"part1.dart"';
|
|
String libraryText = 'library my.lib; part $partString;';
|
|
serializeLibraryText(libraryText);
|
|
expect(linked.units, hasLength(2));
|
|
expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.parts[0], 'part1.dart');
|
|
}
|
|
|
|
test_public_namespace_of_part() {
|
|
addNamedSource('/a.dart', 'part of foo; class C {}');
|
|
serializeLibraryText('library foo; part "a.dart";');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
expect(unlinkedUnits[1].publicNamespace.names, hasLength(1));
|
|
expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
|
|
}
|
|
|
|
test_reference_zero() {
|
|
// Element zero of the references table should be populated in a standard
|
|
// way.
|
|
serializeLibraryText('');
|
|
UnlinkedReference unlinkedReference0 = unlinkedUnits[0].references[0];
|
|
expect(unlinkedReference0.name, '');
|
|
expect(unlinkedReference0.prefixReference, 0);
|
|
LinkedReference linkedReference0 = linked.units[0].references[0];
|
|
expect(linkedReference0.containingReference, 0);
|
|
expect(linkedReference0.dependency, 0);
|
|
expect(linkedReference0.kind, ReferenceKind.unresolved);
|
|
expect(linkedReference0.name, '');
|
|
expect(linkedReference0.numTypeParameters, 0);
|
|
expect(linkedReference0.unit, 0);
|
|
}
|
|
|
|
test_setter_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
void set f(value) {}''';
|
|
UnlinkedExecutable executable =
|
|
serializeExecutableText(text, executableName: 'f=');
|
|
expect(executable.documentationComment, isNotNull);
|
|
checkDocumentationComment(executable.documentationComment, text);
|
|
}
|
|
|
|
test_setter_inferred_type_nonstatic_explicit_param() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { void set f(num value) {} }'
|
|
' abstract class D { void set f(int value); }',
|
|
className: 'C')
|
|
.executables[0];
|
|
expect(f.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_setter_inferred_type_nonstatic_explicit_return() {
|
|
UnlinkedExecutable f =
|
|
serializeClassText('class C { void set f(int value) {} }')
|
|
.executables[0];
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_setter_inferred_type_nonstatic_implicit_param() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { void set f(value) {} }'
|
|
' abstract class D { void set f(int value); }',
|
|
className: 'C')
|
|
.executables[0];
|
|
checkInferredTypeSlot(f.parameters[0].inferredTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_setter_inferred_type_nonstatic_implicit_return() {
|
|
UnlinkedExecutable f =
|
|
serializeClassText('class C { set f(int value) {} }').executables[0];
|
|
checkInferredTypeSlot(f.inferredReturnTypeSlot, null, 'void');
|
|
}
|
|
|
|
test_setter_inferred_type_static_implicit_param() {
|
|
UnlinkedExecutable f = serializeClassText(
|
|
'class C extends D { static void set f(value) {} }'
|
|
' class D { static void set f(int value) {} }',
|
|
className: 'C')
|
|
.executables[0];
|
|
expect(f.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_setter_inferred_type_static_implicit_return() {
|
|
UnlinkedExecutable f =
|
|
serializeClassText('class C { static set f(int value) {} }')
|
|
.executables[0];
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_setter_inferred_type_top_level_implicit_param() {
|
|
UnlinkedExecutable f =
|
|
serializeExecutableText('void set f(value) {}', executableName: 'f=');
|
|
expect(f.parameters[0].inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_setter_inferred_type_top_level_implicit_return() {
|
|
UnlinkedExecutable f =
|
|
serializeExecutableText('set f(int value) {}', executableName: 'f=');
|
|
expect(f.inferredReturnTypeSlot, 0);
|
|
}
|
|
|
|
test_slot_reuse() {
|
|
// Different compilation units have independent notions of slot id, so slot
|
|
// ids should be reused.
|
|
addNamedSource('/a.dart', 'part of foo; final v = 0;');
|
|
serializeLibraryText('library foo; part "a.dart"; final w = 0;');
|
|
expect(unlinkedUnits[1].variables[0].inferredTypeSlot,
|
|
unlinkedUnits[0].variables[0].inferredTypeSlot);
|
|
}
|
|
|
|
test_syntheticFunctionType_genericClosure() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
// TODO(paulberry): once proper generic method syntax supports generic
|
|
// closures, rewrite the test below without using generic comment syntax,
|
|
// and remove this hack. See dartbug.com/25819
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
final v = f() ? /*<T>*/(T t) => 0 : /*<T>*/(T t) => 1;
|
|
bool f() => true;
|
|
''');
|
|
EntityRef inferredType = getTypeRefForSlot(variable.inferredTypeSlot);
|
|
checkLinkedTypeRef(inferredType.syntheticReturnType, 'dart:core', 'int');
|
|
expect(inferredType.syntheticParams, hasLength(1));
|
|
checkLinkedTypeRef(inferredType.syntheticParams[0].type, null, 'Never');
|
|
}
|
|
|
|
test_syntheticFunctionType_inGenericClass() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedVariable variable = serializeClassText('''
|
|
class C<T, U> {
|
|
var v = f() ? (T t, U u) => 0 : (T t, U u) => 1;
|
|
}
|
|
bool f() => false;
|
|
''').fields[0];
|
|
EntityRef inferredType =
|
|
getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
|
|
checkLinkedTypeRef(inferredType.syntheticReturnType, 'dart:core', 'int');
|
|
checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
|
|
checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
|
|
}
|
|
|
|
test_type_arguments_explicit() {
|
|
EntityRef typeRef = serializeTypeText('List<int>');
|
|
checkTypeRef(typeRef, 'dart:core', 'List',
|
|
numTypeParameters: 1, numTypeArguments: 1);
|
|
checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'int');
|
|
}
|
|
|
|
test_type_arguments_explicit_dynamic() {
|
|
EntityRef typeRef = serializeTypeText('List<dynamic>');
|
|
checkTypeRef(typeRef, 'dart:core', 'List',
|
|
numTypeParameters: 1, numTypeArguments: 1);
|
|
checkDynamicTypeRef(typeRef.typeArguments[0]);
|
|
}
|
|
|
|
test_type_arguments_explicit_dynamic_dynamic() {
|
|
EntityRef typeRef = serializeTypeText('Map<dynamic, dynamic>');
|
|
checkTypeRef(typeRef, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkDynamicTypeRef(typeRef.typeArguments[0]);
|
|
checkDynamicTypeRef(typeRef.typeArguments[1]);
|
|
}
|
|
|
|
test_type_arguments_explicit_dynamic_int() {
|
|
EntityRef typeRef = serializeTypeText('Map<dynamic, int>');
|
|
checkTypeRef(typeRef, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkDynamicTypeRef(typeRef.typeArguments[0]);
|
|
checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'int');
|
|
}
|
|
|
|
test_type_arguments_explicit_dynamic_typedef() {
|
|
EntityRef typeRef =
|
|
serializeTypeText('F<dynamic>', otherDeclarations: 'typedef T F<T>();');
|
|
checkTypeRef(typeRef, null, 'F',
|
|
expectedKind: ReferenceKind.typedef,
|
|
numTypeParameters: 1,
|
|
numTypeArguments: 1);
|
|
checkDynamicTypeRef(typeRef.typeArguments[0]);
|
|
}
|
|
|
|
test_type_arguments_explicit_String_dynamic() {
|
|
EntityRef typeRef = serializeTypeText('Map<String, dynamic>');
|
|
checkTypeRef(typeRef, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'String');
|
|
checkDynamicTypeRef(typeRef.typeArguments[1]);
|
|
}
|
|
|
|
test_type_arguments_explicit_String_int() {
|
|
EntityRef typeRef = serializeTypeText('Map<String, int>');
|
|
checkTypeRef(typeRef, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'String');
|
|
checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'int');
|
|
}
|
|
|
|
test_type_arguments_explicit_typedef() {
|
|
EntityRef typeRef =
|
|
serializeTypeText('F<int>', otherDeclarations: 'typedef T F<T>();');
|
|
checkTypeRef(typeRef, null, 'F',
|
|
expectedKind: ReferenceKind.typedef,
|
|
numTypeParameters: 1,
|
|
numTypeArguments: 1);
|
|
checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'int');
|
|
}
|
|
|
|
test_type_arguments_implicit() {
|
|
EntityRef typeRef = serializeTypeText('List');
|
|
checkTypeRef(typeRef, 'dart:core', 'List', numTypeParameters: 1);
|
|
}
|
|
|
|
test_type_arguments_implicit_typedef() {
|
|
EntityRef typeRef =
|
|
serializeTypeText('F', otherDeclarations: 'typedef T F<T>();');
|
|
checkTypeRef(typeRef, null, 'F',
|
|
expectedKind: ReferenceKind.typedef, numTypeParameters: 1);
|
|
}
|
|
|
|
test_type_arguments_implicit_typedef_withBound() {
|
|
EntityRef typeRef = serializeTypeText('F',
|
|
otherDeclarations: 'typedef T F<T extends num>();');
|
|
checkTypeRef(typeRef, null, 'F',
|
|
expectedKind: ReferenceKind.typedef, numTypeParameters: 1);
|
|
}
|
|
|
|
test_type_arguments_order() {
|
|
EntityRef typeRef = serializeTypeText('Map<int, Object>');
|
|
checkTypeRef(typeRef, 'dart:core', 'Map',
|
|
numTypeParameters: 2, numTypeArguments: 2);
|
|
checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'int');
|
|
checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'Object');
|
|
}
|
|
|
|
test_type_dynamic() {
|
|
checkDynamicTypeRef(serializeTypeText('dynamic'));
|
|
}
|
|
|
|
test_type_inference_based_on_type_parameter() {
|
|
var class_ = serializeClassText('''
|
|
class C<T> {
|
|
var field = T;
|
|
}
|
|
''');
|
|
var field = class_.fields[0];
|
|
checkLinkedTypeSlot(field.inferredTypeSlot, 'dart:core', 'Type');
|
|
}
|
|
|
|
test_type_invalid_typeParameter_asPrefix() {
|
|
UnlinkedClass c = serializeClassText('''
|
|
class C<T> {
|
|
m(T.K p) {}
|
|
}
|
|
''');
|
|
UnlinkedExecutable m = c.executables[0];
|
|
expect(m.name, 'm');
|
|
checkTypeRef(m.parameters[0].type, null, 'dynamic');
|
|
}
|
|
|
|
test_type_nullability_suffix_none() {
|
|
featureSet = enableNnbd;
|
|
EntityRef typeRef = serializeTypeText('int');
|
|
checkTypeRef(typeRef, 'dart:core', 'int',
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.none);
|
|
}
|
|
|
|
test_type_nullability_suffix_question() {
|
|
featureSet = enableNnbd;
|
|
EntityRef typeRef = serializeTypeText('int?');
|
|
checkTypeRef(typeRef, 'dart:core', 'int',
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.question);
|
|
}
|
|
|
|
test_type_nullability_suffix_star() {
|
|
featureSet = disableNnbd;
|
|
EntityRef typeRef = serializeTypeText('int');
|
|
checkTypeRef(typeRef, 'dart:core', 'int',
|
|
nullabilitySuffix: EntityRefNullabilitySuffix.starOrIrrelevant);
|
|
}
|
|
|
|
test_type_param_codeRange() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class A {} class C<T extends A> {}');
|
|
UnlinkedTypeParam typeParameter = cls.typeParameters[0];
|
|
_assertCodeRange(typeParameter.codeRange, 19, 11);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_constructor() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<D> { D x; C.D(); } class D {}');
|
|
checkParamTypeRef(cls.fields[0].type, 1);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_field_in_extends() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T> extends D<T> { T x; } class D<T> {}');
|
|
checkParamTypeRef(cls.supertype.typeArguments[0], 1);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_field_in_implements() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T> implements D<T> { T x; } class D<T> {}');
|
|
checkParamTypeRef(cls.interfaces[0].typeArguments[0], 1);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_field_in_with() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<T> extends Object with D<T> { T x; } class D<T> {}');
|
|
checkParamTypeRef(cls.mixins[0].typeArguments[0], 1);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_method_parameter() {
|
|
UnlinkedClass cls = serializeClassText('class C<T> { f(int T, T x) {} }');
|
|
checkParamTypeRef(cls.executables[0].parameters[1].type, 1);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_setter() {
|
|
// The code under test should not produce a compile-time error, but it
|
|
// does.
|
|
bool workAroundBug25525 = true;
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<D> { D x; void set D(value) {} } class D {}',
|
|
allowErrors: workAroundBug25525);
|
|
checkParamTypeRef(cls.fields[0].type, 1);
|
|
}
|
|
|
|
test_type_param_not_shadowed_by_typedef_parameter() {
|
|
UnlinkedTypedef typedef =
|
|
serializeTypedefText('typedef void F<T>(int T, T x);');
|
|
checkParamTypeRef(typedef.parameters[1].type, 1);
|
|
}
|
|
|
|
test_type_param_shadowed_by_field() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<D> { D x; int D; } class D {}',
|
|
allowErrors: true);
|
|
checkDynamicTypeRef(cls.fields[0].type);
|
|
}
|
|
|
|
test_type_param_shadowed_by_getter() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<D> { D x; int get D => null; } class D {}',
|
|
allowErrors: true);
|
|
checkDynamicTypeRef(cls.fields[0].type);
|
|
}
|
|
|
|
test_type_param_shadowed_by_method() {
|
|
UnlinkedClass cls = serializeClassText(
|
|
'class C<D> { D x; void D() {} } class D {}',
|
|
allowErrors: true);
|
|
checkDynamicTypeRef(cls.fields[0].type);
|
|
}
|
|
|
|
test_type_param_shadowed_by_type_param() {
|
|
UnlinkedClass cls =
|
|
serializeClassText('class C<T> { T f<T>(T x) => null; }');
|
|
checkParamTypeRef(cls.executables[0].returnType, 1);
|
|
checkParamTypeRef(cls.executables[0].parameters[0].type, 1);
|
|
}
|
|
|
|
test_type_reference_from_part() {
|
|
addNamedSource('/a.dart', 'part of foo; C v;');
|
|
serializeLibraryText('library foo; part "a.dart"; class C {}');
|
|
checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
|
|
null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum,
|
|
linkedSourceUnit: linked.units[1],
|
|
unlinkedSourceUnit: unlinkedUnits[1]);
|
|
}
|
|
|
|
test_type_reference_from_part_withPrefix() {
|
|
addNamedSource('/a.dart', 'class C {}');
|
|
addNamedSource('/p.dart', 'part of foo; a.C v;');
|
|
serializeLibraryText(
|
|
'library foo; import "a.dart"; import "a.dart" as a; part "p.dart";',
|
|
allowErrors: true);
|
|
checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
|
|
absUri('/a.dart'), 'C',
|
|
expectedPrefix: 'a',
|
|
linkedSourceUnit: linked.units[1],
|
|
unlinkedSourceUnit: unlinkedUnits[1]);
|
|
}
|
|
|
|
test_type_reference_to_class_argument() {
|
|
UnlinkedClass cls = serializeClassText('class C<T, U> { T t; U u; }');
|
|
{
|
|
EntityRef typeRef =
|
|
findVariable('t', variables: cls.fields, failIfAbsent: true).type;
|
|
checkParamTypeRef(typeRef, 2);
|
|
}
|
|
{
|
|
EntityRef typeRef =
|
|
findVariable('u', variables: cls.fields, failIfAbsent: true).type;
|
|
checkParamTypeRef(typeRef, 1);
|
|
}
|
|
}
|
|
|
|
test_type_reference_to_import_of_export() {
|
|
addNamedSource('/a.dart', 'library a; export "b.dart";');
|
|
addNamedSource('/b.dart', 'library b; class C {}');
|
|
checkTypeRef(serializeTypeText('C', otherDeclarations: 'import "a.dart";'),
|
|
absUri('/b.dart'), 'C');
|
|
}
|
|
|
|
test_type_reference_to_import_of_export_via_prefix() {
|
|
addNamedSource('/a.dart', 'library a; export "b.dart";');
|
|
addNamedSource('/b.dart', 'library b; class C {}');
|
|
checkTypeRef(
|
|
serializeTypeText('p.C', otherDeclarations: 'import "a.dart" as p;'),
|
|
absUri('/b.dart'),
|
|
'C',
|
|
expectedPrefix: 'p');
|
|
}
|
|
|
|
test_type_reference_to_imported_part() {
|
|
addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
|
|
addNamedSource('/b.dart', 'part of my.lib; class C {}');
|
|
checkTypeRef(
|
|
serializeTypeText('C',
|
|
otherDeclarations: 'library my.lib; import "a.dart";'),
|
|
absUri('/a.dart'),
|
|
'C',
|
|
expectedTargetUnit: 1);
|
|
}
|
|
|
|
test_type_reference_to_imported_part_with_prefix() {
|
|
addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
|
|
addNamedSource('/b.dart', 'part of my.lib; class C {}');
|
|
checkTypeRef(
|
|
serializeTypeText('p.C',
|
|
otherDeclarations: 'library my.lib; import "a.dart" as p;'),
|
|
absUri('/a.dart'),
|
|
'C',
|
|
expectedPrefix: 'p',
|
|
expectedTargetUnit: 1);
|
|
}
|
|
|
|
test_type_reference_to_internal_class() {
|
|
checkTypeRef(
|
|
serializeTypeText('C', otherDeclarations: 'class C {}'), null, 'C');
|
|
}
|
|
|
|
test_type_reference_to_internal_class_alias() {
|
|
checkTypeRef(
|
|
serializeTypeText('C',
|
|
otherDeclarations: 'class C = D with E; class D {} class E {}'),
|
|
null,
|
|
'C');
|
|
}
|
|
|
|
test_type_reference_to_internal_enum() {
|
|
checkTypeRef(serializeTypeText('E', otherDeclarations: 'enum E { value }'),
|
|
null, 'E');
|
|
}
|
|
|
|
test_type_reference_to_local_part() {
|
|
addNamedSource('/a.dart', 'part of my.lib; class C {}');
|
|
checkTypeRef(
|
|
serializeTypeText('C',
|
|
otherDeclarations: 'library my.lib; part "a.dart";'),
|
|
null,
|
|
'C',
|
|
expectedTargetUnit: 1);
|
|
}
|
|
|
|
test_type_reference_to_nonexistent_file_via_prefix() {
|
|
allowMissingFiles = true;
|
|
EntityRef typeRef = serializeTypeText('p.C',
|
|
otherDeclarations: 'import "foo.dart" as p;', allowErrors: true);
|
|
checkUnresolvedTypeRef(typeRef, 'p', 'C');
|
|
}
|
|
|
|
test_type_reference_to_part() {
|
|
addNamedSource('/a.dart', 'part of foo; class C { C(); }');
|
|
serializeLibraryText('library foo; part "a.dart"; C c;');
|
|
checkTypeRef(unlinkedUnits[0].variables.single.type, null, 'C',
|
|
expectedKind: ReferenceKind.classOrEnum, expectedTargetUnit: 1);
|
|
}
|
|
|
|
test_type_reference_to_type_visible_via_multiple_import_prefixes() {
|
|
addNamedSource('/lib1.dart', 'class C');
|
|
addNamedSource('/lib2.dart', 'export "lib1.dart";');
|
|
addNamedSource('/lib3.dart', 'export "lib1.dart";');
|
|
addNamedSource('/lib4.dart', 'export "lib1.dart";');
|
|
serializeLibraryText('''
|
|
import 'lib2.dart';
|
|
import 'lib3.dart' as a;
|
|
import 'lib4.dart' as b;
|
|
C c2;
|
|
a.C c3;
|
|
b.C c4;''');
|
|
// Note: it is important that each reference to class C records the prefix
|
|
// used to find it; otherwise it's possible that relinking might produce an
|
|
// incorrect result after a change to lib2.dart, lib3.dart, or lib4.dart.
|
|
checkTypeRef(findVariable('c2').type, absUri('/lib1.dart'), 'C');
|
|
checkTypeRef(findVariable('c3').type, absUri('/lib1.dart'), 'C',
|
|
expectedPrefix: 'a');
|
|
checkTypeRef(findVariable('c4').type, absUri('/lib1.dart'), 'C',
|
|
expectedPrefix: 'b');
|
|
}
|
|
|
|
test_type_reference_to_typedef() {
|
|
checkTypeRef(serializeTypeText('F', otherDeclarations: 'typedef void F();'),
|
|
null, 'F',
|
|
expectedKind: ReferenceKind.typedef);
|
|
}
|
|
|
|
test_type_unit_counts_unreferenced_units() {
|
|
addNamedSource('/a.dart', 'library a; part "b.dart"; part "c.dart";');
|
|
addNamedSource('/b.dart', 'part of a;');
|
|
addNamedSource('/c.dart', 'part of a; class C {}');
|
|
EntityRef typeRef =
|
|
serializeTypeText('C', otherDeclarations: 'import "a.dart";');
|
|
// The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
|
|
// b.dart. a.dart and b.dart are counted even though nothing is imported
|
|
// from them.
|
|
checkTypeRef(typeRef, absUri('/a.dart'), 'C', expectedTargetUnit: 2);
|
|
}
|
|
|
|
test_type_unresolved() {
|
|
EntityRef typeRef = serializeTypeText('Foo', allowErrors: true);
|
|
checkUnresolvedTypeRef(typeRef, null, 'Foo');
|
|
}
|
|
|
|
test_typedef_codeRange() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F();');
|
|
_assertCodeRange(type.codeRange, 0, 12);
|
|
}
|
|
|
|
test_typedef_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
typedef F();''';
|
|
UnlinkedTypedef typedef = serializeTypedefText(text);
|
|
expect(typedef.documentationComment, isNotNull);
|
|
checkDocumentationComment(typedef.documentationComment, text);
|
|
}
|
|
|
|
test_typedef_genericFunction_reference() {
|
|
EntityRef typeRef = serializeTypeText('F',
|
|
otherDeclarations: 'typedef F<S> = S Function<T>(T x);');
|
|
checkTypeRef(typeRef, null, 'F',
|
|
numTypeParameters: 1,
|
|
expectedKind: ReferenceKind.genericFunctionTypedef);
|
|
}
|
|
|
|
test_typedef_genericFunction_typeNames() {
|
|
UnlinkedTypedef typedef =
|
|
serializeTypedefText('typedef F<S> = S Function(int x, String y);');
|
|
expect(typedef.style, TypedefStyle.genericFunctionType);
|
|
expect(typedef.typeParameters, hasLength(1));
|
|
expect(typedef.typeParameters[0].name, 'S');
|
|
expect(typedef.parameters, isEmpty);
|
|
|
|
EntityRef genericFunction = typedef.returnType;
|
|
expect(genericFunction.entityKind, EntityRefKind.genericFunctionType);
|
|
expect(genericFunction.typeParameters, isEmpty);
|
|
|
|
List<UnlinkedParam> functionParameters = genericFunction.syntheticParams;
|
|
expect(functionParameters, hasLength(2));
|
|
expect(functionParameters[0].name, 'x');
|
|
expect(functionParameters[1].name, 'y');
|
|
checkLinkedTypeRef(functionParameters[0].type, 'dart:core', 'int');
|
|
checkLinkedTypeRef(functionParameters[1].type, 'dart:core', 'String');
|
|
|
|
checkParamTypeRef(genericFunction.syntheticReturnType, 1);
|
|
}
|
|
|
|
test_typedef_genericFunction_typeParameters() {
|
|
UnlinkedTypedef typedef =
|
|
serializeTypedefText('typedef F<S> = S Function<T1, T2>(T1 x, T2 y);');
|
|
expect(typedef.style, TypedefStyle.genericFunctionType);
|
|
expect(typedef.typeParameters, hasLength(1));
|
|
expect(typedef.typeParameters[0].name, 'S');
|
|
expect(typedef.parameters, isEmpty);
|
|
|
|
EntityRef genericFunction = typedef.returnType;
|
|
expect(genericFunction.entityKind, EntityRefKind.genericFunctionType);
|
|
|
|
expect(genericFunction.typeParameters, hasLength(2));
|
|
expect(genericFunction.typeParameters[0].name, 'T1');
|
|
expect(genericFunction.typeParameters[1].name, 'T2');
|
|
|
|
expect(genericFunction.syntheticParams, hasLength(2));
|
|
expect(genericFunction.syntheticParams[0].name, 'x');
|
|
expect(genericFunction.syntheticParams[1].name, 'y');
|
|
checkParamTypeRef(genericFunction.syntheticParams[0].type, 2);
|
|
checkParamTypeRef(genericFunction.syntheticParams[1].type, 1);
|
|
|
|
checkParamTypeRef(genericFunction.syntheticReturnType, 3);
|
|
}
|
|
|
|
test_typedef_name() {
|
|
String text = 'typedef F();';
|
|
UnlinkedTypedef type = serializeTypedefText(text);
|
|
expect(type.name, 'F');
|
|
expect(type.nameOffset, text.indexOf('F'));
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
|
|
expect(
|
|
unlinkedUnits[0].publicNamespace.names[0].kind, ReferenceKind.typedef);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'F');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
|
|
}
|
|
|
|
test_typedef_notSimplyBounded_dependency_via_param_type_new_style_name_included() {
|
|
// F is considered "not simply bounded" because it expands to a type that
|
|
// refers to C, which is not simply bounded.
|
|
UnlinkedTypedef typedef = serializeTypedefText(
|
|
'typedef F = void Function(C c); class C<T extends C<T>> {}');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_typedef_notSimplyBounded_dependency_via_param_type_new_style_name_omitted() {
|
|
// F is considered "not simply bounded" because it expands to a type that
|
|
// refers to C, which is not simply bounded.
|
|
UnlinkedTypedef typedef = serializeTypedefText(
|
|
'typedef F = void Function(C); class C<T extends C<T>> {}');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_typedef_notSimplyBounded_dependency_via_param_type_old_style() {
|
|
// F is considered "not simply bounded" because it expands to a type that
|
|
// refers to C, which is not simply bounded.
|
|
UnlinkedTypedef typedef =
|
|
serializeTypedefText('typedef void F(C c); class C<T extends C<T>> {}');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_typedef_notSimplyBounded_dependency_via_return_type_new_style() {
|
|
// F is considered "not simply bounded" because it expands to a type that
|
|
// refers to C, which is not simply bounded.
|
|
UnlinkedTypedef typedef = serializeTypedefText(
|
|
'typedef F = C Function(); class C<T extends C<T>> {}');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_typedef_notSimplyBounded_dependency_via_return_type_old_style() {
|
|
// F is considered "not simply bounded" because it expands to a type that
|
|
// refers to C, which is not simply bounded.
|
|
UnlinkedTypedef typedef =
|
|
serializeTypedefText('typedef C F(); class C<T extends C<T>> {}');
|
|
expect(typedef.notSimplyBoundedSlot, isNot(0));
|
|
if (!skipFullyLinkedData) {
|
|
expect(linked.units[0].notSimplyBounded,
|
|
contains(typedef.notSimplyBoundedSlot));
|
|
}
|
|
}
|
|
|
|
test_typedef_param_none() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F();');
|
|
expect(type.parameters, isEmpty);
|
|
}
|
|
|
|
test_typedef_param_order() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F(x, y);');
|
|
expect(type.parameters, hasLength(2));
|
|
expect(type.parameters[0].name, 'x');
|
|
expect(type.parameters[1].name, 'y');
|
|
}
|
|
|
|
test_typedef_private() {
|
|
serializeTypedefText('typedef _F();', '_F');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
}
|
|
|
|
test_typedef_reference_generic() {
|
|
EntityRef typeRef =
|
|
serializeTypeText('F', otherDeclarations: 'typedef void F<A, B>();');
|
|
checkTypeRef(typeRef, null, 'F',
|
|
numTypeParameters: 2, expectedKind: ReferenceKind.typedef);
|
|
}
|
|
|
|
test_typedef_reference_generic_imported() {
|
|
addNamedSource('/lib.dart', 'typedef void F<A, B>();');
|
|
EntityRef typeRef =
|
|
serializeTypeText('F', otherDeclarations: 'import "lib.dart";');
|
|
checkTypeRef(typeRef, absUri('/lib.dart'), 'F',
|
|
numTypeParameters: 2, expectedKind: ReferenceKind.typedef);
|
|
}
|
|
|
|
test_typedef_return_type_explicit() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef int F();');
|
|
checkTypeRef(type.returnType, 'dart:core', 'int');
|
|
}
|
|
|
|
test_typedef_type_param_in_parameter() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F<T>(T t);');
|
|
checkParamTypeRef(type.parameters[0].type, 1);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
|
|
}
|
|
|
|
test_typedef_type_param_in_return_type() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef T F<T>();');
|
|
checkParamTypeRef(type.returnType, 1);
|
|
}
|
|
|
|
test_typedef_type_param_none() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F();');
|
|
expect(type.typeParameters, isEmpty);
|
|
}
|
|
|
|
test_typedef_type_param_order() {
|
|
UnlinkedTypedef type = serializeTypedefText('typedef F<T, U>();');
|
|
expect(type.typeParameters, hasLength(2));
|
|
expect(type.typeParameters[0].name, 'T');
|
|
expect(type.typeParameters[1].name, 'U');
|
|
}
|
|
|
|
test_unit_codeRange() {
|
|
serializeLibraryText(' int a = 1; ');
|
|
UnlinkedUnit unit = unlinkedUnits[0];
|
|
_assertCodeRange(unit.codeRange, 0, 14);
|
|
}
|
|
|
|
test_unresolved_export() {
|
|
allowMissingFiles = true;
|
|
serializeLibraryText("export 'foo.dart';", allowErrors: true);
|
|
expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.exports[0].uri, 'foo.dart');
|
|
expect(linked.exportDependencies, hasLength(1));
|
|
checkDependency(linked.exportDependencies[0], absUri('/foo.dart'));
|
|
}
|
|
|
|
test_unresolved_import() {
|
|
allowMissingFiles = true;
|
|
serializeLibraryText("import 'foo.dart';", allowErrors: true);
|
|
expect(unlinkedUnits[0].imports, hasLength(2));
|
|
expect(unlinkedUnits[0].imports[0].uri, 'foo.dart');
|
|
// Note: imports[1] is the implicit import of dart:core.
|
|
expect(unlinkedUnits[0].imports[1].isImplicit, true);
|
|
expect(linked.importDependencies, hasLength(2));
|
|
checkDependency(linked.importDependencies[0], absUri('/foo.dart'));
|
|
}
|
|
|
|
test_unresolved_part() {
|
|
allowMissingFiles = true;
|
|
serializeLibraryText("part 'foo.dart';", allowErrors: true);
|
|
expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
|
|
expect(unlinkedUnits[0].publicNamespace.parts[0], 'foo.dart');
|
|
}
|
|
|
|
test_unresolved_reference_in_multiple_parts() {
|
|
addNamedSource('/a.dart', 'part of foo; int x; Unresolved y;');
|
|
serializeLibraryText('library foo; part "a.dart"; Unresolved z;',
|
|
allowErrors: true);
|
|
// The unresolved types in the defining compilation unit and the part
|
|
// should both work correctly even though they use different reference
|
|
// indices.
|
|
checkUnresolvedTypeRef(
|
|
unlinkedUnits[0].variables[0].type, null, 'Unresolved');
|
|
checkUnresolvedTypeRef(
|
|
unlinkedUnits[1].variables[1].type, null, 'Unresolved',
|
|
linkedSourceUnit: linked.units[1],
|
|
unlinkedSourceUnit: unlinkedUnits[1]);
|
|
}
|
|
|
|
test_unresolved_reference_shared() {
|
|
// Both `x` and `y` use unresolved identifier `C` as their type. Verify
|
|
// that they both use the same unresolved reference.
|
|
serializeLibraryText('C x; C y;', allowErrors: true);
|
|
EntityRef xType = findVariable('x').type;
|
|
EntityRef yType = findVariable('y').type;
|
|
expect(xType.reference, yType.reference);
|
|
}
|
|
|
|
test_unused_type_parameter() {
|
|
if (skipFullyLinkedData) {
|
|
return;
|
|
}
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
class C<T> {
|
|
void f() {}
|
|
}
|
|
C<int> c;
|
|
var v = c.f;
|
|
''');
|
|
EntityRef type =
|
|
getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
|
|
expect(type.typeArguments, hasLength(1));
|
|
checkLinkedTypeRef(type.typeArguments[0], 'dart:core', 'int');
|
|
}
|
|
|
|
test_variable() {
|
|
String text = 'int i;';
|
|
UnlinkedVariable v = serializeVariableText(text, variableName: 'i');
|
|
expect(v.nameOffset, text.indexOf('i;'));
|
|
expect(findExecutable('i'), isNull);
|
|
expect(findExecutable('i='), isNull);
|
|
expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].kind,
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].name, 'i');
|
|
expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
|
|
expect(unlinkedUnits[0].publicNamespace.names[1].kind,
|
|
ReferenceKind.topLevelPropertyAccessor);
|
|
expect(unlinkedUnits[0].publicNamespace.names[1].name, 'i=');
|
|
expect(unlinkedUnits[0].publicNamespace.names[1].numTypeParameters, 0);
|
|
}
|
|
|
|
test_variable_codeRange() {
|
|
serializeLibraryText(' int a = 1, b = 22;');
|
|
List<UnlinkedVariable> variables = unlinkedUnits[0].variables;
|
|
_assertCodeRange(variables[0].codeRange, 1, 9);
|
|
_assertCodeRange(variables[1].codeRange, 12, 6);
|
|
}
|
|
|
|
test_variable_const() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('const int i = 0;', variableName: 'i');
|
|
expect(variable.isConst, isTrue);
|
|
}
|
|
|
|
test_variable_documented() {
|
|
String text = '''
|
|
// Extra comment so doc comment offset != 0
|
|
/**
|
|
* Docs
|
|
*/
|
|
var v;''';
|
|
UnlinkedVariable variable = serializeVariableText(text);
|
|
expect(variable.documentationComment, isNotNull);
|
|
checkDocumentationComment(variable.documentationComment, text);
|
|
}
|
|
|
|
test_variable_explicit_dynamic() {
|
|
UnlinkedVariable variable = serializeVariableText('dynamic v;');
|
|
checkDynamicTypeRef(variable.type);
|
|
}
|
|
|
|
test_variable_implicit_dynamic() {
|
|
UnlinkedVariable variable = serializeVariableText('var v;');
|
|
expect(variable.type, isNull);
|
|
}
|
|
|
|
test_variable_inferred_type_explicit_initialized() {
|
|
UnlinkedVariable v = serializeVariableText('int v = 0;');
|
|
expect(v.inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_variable_inferred_type_implicit_initialized() {
|
|
UnlinkedVariable v = serializeVariableText('var v = 0;');
|
|
checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'int');
|
|
}
|
|
|
|
test_variable_inferred_type_implicit_uninitialized() {
|
|
UnlinkedVariable v = serializeVariableText('var v;');
|
|
expect(v.inferredTypeSlot, 0);
|
|
}
|
|
|
|
test_variable_initializer() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i = 0;', variableName: 'i');
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
|
|
test_variable_initializer_final() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('final int i = 0;', variableName: 'i');
|
|
expect(variable.isFinal, isTrue);
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
|
|
test_variable_initializer_final_untyped() {
|
|
if (skipFullyLinkedData) return;
|
|
UnlinkedVariable variable = serializeVariableText('final v = 0;');
|
|
var typeRef = getTypeRefForSlot(variable.inferredTypeSlot);
|
|
checkLinkedTypeRef(typeRef, 'dart:core', 'int');
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
}
|
|
|
|
test_variable_initializer_literal() {
|
|
UnlinkedVariable variable = serializeVariableText('var v = 42;');
|
|
UnlinkedExecutable initializer = variable.initializer;
|
|
expect(initializer, isNotNull);
|
|
expect(initializer.nameOffset, 8);
|
|
expect(initializer.name, isEmpty);
|
|
expect(initializer.localFunctions, isEmpty);
|
|
}
|
|
|
|
test_variable_initializer_noInitializer() {
|
|
UnlinkedVariable variable = serializeVariableText('var v;');
|
|
expect(variable.initializer, isNull);
|
|
}
|
|
|
|
test_variable_initializer_untyped() {
|
|
if (skipFullyLinkedData) return;
|
|
UnlinkedVariable variable = serializeVariableText('var v = 0;');
|
|
var typeRef = getTypeRefForSlot(variable.inferredTypeSlot);
|
|
checkLinkedTypeRef(typeRef, 'dart:core', 'int');
|
|
if (containsNonConstExprs) {
|
|
expect(variable.initializer.bodyExpr, isNotNull);
|
|
} else {
|
|
expect(variable.initializer.bodyExpr, isNull);
|
|
}
|
|
}
|
|
|
|
test_variable_initializer_withLocals() {
|
|
String text = 'var v = <dynamic, dynamic>{"1": () { f1() {} var v1; }, '
|
|
'"2": () { f2() {} var v2; }};';
|
|
UnlinkedVariable variable = serializeVariableText(text);
|
|
UnlinkedExecutable initializer = variable.initializer;
|
|
expect(initializer, isNotNull);
|
|
expect(initializer.nameOffset, text.indexOf('<dynamic, dynamic>{"1'));
|
|
expect(initializer.name, isEmpty);
|
|
expect(initializer.localFunctions, hasLength(2));
|
|
// closure: () { f1() {} var v1; }
|
|
{
|
|
UnlinkedExecutable closure = initializer.localFunctions[0];
|
|
expect(closure.nameOffset, text.indexOf('() { f1()'));
|
|
expect(closure.name, isEmpty);
|
|
// closure - f1
|
|
expect(closure.localFunctions, hasLength(1));
|
|
expect(closure.localFunctions[0].name, 'f1');
|
|
expect(closure.localFunctions[0].nameOffset, text.indexOf('f1()'));
|
|
}
|
|
// closure: () { f2() {} var v2; }
|
|
{
|
|
UnlinkedExecutable closure = initializer.localFunctions[1];
|
|
expect(closure.nameOffset, text.indexOf('() { f2()'));
|
|
expect(closure.name, isEmpty);
|
|
// closure - f1
|
|
expect(closure.localFunctions, hasLength(1));
|
|
expect(closure.localFunctions[0].name, 'f2');
|
|
expect(closure.localFunctions[0].nameOffset, text.indexOf('f2()'));
|
|
}
|
|
}
|
|
|
|
test_variable_late() {
|
|
featureSet = enableNnbd;
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('late int i;', variableName: 'i');
|
|
expect(variable.isLate, isTrue);
|
|
expect(variable.isStatic, isFalse);
|
|
expect(variable.isConst, isFalse);
|
|
expect(variable.isFinal, isFalse);
|
|
}
|
|
|
|
test_variable_name() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i;', variableName: 'i');
|
|
expect(variable.name, 'i');
|
|
}
|
|
|
|
test_variable_no_flags() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i;', variableName: 'i');
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isFalse);
|
|
expect(variable.isConst, isFalse);
|
|
expect(variable.isFinal, isFalse);
|
|
}
|
|
|
|
test_variable_non_const() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i = 0;', variableName: 'i');
|
|
expect(variable.isConst, isFalse);
|
|
}
|
|
|
|
test_variable_non_final() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i;', variableName: 'i');
|
|
expect(variable.isFinal, isFalse);
|
|
}
|
|
|
|
test_variable_non_static() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { int i; }').fields[0];
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isFalse);
|
|
}
|
|
|
|
test_variable_non_static_top_level() {
|
|
// Top level variables are considered non-static.
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i;', variableName: 'i');
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isFalse);
|
|
}
|
|
|
|
test_variable_private() {
|
|
serializeVariableText('int _i;', variableName: '_i');
|
|
expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
|
|
}
|
|
|
|
test_variable_static() {
|
|
UnlinkedVariable variable =
|
|
serializeClassText('class C { static int i; }').fields[0];
|
|
expect(variable.isLate, isFalse);
|
|
expect(variable.isStatic, isTrue);
|
|
}
|
|
|
|
test_variable_type() {
|
|
UnlinkedVariable variable =
|
|
serializeVariableText('int i;', variableName: 'i');
|
|
checkTypeRef(variable.type, 'dart:core', 'int');
|
|
}
|
|
|
|
/// Assert that serializing the given [expr] of form `(a op= 1 + 2) + 3`
|
|
/// uses the given [expectedAssignOperator].
|
|
void _assertAssignmentOperator(
|
|
String expr, UnlinkedExprAssignOperator expectedAssignOperator) {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
int a = 0;
|
|
final v = $expr;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, expr,
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.add,
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.add,
|
|
],
|
|
assignmentOperators: [expectedAssignOperator],
|
|
ints: [1, 2, 3],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
void _assertCodeRange(CodeRange codeRange, int offset, int length) {
|
|
expect(codeRange, isNotNull);
|
|
expect(codeRange.offset, offset);
|
|
expect(codeRange.length, length);
|
|
}
|
|
|
|
void _assertParameterVisible(
|
|
String code, UnlinkedParam p, String visibleBegin, String visibleEnd) {
|
|
int expectedVisibleOffset = code.indexOf(visibleBegin);
|
|
int expectedVisibleLength =
|
|
code.indexOf(visibleEnd) - expectedVisibleOffset + 1;
|
|
expect(p.visibleOffset, expectedVisibleOffset);
|
|
expect(p.visibleLength, expectedVisibleLength);
|
|
}
|
|
|
|
void _assertParameterZeroVisibleRange(UnlinkedParam p) {
|
|
expect(p.visibleOffset, isZero);
|
|
expect(p.visibleLength, isZero);
|
|
}
|
|
|
|
/// Assert that the [expr] of the form `++a + 2` is serialized with the
|
|
/// [expectedAssignmentOperator].
|
|
void _assertRefPrefixPostfixIncrementDecrement(
|
|
String expr, UnlinkedExprAssignOperator expectedAssignmentOperator) {
|
|
UnlinkedVariable variable = serializeVariableText('''
|
|
int a = 0;
|
|
final v = $expr;
|
|
''');
|
|
assertUnlinkedConst(variable.initializer.bodyExpr, expr,
|
|
isValidConst: false,
|
|
operators: [
|
|
UnlinkedExprOperation.assignToRef,
|
|
UnlinkedExprOperation.pushInt,
|
|
UnlinkedExprOperation.add,
|
|
],
|
|
assignmentOperators: [expectedAssignmentOperator],
|
|
ints: [2],
|
|
strings: [],
|
|
referenceValidators: [
|
|
(EntityRef r) => checkTypeRef(r, null, 'a',
|
|
expectedKind: ReferenceKind.topLevelPropertyAccessor)
|
|
],
|
|
forTypeInferenceOnly: true);
|
|
}
|
|
|
|
String _normalizeTokenString(String tokenString) {
|
|
// Note: to normalize the token string it's not sufficient to tokenize it
|
|
// and then pass the tokens to `tokensToString`; we also need to parse it
|
|
// because parsing modifies the token stream (splitting up `[]`, `>>`, and
|
|
// `>>>` tokens when circumstances warrant).
|
|
//
|
|
// We wrap the expression in "f() async => ...;" to ensure that the await
|
|
// keyword is properly parsed.
|
|
var sourceText = 'f() async => $tokenString;';
|
|
var errorListener = AnalysisErrorListener.NULL_LISTENER;
|
|
var reader = new CharSequenceReader(sourceText);
|
|
var stringSource = new StringSource(sourceText, null);
|
|
var scanner = new Scanner(stringSource, reader, errorListener)
|
|
..configureFeatures(featureSet);
|
|
var startToken = scanner.tokenize();
|
|
var parser =
|
|
new Parser(stringSource, errorListener, featureSet: featureSet);
|
|
var compilationUnit = parser.parseCompilationUnit(startToken);
|
|
var f = compilationUnit.declarations[0] as FunctionDeclaration;
|
|
var body = f.functionExpression.body as ExpressionFunctionBody;
|
|
var expression = body.expression;
|
|
return tokensToString(expression.beginToken, expression.endToken);
|
|
}
|
|
}
|
|
|
|
/// Description of expectations for a prelinked prefix reference.
|
|
class _PrefixExpectation {
|
|
final ReferenceKind kind;
|
|
final String name;
|
|
final String absoluteUri;
|
|
final int numTypeParameters;
|
|
|
|
_PrefixExpectation(this.kind, this.name,
|
|
{this.absoluteUri, this.numTypeParameters: 0});
|
|
}
|