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