| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:analyzer/src/binary/binary_reader.dart'; | |
| import 'package:analyzer/src/binary/binary_writer.dart'; | |
| import 'package:analyzer/src/summary2/reference.dart'; | |
| import 'package:test/test.dart'; | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(ReferenceTest); | |
| }); | |
| } | |
| @reflectiveTest | |
| class ReferenceTest { | |
| void test_builtIn_dartCore() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('dart:core')); | |
| var dynamic0 = library.dynamicRef; | |
| var dynamic1 = library.dynamicRef; | |
| var never_ = library.neverRef; | |
| expect(dynamic1, same(dynamic0)); | |
| expect(dynamic0.library, same(library)); | |
| expect(dynamic0.enclosingReference, same(library)); | |
| expect(dynamic0.debugString(), 'dart:core::dynamic'); | |
| expect(never_.library, same(library)); | |
| expect(never_.debugString(), 'dart:core::Never'); | |
| expect(library.children, [dynamic0, never_]); | |
| } | |
| void test_debugString() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('package:test/a.dart')); | |
| var classReference = library.declareClass('A'); | |
| var methodReference = classReference.declareMethod('foo'); | |
| expect(root.debugString(), 'root'); | |
| expect(library.debugString(), 'package:test/a.dart'); | |
| expect(classReference.debugString(), 'package:test/a.dart::@class::A'); | |
| expect( | |
| methodReference.debugString(), | |
| 'package:test/a.dart::@class::A::@method::foo', | |
| ); | |
| expect( | |
| methodReference.debugString(formatLibraryUri: (_) => '<library>'), | |
| '<library>::@class::A::@method::foo', | |
| ); | |
| expect( | |
| methodReference.toString(), | |
| 'package:test/a.dart::@class::A::@method::foo', | |
| ); | |
| } | |
| void test_declare_duplicateKey() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('package:test/a.dart')); | |
| library.declareClass('A'); | |
| library.declareTopLevelFunction('f'); | |
| expect(() => library.declareClass('A'), throwsStateError); | |
| expect(() => library.declareTopLevelFunction('f'), throwsStateError); | |
| var classReference = library.getOrCreateClass('A'); | |
| classReference.declareConstructor('new'); | |
| classReference.declareMethod('m'); | |
| expect(() => classReference.declareConstructor('new'), throwsStateError); | |
| expect(() => classReference.declareMethod('m'), throwsStateError); | |
| } | |
| void test_direct_memberReferences() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('package:test/a.dart')); | |
| var classReference = library.declareClass('A'); | |
| const constructorName = 'new'; | |
| const fieldName = 'field'; | |
| const propertyName = 'property'; | |
| const methodName = 'method'; | |
| var methodReference = classReference.declareMethod(methodName); | |
| var setterReference = classReference.declareSetter(propertyName); | |
| var constructorReference = classReference.declareConstructor( | |
| constructorName, | |
| ); | |
| var getterReference = classReference.declareGetter(propertyName); | |
| var fieldReference = classReference.declareField(fieldName); | |
| expect( | |
| classReference.getOrCreateConstructor(constructorName), | |
| same(constructorReference), | |
| ); | |
| expect(classReference.getOrCreateField(fieldName), same(fieldReference)); | |
| expect( | |
| classReference.getOrCreateGetter(propertyName), | |
| same(getterReference), | |
| ); | |
| expect( | |
| classReference.getOrCreateSetter(propertyName), | |
| same(setterReference), | |
| ); | |
| expect(classReference.getOrCreateMethod(methodName), same(methodReference)); | |
| expect(classReference.children, [ | |
| constructorReference, | |
| fieldReference, | |
| getterReference, | |
| setterReference, | |
| methodReference, | |
| ]); | |
| for (var reference in classReference.children) { | |
| expect(reference, isA<MemberReference>()); | |
| expect(reference.enclosingReference, same(classReference)); | |
| } | |
| } | |
| void test_direct_topLevelReferences() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('package:test/a.dart')); | |
| const propertyName = 'property'; | |
| var topLevelVariable = library.declareTopLevelVariable('v'); | |
| var setter = library.declareSetter(propertyName); | |
| var getter = library.declareGetter(propertyName); | |
| var topLevelFunction = library.declareTopLevelFunction('f'); | |
| var typeAlias = library.declareTypeAlias('T'); | |
| var mixin = library.declareMixin('M'); | |
| var extensionType = library.declareExtensionType('ET'); | |
| var extension = library.declareExtension('E'); | |
| var enum_ = library.declareEnum('Enum'); | |
| var class_ = library.declareClass('A'); | |
| expect(library.getOrCreateClass('A'), same(class_)); | |
| expect(library.getOrCreateEnum('Enum'), same(enum_)); | |
| expect(library.getOrCreateExtension('E'), same(extension)); | |
| expect(library.getOrCreateExtensionType('ET'), same(extensionType)); | |
| expect(library.getOrCreateMixin('M'), same(mixin)); | |
| expect(library.getOrCreateTypeAlias('T'), same(typeAlias)); | |
| expect(library.getOrCreateTopLevelFunction('f'), same(topLevelFunction)); | |
| expect(library.getOrCreateGetter(propertyName), same(getter)); | |
| expect(library.getOrCreateSetter(propertyName), same(setter)); | |
| expect(library.getOrCreateTopLevelVariable('v'), same(topLevelVariable)); | |
| expect(library.children, [ | |
| class_, | |
| enum_, | |
| extension, | |
| extensionType, | |
| mixin, | |
| typeAlias, | |
| topLevelFunction, | |
| getter, | |
| setter, | |
| topLevelVariable, | |
| ]); | |
| for (var reference in [class_, enum_, extension, extensionType, mixin]) { | |
| expect(reference, isA<MemberContainerReference>()); | |
| expect(reference.enclosingReference, same(library)); | |
| } | |
| for (var reference in [ | |
| typeAlias, | |
| topLevelFunction, | |
| getter, | |
| setter, | |
| topLevelVariable, | |
| ]) { | |
| expect(reference, isA<LeafTopLevelReference>()); | |
| expect(reference.enclosingReference, same(library)); | |
| } | |
| } | |
| void test_libraryReferenceBuilder_memberKeys() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('package:test/a.dart')); | |
| var builder = LibraryReferenceBuilder(library); | |
| var classA = builder.declareClass('A'); | |
| var classB = builder.declareClass('B'); | |
| var method = builder.declareMemberMethod(container: classA, name: 'foo'); | |
| var duplicateMethod = builder.declareMemberMethod( | |
| container: classA, | |
| name: 'foo', | |
| ); | |
| var getter = builder.declareMemberGetter(container: classA, name: 'foo'); | |
| var methodInClassB = builder.declareMemberMethod( | |
| container: classB, | |
| name: 'foo', | |
| ); | |
| var unnamedField = builder.declareMemberField( | |
| container: classA, | |
| name: null, | |
| ); | |
| var unnamedGetter = builder.declareMemberGetter( | |
| container: classA, | |
| name: null, | |
| ); | |
| expect(classA.getOrCreateMethod('foo'), same(method)); | |
| expect(classA.getOrCreateMethod('foo#1'), same(duplicateMethod)); | |
| expect(classA.getOrCreateGetter('foo'), same(getter)); | |
| expect(classB.getOrCreateMethod('foo'), same(methodInClassB)); | |
| expect(classA.getOrCreateField('#0'), same(unnamedField)); | |
| expect(classA.getOrCreateGetter('#1'), same(unnamedGetter)); | |
| } | |
| void test_libraryReferenceBuilder_topLevelKeys() { | |
| var root = RootReference(); | |
| var library = root.getOrCreateLibrary(Uri.parse('package:test/a.dart')); | |
| var builder = LibraryReferenceBuilder(library); | |
| var classA = builder.declareClass('A'); | |
| var duplicateClassA = builder.declareClass('A'); | |
| var enumA = builder.declareEnum('A'); | |
| var unnamedGetter = builder.declareGetter(null); | |
| var unnamedSetter = builder.declareSetter(null); | |
| var getterX = builder.declareGetter('x'); | |
| var duplicateGetterX = builder.declareGetter('x'); | |
| var setterX = builder.declareSetter('x'); | |
| expect(library.getOrCreateClass('A'), same(classA)); | |
| expect(library.getOrCreateClass('A#1'), same(duplicateClassA)); | |
| expect(library.getOrCreateEnum('A'), same(enumA)); | |
| expect(library.getOrCreateGetter('#0'), same(unnamedGetter)); | |
| expect(library.getOrCreateSetter('#1'), same(unnamedSetter)); | |
| expect(library.getOrCreateGetter('x'), same(getterX)); | |
| expect(library.getOrCreateGetter('x#1'), same(duplicateGetterX)); | |
| expect(library.getOrCreateSetter('x'), same(setterX)); | |
| } | |
| void test_referenceTable_roundTrip() { | |
| var writeRoot = RootReference(); | |
| var packageUri = Uri.parse('package:test/a.dart'); | |
| var packageLibrary = writeRoot.getOrCreateLibrary(packageUri); | |
| var classReference = packageLibrary.declareClass('A'); | |
| var functionReference = packageLibrary.declareTopLevelFunction('f'); | |
| var methodReference = classReference.declareMethod('m'); | |
| var dartCore = writeRoot.getOrCreateLibrary(Uri.parse('dart:core')); | |
| var dynamicReference = dartCore.dynamicRef; | |
| var sink = BinaryWriter(); | |
| var tableWriter = ReferenceTableWriter(); | |
| tableWriter.writeReference(sink, writeRoot); | |
| tableWriter.writeReference(sink, packageLibrary); | |
| tableWriter.writeReference(sink, classReference); | |
| tableWriter.writeReference(sink, functionReference); | |
| tableWriter.writeReference(sink, methodReference); | |
| tableWriter.writeReference(sink, dynamicReference); | |
| tableWriter.writeReference(sink, classReference); | |
| var tableOffset = sink.offset; | |
| tableWriter.write(sink); | |
| sink.writeTableTrailer(); | |
| var reader = BinaryReader(sink.takeBytes()); | |
| reader.initFromTableTrailer(); | |
| var readRoot = RootReference(); | |
| reader.offset = tableOffset; | |
| var tableReader = ReferenceTableReader( | |
| reader: reader, | |
| rootReference: readRoot, | |
| ); | |
| reader.offset = 0; | |
| expect(tableReader.readReference(reader), same(readRoot)); | |
| var readPackageLibrary = tableReader.readLibraryReference(reader); | |
| expect(readPackageLibrary.uriString, '$packageUri'); | |
| expect(readRoot.getOrCreateLibrary(packageUri), same(readPackageLibrary)); | |
| var readClass = tableReader.readMemberContainerReference(reader); | |
| expect(readClass, same(readPackageLibrary.getOrCreateClass('A'))); | |
| var readFunction = tableReader.readTopLevelReference(reader); | |
| expect( | |
| readFunction, | |
| same(readPackageLibrary.getOrCreateTopLevelFunction('f')), | |
| ); | |
| var readMethod = tableReader.readMemberReference(reader); | |
| expect(readMethod, same(readClass.getOrCreateMethod('m'))); | |
| var readDynamic = tableReader.readExportableReference(reader); | |
| expect( | |
| readDynamic, | |
| same(readRoot.getOrCreateLibrary(Uri.parse('dart:core')).dynamicRef), | |
| ); | |
| expect(tableReader.readDeclarationReference(reader), same(readClass)); | |
| expect(readPackageLibrary.children, [readClass, readFunction]); | |
| } | |
| void test_root_libraries() { | |
| var root = RootReference(); | |
| var a = Uri.parse('package:test/a.dart'); | |
| var b = Uri.parse('package:test/b.dart'); | |
| expect(root.children, isEmpty); | |
| expect(root.libraryIfExists(a), isNull); | |
| expect(root.removeLibrary(a), isNull); | |
| var libraryA = root.getOrCreateLibrary(a); | |
| expect(libraryA.uriString, '$a'); | |
| expect(libraryA.uri, a); | |
| expect(libraryA.enclosingReference, isNull); | |
| expect(root.getOrCreateLibrary(a), same(libraryA)); | |
| expect(root.libraryIfExists(a), same(libraryA)); | |
| expect(root.children, [libraryA]); | |
| var libraryB = root.getOrCreateLibrary(b); | |
| expect(root.children, [libraryA, libraryB]); | |
| expect(root.removeLibrary(a), same(libraryA)); | |
| expect(root.children, [libraryB]); | |
| expect(root.removeLibrary(a), isNull); | |
| } | |
| } |