| // 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/ast/ast.dart'; |
| import 'package:analyzer/error/listener.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments.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) { |
| CharacterReader reader = new CharSequenceReader(text); |
| Scanner scanner = |
| new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER); |
| Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER); |
| CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize()); |
| UnlinkedPublicNamespace namespace = new UnlinkedPublicNamespace.fromBuffer( |
| public_namespace.computePublicNamespace(unit).toBuffer()); |
| return namespace; |
| } |
| |
| /** |
| * Type of a function that validates an [EntityRef]. |
| */ |
| typedef void _EntityRefValidator(EntityRef entityRef); |
| |
| /// 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]; |
| |
| /** |
| * 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}) { |
| linkedSourceUnit ??= definingUnit; |
| expect(typeRef, new TypeMatcher<EntityRef>()); |
| expect(typeRef.paramReference, 0); |
| int index = typeRef.reference; |
| expect(typeRef.typeArguments, hasLength(numTypeArguments)); |
| |
| if (entityKind == EntityRefKind.genericFunctionType) { |
| // [GenericFunctionType]s don't have references to check. |
| return; |
| } |
| |
| UnlinkedReference reference = checkReferenceIndex( |
| index, absoluteUri, expectedName, |
| expectedKind: expectedKind, |
| expectedTargetUnit: expectedTargetUnit, |
| linkedSourceUnit: linkedSourceUnit, |
| unlinkedSourceUnit: unlinkedSourceUnit, |
| numTypeParameters: numTypeParameters, |
| unresolvedHasName: unresolvedHasName); |
| expect(reference, isNotNull, |
| reason: 'Unlinked type refs must refer to an explicit reference'); |
| if (expectedPrefix != null) { |
| checkPrefix(reference.prefixReference, expectedPrefix); |
| } else if (prefixExpectations != null) { |
| for (_PrefixExpectation expectation in prefixExpectations) { |
| expect(reference.prefixReference, isNot(0)); |
| reference = checkReferenceIndex(reference.prefixReference, |
| expectation.absoluteUri, expectation.name, |
| expectedKind: expectation.kind, |
| expectedTargetUnit: expectedTargetUnit, |
| linkedSourceUnit: linkedSourceUnit, |
| unlinkedSourceUnit: unlinkedSourceUnit, |
| numTypeParameters: expectation.numTypeParameters); |
| } |
| expect(reference.prefixReference, 0); |
| } else { |
| expect(reference.prefixReference, 0); |
| } |
| } |
| |
| /** |
| * Verify that the given [typeRef] represents a reference to an unresolved |
| * type. |
| */ |
| void checkUnresolvedTypeRef( |
| EntityRef typeRef, String expectedPrefix, String expectedName, |
| {LinkedUnit linkedSourceUnit, UnlinkedUnit unlinkedSourceUnit}) { |
| // When serializing from the element model, unresolved type refs lose their |
| // name. |
| checkTypeRef(typeRef, null, expectedName, |
| expectedPrefix: expectedPrefix, |
| expectedKind: ReferenceKind.unresolved, |
| linkedSourceUnit: linkedSourceUnit, |
| unlinkedSourceUnit: unlinkedSourceUnit); |
| } |
| |
| /** |
| * Verify that the given [typeRef] represents the type `void`. |
| */ |
| void checkVoidTypeRef(EntityRef typeRef) { |
| checkTypeRef(typeRef, null, 'void'); |
| } |
| |
| fail_invalid_prefix_dynamic() { |
| // if (checkAstDerivedData) { |
| // // TODO(paulberry): get this to work properly. |
| // return; |
| // } |
| var t = serializeTypeText('dynamic.T', allowErrors: true); |
| checkUnresolvedTypeRef(t, 'dynamic', 'T'); |
| } |
| |
| fail_invalid_prefix_type_parameter() { |
| // if (checkAstDerivedData) { |
| // // TODO(paulberry): get this to work properly. |
| // return; |
| // } |
| checkUnresolvedTypeRef( |
| serializeClassText('class C<T> { T.U x; }', allowErrors: true) |
| .fields[0] |
| .type, |
| 'T', |
| 'U'); |
| } |
| |
| fail_invalid_prefix_void() { |
| // if (checkAstDerivedData) { |
| // // TODO(paulberry): get this to work properly. |
| // return; |
| // } |
| checkUnresolvedTypeRef( |
| serializeTypeText('void.T', allowErrors: true), 'void', 'T'); |
| } |
| |
| /** |
| * Find the class with the given [className] in the summary, and return its |
| * [UnlinkedClass] data structure. If [unit] is not given, the class is |
| * looked for in the defining compilation unit. |
| */ |
| UnlinkedClass findClass(String className, |
| {bool failIfAbsent: false, UnlinkedUnit unit}) { |
| unit ??= unlinkedUnits[0]; |
| UnlinkedClass result; |
| for (UnlinkedClass cls in unit.classes) { |
| if (cls.name == className) { |
| if (result != null) { |
| fail('Duplicate class $className'); |
| } |
| result = cls; |
| } |
| } |
| if (result == null && failIfAbsent) { |
| fail('Class $className not found in serialized output'); |
| } |
| return result; |
| } |
| |
| /** |
| * Find the enum with the given [enumName] in the summary, and return its |
| * [UnlinkedEnum] data structure. If [unit] is not given, the enum is looked |
| * for in the defining compilation unit. |
| */ |
| UnlinkedEnum findEnum(String enumName, |
| {bool failIfAbsent: false, UnlinkedUnit unit}) { |
| unit ??= unlinkedUnits[0]; |
| UnlinkedEnum result; |
| for (UnlinkedEnum e in unit.enums) { |
| if (e.name == enumName) { |
| if (result != null) { |
| fail('Duplicate enum $enumName'); |
| } |
| result = e; |
| } |
| } |
| if (result == null && failIfAbsent) { |
| fail('Enum $enumName not found in serialized output'); |
| } |
| return result; |
| } |
| |
| /** |
| * Find the executable with the given [executableName] in the summary, and |
| * return its [UnlinkedExecutable] data structure. If [executables] is not |
| * given, then the executable is searched for in the defining compilation |
| * unit. |
| */ |
| UnlinkedExecutable findExecutable(String executableName, |
| {List<UnlinkedExecutable> executables, bool failIfAbsent: false}) { |
| executables ??= unlinkedUnits[0].executables; |
| UnlinkedExecutable result; |
| for (UnlinkedExecutable executable in executables) { |
| if (executable.name == executableName) { |
| if (result != null) { |
| fail('Duplicate executable $executableName'); |
| } |
| result = executable; |
| } |
| } |
| if (result == null && failIfAbsent) { |
| fail('Executable $executableName not found in serialized output'); |
| } |
| return result; |
| } |
| |
| /** |
| * Find the 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}) { |
| serializeLibraryText(text, allowErrors: allowErrors); |
| return findVariable(variableName, failIfAbsent: true); |
| } |
| |
| test_apiSignature() { |
| List<int> signature1; |
| List<int> signature2; |
| List<int> signature3; |
| { |
| serializeLibraryText('class A {}'); |
| signature1 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText('class A { }'); |
| signature2 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText('class B {}'); |
| signature3 = unlinkedUnits[0].apiSignature; |
| } |
| expect(signature2, signature1); |
| expect(signature3, isNot(signature1)); |
| } |
| |
| test_apiSignature_excludeBody_constructor() { |
| List<int> signature1; |
| List<int> signature2; |
| List<int> signature3; |
| { |
| serializeLibraryText(r''' |
| class A { |
| A() { |
| } |
| } |
| '''); |
| signature1 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText(r''' |
| class A { |
| A() { |
| int v1; |
| f() { |
| double v2; |
| } |
| } |
| } |
| '''); |
| signature2 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText(r''' |
| class A { |
| A(int p) { |
| } |
| } |
| '''); |
| } |
| expect(signature2, signature1); |
| expect(signature3, isNot(signature1)); |
| } |
| |
| test_apiSignature_excludeBody_method() { |
| List<int> signature1; |
| List<int> signature2; |
| List<int> signature3; |
| { |
| serializeLibraryText(r''' |
| class A { |
| m() { |
| } |
| } |
| '''); |
| signature1 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText(r''' |
| class A { |
| m() { |
| int v1; |
| f() { |
| double v2; |
| } |
| } |
| } |
| '''); |
| signature2 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText(r''' |
| class A { |
| m(p) { |
| } |
| } |
| '''); |
| } |
| expect(signature2, signature1); |
| expect(signature3, isNot(signature1)); |
| } |
| |
| test_apiSignature_excludeBody_topLevelFunction() { |
| List<int> signature1; |
| List<int> signature2; |
| List<int> signature3; |
| { |
| serializeLibraryText('main() {}'); |
| signature1 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText(r''' |
| main() { |
| int v1 = 1; |
| f() { |
| int v2 = 2; |
| } |
| } |
| '''); |
| signature2 = unlinkedUnits[0].apiSignature; |
| } |
| { |
| serializeLibraryText('main(p) {}'); |
| signature3 = unlinkedUnits[0].apiSignature; |
| } |
| expect(signature2, signature1); |
| expect(signature3, isNot(signature1)); |
| } |
| |
| test_bottom_reference_shared() { |
| if (skipFullyLinkedData) { |
| return; |
| } |
| // The synthetic executables for both `x` and `y` have type `() => `Bottom`. |
| // Verify that they both use the same reference to `Bottom`. |
| serializeLibraryText('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_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_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_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_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.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.makeTypedMap |
| ], |
| ints: [ |
| 11, |
| 22, |
| 33, |
| 3 |
| ], |
| strings: [ |
| 'aaa', |
| 'bbb', |
| 'ccc' |
| ], |
| referenceValidators: [ |
| (EntityRef r) => checkTypeRef(r, 'dart:core', 'int', |
| expectedKind: ReferenceKind.classOrEnum), |
| (EntityRef r) => checkTypeRef(r, 'dart:core', 'String', |
| expectedKind: ReferenceKind.classOrEnum) |
| ]); |
| } |
| |
| test_constExpr_makeTypedMap_dynamic() { |
| UnlinkedVariable variable = serializeVariableText( |
| 'const v = const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"};'); |
| assertUnlinkedConst(variable.initializer.bodyExpr, |
| 'const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"}', |
| operators: [ |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.makeTypedMap |
| ], |
| ints: [ |
| 11, |
| 22, |
| 33, |
| 3 |
| ], |
| strings: [ |
| 'aaa', |
| 'bbb', |
| 'ccc' |
| ], |
| referenceValidators: [ |
| (EntityRef r) => checkDynamicTypeRef(r), |
| (EntityRef r) => checkDynamicTypeRef(r) |
| ]); |
| } |
| |
| test_constExpr_makeTypedSet() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| 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() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| 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() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| 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() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| 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.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.makeUntypedMap |
| ], |
| ints: [ |
| 11, |
| 22, |
| 33, |
| 3 |
| ], |
| strings: [ |
| 'aaa', |
| 'bbb', |
| 'ccc' |
| ]); |
| } |
| |
| test_constExpr_makeUntypedSet() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| 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.makeUntypedSet |
| ], |
| ints: [11, 22, 33, 3], |
| ); |
| } |
| |
| 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_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.positional); |
| 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.named); |
| 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.named); |
| 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.positional); |
| 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.positional); |
| 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.required); |
| } |
| |
| 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.positional); |
| 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.positional); |
| 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.named); |
| 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.named); |
| 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.positional); |
| 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.positional); |
| 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.required); |
| 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_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.makeTypedMap], |
| 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() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| 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.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushString, |
| UnlinkedExprOperation.makeUntypedMap |
| ], |
| ints: [11, 22, 33, 3], |
| strings: ['aaa', 'bbb', 'ccc'], |
| forTypeInferenceOnly: true); |
| } |
| |
| test_expr_makeUntypedSet() { |
| experimentStatus = ExperimentStatus(set_literals: true); |
| UnlinkedVariable variable = serializeVariableText('var v = {11, 22, 33};'); |
| assertUnlinkedConst(variable.initializer.bodyExpr, '{11, 22, 33}', |
| operators: [ |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.pushInt, |
| UnlinkedExprOperation.makeUntypedSet |
| ], |
| ints: [11, 22, 33, 3], |
| forTypeInferenceOnly: true); |
| } |
| |
| 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.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_static() { |
| UnlinkedVariable variable = |
| serializeClassText('class C { static int i; }').fields[0]; |
| 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.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_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_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, '*bottom*', |
| 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, '*bottom*'); |
| } |
| |
| 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_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_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.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.isStatic, isFalse); |
| } |
| |
| test_variable_non_static_top_level() { |
| // Top level variables are considered non-static. |
| UnlinkedVariable variable = |
| serializeVariableText('int i;', variableName: 'i'); |
| 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.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); |
| var startToken = scanner.tokenize(); |
| var parser = new Parser(stringSource, errorListener) |
| ..enableNonNullable = experimentStatus.non_nullable; |
| 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}); |
| } |