diff --git a/pkg/analyzer/lib/src/fine/manifest_ast.dart b/pkg/analyzer/lib/src/fine/manifest_ast.dart index c1ab5c28af1..8c7af73b54c 100644 --- a/pkg/analyzer/lib/src/fine/manifest_ast.dart +++ b/pkg/analyzer/lib/src/fine/manifest_ast.dart @@ -2,40 +2,136 @@ // 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 'dart:typed_data'; + import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/src/dart/ast/ast.dart'; import 'package:analyzer/src/fine/manifest_context.dart'; import 'package:analyzer/src/summary2/data_reader.dart'; import 'package:analyzer/src/summary2/data_writer.dart'; +import 'package:analyzer/src/utilities/extensions/collection.dart'; +import 'package:collection/collection.dart'; -sealed class ManifestNode { - bool match(MatchContext context, AstNode node); +/// Enough information to decide if the node is the same. +/// +/// We don't store ASTs, instead we rely on the fact that the same tokens +/// are parsed into the same AST (when the same language features, which is +/// ensured outside). +/// +/// In addition we record all referenced elements. +class ManifestNode { + /// The concatenated lexemes of all tokens. + final String tokenBuffer; - void write(BufferedSink sink); + /// The length of each token in [tokenBuffer]. + final Uint32List tokenLengthList; - static ManifestNode encode(EncodeContext context, AstNode node) { - switch (node) { - case Annotation(): - return ManifestNodeAnnotation.encode(context, node); - case IntegerLiteral(): - return ManifestNodeIntegerLiteral.encode(node); - case SimpleIdentifier(): - return ManifestNodeSimpleIdentifier.encode(context, node); - default: - throw UnimplementedError('(${node.runtimeType}) $node'); + /// All unique elements referenced by this node. + final List elements; + + /// For each property in the AST structure summarized by this manifest that + /// might point to an element, `0` if the element pointer is `null`; otherwise + /// one plus the index of the associated manifest element in [elements]. + /// + /// The order of this list reflects the AST structure, according to the + /// behavior of [_ElementCollector]. + final Uint32List elementIndexList; + + factory ManifestNode.encode(EncodeContext context, AstNode node) { + var buffer = StringBuffer(); + var lengthList = []; + + var token = node.beginToken; + while (true) { + buffer.write(token.lexeme); + lengthList.add(token.lexeme.length); + if (token == node.endToken) { + break; + } + token = token.next ?? (throw StateError('endToken not found')); } + + var collector = _ElementCollector(); + node.accept(collector); + + return ManifestNode._( + tokenBuffer: buffer.toString(), + tokenLengthList: Uint32List.fromList(lengthList), + elements: collector.map.keys + .map((element) => ManifestElement.encode(context, element)) + .toFixedList(), + elementIndexList: Uint32List.fromList(collector.elementIndexList), + ); } - static ManifestNode read(SummaryDataReader reader) { - var kind = reader.readEnum(_ManifestNodeKind.values); - switch (kind) { - case _ManifestNodeKind.annotation: - return ManifestNodeAnnotation.read(reader); - case _ManifestNodeKind.integerLiteral: - return ManifestNodeIntegerLiteral.read(reader); - case _ManifestNodeKind.simpleIdentifier: - return ManifestNodeSimpleIdentifier.read(reader); + factory ManifestNode.read(SummaryDataReader reader) { + return ManifestNode._( + tokenBuffer: reader.readStringUtf8(), + tokenLengthList: reader.readUInt30List(), + elements: ManifestElement.readList(reader), + elementIndexList: reader.readUInt30List(), + ); + } + + ManifestNode._({ + required this.tokenBuffer, + required this.tokenLengthList, + required this.elements, + required this.elementIndexList, + }); + + bool match(MatchContext context, AstNode node) { + var tokenIndex = 0; + var tokenOffset = 0; + var token = node.beginToken; + while (true) { + var tokenLength = token.lexeme.length; + if (tokenLengthList[tokenIndex++] != tokenLength) { + return false; + } + + if (!tokenBuffer.startsWith(token.lexeme, tokenOffset)) { + return false; + } + tokenOffset += tokenLength; + + if (token == node.endToken) { + break; + } + token = token.next ?? (throw StateError('endToken not found')); } + + var collector = _ElementCollector(); + node.accept(collector); + + // Must reference the same elements. + if (collector.map.length != elements.length) { + return false; + } + for (var (index, element) in collector.map.keys.indexed) { + if (!elements[index].match(context, element)) { + return false; + } + } + + // Must reference elements in the same order. + if (!const ListEquality().equals( + collector.elementIndexList, + elementIndexList, + )) { + return false; + } + + return true; + } + + void write(BufferedSink sink) { + sink.writeStringUtf8(tokenBuffer); + sink.writeUint30List(tokenLengthList); + sink.writeList(elements, (e) => e.write(sink)); + sink.writeUint30List(elementIndexList); } static ManifestNode? readOptional(SummaryDataReader reader) { @@ -43,162 +139,54 @@ sealed class ManifestNode { } } -class ManifestNodeAnnotation extends ManifestNode { - final ManifestNodeSimpleIdentifier name; +class _ElementCollector extends ThrowingAstVisitor { + static const int _nullIndex = 0; - ManifestNodeAnnotation({ - required this.name, - }); + final Map map = Map.identity(); + final List elementIndexList = []; - factory ManifestNodeAnnotation.encode( - EncodeContext context, - Annotation node, - ) { - if (node.name case SimpleIdentifier identifier) { - return ManifestNodeAnnotation( - name: ManifestNodeSimpleIdentifier.encode(context, identifier), - ); + @override + void visitAnnotation(Annotation node) { + // TODO(scheglov): implement visitAnnotation + } + + @override + void visitBinaryExpression(BinaryExpression node) { + node.leftOperand.accept(this); + _addElement(node.element); + node.rightOperand.accept(this); + } + + @override + void visitIntegerLiteral(IntegerLiteral node) {} + + @override + void visitParenthesizedExpression(ParenthesizedExpression node) { + node.visitChildren(this); + } + + @override + void visitSimpleIdentifier(SimpleIdentifier node) { + _addElement(node.element); + } + + void _addElement(Element2? element) { + if (element == null) { + elementIndexList.add(_nullIndex); } else { - throw UnimplementedError('(${node.runtimeType}) $node'); + var index = map[element] ??= 1 + map.length; + elementIndexList.add(index); } } - - factory ManifestNodeAnnotation.read(SummaryDataReader reader) { - return ManifestNodeAnnotation( - name: ManifestNodeSimpleIdentifier.read(reader), - ); - } - - @override - bool match(MatchContext context, AstNode node) { - if (node is! Annotation) { - return false; - } - - if (!name.match(context, node.name)) { - return false; - } - - return true; - } - - @override - void write(BufferedSink sink) { - sink.writeEnum(_ManifestNodeKind.annotation); - name.writeNoTag(sink); - } -} - -class ManifestNodeIntegerLiteral extends ManifestNode { - final int? value; - - ManifestNodeIntegerLiteral({ - required this.value, - }); - - factory ManifestNodeIntegerLiteral.encode(IntegerLiteral node) { - return ManifestNodeIntegerLiteral( - value: node.value, - ); - } - - factory ManifestNodeIntegerLiteral.read(SummaryDataReader reader) { - return ManifestNodeIntegerLiteral( - value: reader.readOptionalInt64(), - ); - } - - @override - bool match(MatchContext context, AstNode node) { - return node is IntegerLiteral && node.value == value; - } - - @override - void write(BufferedSink sink) { - sink.writeEnum(_ManifestNodeKind.integerLiteral); - sink.writeOptionalInt64(value); - } -} - -class ManifestNodeSimpleIdentifier extends ManifestNode { - final String name; - final ManifestElement? element; - - ManifestNodeSimpleIdentifier({ - required this.name, - required this.element, - }); - - factory ManifestNodeSimpleIdentifier.encode( - EncodeContext context, - SimpleIdentifier node, - ) { - var element = node.element; - return ManifestNodeSimpleIdentifier( - name: node.name, - element: - element != null ? ManifestElement.encode(context, element) : null, - ); - } - - factory ManifestNodeSimpleIdentifier.read(SummaryDataReader reader) { - return ManifestNodeSimpleIdentifier( - name: reader.readStringUtf8(), - element: reader.readOptionalObject( - () => ManifestElement.read(reader), - ), - ); - } - - @override - bool match(MatchContext context, AstNode node) { - if (node is! SimpleIdentifier) { - return false; - } - - if (node.name != name) { - return false; - } - - var element = this.element; - var nodeElement = node.element; - if (element == null && nodeElement == null) { - } else if (element == null || nodeElement == null) { - return false; - } else if (!element.match(context, nodeElement)) { - return false; - } - - return true; - } - - @override - void write(BufferedSink sink) { - sink.writeEnum(_ManifestNodeKind.simpleIdentifier); - writeNoTag(sink); - } - - void writeNoTag(BufferedSink sink) { - sink.writeStringUtf8(name); - sink.writeOptionalObject(element, (it) => it.write(sink)); - } -} - -enum _ManifestNodeKind { - annotation, - integerLiteral, - simpleIdentifier, } extension ManifestNodeOrNullExtension on ManifestNode? { bool match(MatchContext context, AstNode? node) { var self = this; - if (self == null && node == null) { - return true; - } else if (self == null || node == null) { - return false; - } else { + if (self != null && node != null) { return self.match(context, node); + } else { + return self == null && node == null; } } diff --git a/pkg/analyzer/lib/src/fine/manifest_context.dart b/pkg/analyzer/lib/src/fine/manifest_context.dart index 74945a1a1e8..49368f7b32b 100644 --- a/pkg/analyzer/lib/src/fine/manifest_context.dart +++ b/pkg/analyzer/lib/src/fine/manifest_context.dart @@ -5,6 +5,7 @@ import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/src/fine/lookup_name.dart'; import 'package:analyzer/src/fine/manifest_id.dart'; +import 'package:analyzer/src/fine/manifest_item.dart'; import 'package:analyzer/src/fine/manifest_type.dart'; import 'package:analyzer/src/summary2/data_reader.dart'; import 'package:analyzer/src/summary2/data_writer.dart'; @@ -68,59 +69,78 @@ final class ManifestElement { /// The URI of the library that declares the element. final Uri libraryUri; - /// The name of the element. - final String name; + /// The top-level element name. + final String topLevelName; + + /// The member name, e.g. a method name. + final String? memberName; /// The id of the element, if not from the same bundle. final ManifestItemId? id; ManifestElement({ required this.libraryUri, - required this.name, + required this.topLevelName, + required this.memberName, required this.id, }); factory ManifestElement.read(SummaryDataReader reader) { return ManifestElement( libraryUri: reader.readUri(), - name: reader.readStringUtf8(), + topLevelName: reader.readStringUtf8(), + memberName: reader.readOptionalStringUtf8(), id: reader.readOptionalObject(() => ManifestItemId.read(reader)), ); } @override - int get hashCode => Object.hash(libraryUri, name); + int get hashCode => Object.hash(libraryUri, topLevelName, memberName); @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is ManifestElement && other.libraryUri == libraryUri && - other.name == name; + other.topLevelName == topLevelName && + other.memberName == memberName; } /// If [element] matches this description, records the reference and id. /// If not, returns `false`, it is a mismatch anyway. bool match(MatchContext context, Element2 element) { - var enclosingElement = element.enclosingElement2; - if (enclosingElement case LibraryElement2 library) { - if (library.uri == libraryUri && element.name3 == name) { - context.elements.add(element); - if (id case var id?) { - context.externalIds[element] = id; - } - return true; - } + var enclosingElement = element.enclosingElement2!; + Element2 givenTopLevelElement; + Element2? givenMemberElement; + if (enclosingElement is LibraryElement2) { + givenTopLevelElement = element; + } else { + givenTopLevelElement = enclosingElement; + givenMemberElement = element; + } + var givenLibraryUri = enclosingElement.library2!.uri; + + if (givenLibraryUri != libraryUri) { + return false; + } + if (givenTopLevelElement.lookupName != topLevelName) { + return false; + } + if (givenMemberElement?.lookupName != memberName) { return false; } - // TODO(scheglov): support also not top-level elements. - return false; + context.elements.add(element); + if (id case var id?) { + context.externalIds[element] = id; + } + return true; } void write(BufferedSink sink) { sink.writeUri(libraryUri); - sink.writeStringUtf8(name); + sink.writeStringUtf8(topLevelName); + sink.writeOptionalStringUtf8(memberName); sink.writeOptionalObject(id, (it) => it.write(sink)); } @@ -128,13 +148,27 @@ final class ManifestElement { EncodeContext context, Element2 element, ) { - // TODO(scheglov): support also not top-level elements. + Element2 topLevelElement; + Element2? memberElement; + var enclosingElement = element.enclosingElement2!; + if (enclosingElement is LibraryElement2) { + topLevelElement = element; + } else { + topLevelElement = enclosingElement; + memberElement = element; + } + return ManifestElement( - libraryUri: element.library2!.uri, - name: element.name3!, + libraryUri: topLevelElement.library2!.uri, + topLevelName: topLevelElement.lookupName!, + memberName: memberElement?.lookupName, id: context.getElementId(element), ); } + + static List readList(SummaryDataReader reader) { + return reader.readTypedList(() => ManifestElement.read(reader)); + } } class MatchContext { @@ -192,12 +226,18 @@ class MatchContext { extension LinkedElementFactoryExtension on LinkedElementFactory { /// Returns the id of [element], or `null` if from this bundle. - ManifestItemId? getElementId(Element2 element) { - // SAFETY: if we can reference the element, it has a name. - var name = element.lookupName!.asLookupName; + ManifestItemId? getElementId(Element2 element2) { + Element2 topLevelElement; + Element2? memberElement; + if (element2.enclosingElement2 is LibraryElement2) { + topLevelElement = element2; + } else { + topLevelElement = element2.enclosingElement2!; + memberElement = element2; + } // SAFETY: if we can reference the element, it is in a library. - var libraryUri = element.library2!.uri; + var libraryUri = topLevelElement.library2!.uri; // Prepare the external library manifest. var manifest = libraryManifests[libraryUri]; @@ -205,8 +245,27 @@ extension LinkedElementFactoryExtension on LinkedElementFactory { return null; } - // SAFETY: every element is in the manifest of the declaring library. - // TODO(scheglov): if we do null assert, it fails, investigate - return manifest.items[name]?.id; + // SAFETY: if we can reference the element, it has a name. + var topLevelName = topLevelElement.lookupName!.asLookupName; + var topLevelItem = manifest.items[topLevelName]; + + // TODO(scheglov): remove it after supporting all elements + if (topLevelItem == null) { + return null; + } + + if (memberElement == null) { + return topLevelItem.id; + } + + // TODO(scheglov): When implementation is complete, cast unconditionally. + if (topLevelItem is InstanceItem) { + var memberName = memberElement.lookupName!.asLookupName; + var memberItem = topLevelItem.members[memberName]; + // TODO(scheglov): When implementation is complete, null assert. + return memberItem?.id; + } + + return null; } } diff --git a/pkg/analyzer/lib/src/fine/manifest_item.dart b/pkg/analyzer/lib/src/fine/manifest_item.dart index 0d3677cdc1f..7819bafe978 100644 --- a/pkg/analyzer/lib/src/fine/manifest_item.dart +++ b/pkg/analyzer/lib/src/fine/manifest_item.dart @@ -717,6 +717,7 @@ extension _GetterElementImplExtension on GetterElementImpl { // TODO(scheglov): support all expressions switch (constInitializer) { + case BinaryExpression(): case IntegerLiteral(): case SimpleIdentifier(): break; diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart index 5a9d021514b..afb6952c53e 100644 --- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart @@ -9538,10 +9538,271 @@ class A {} ); } - test_manifest_constInitializer_integerLiteral() async { + test_manifest_constInitializer_binaryExpression() async { + await _runLibraryManifestScenario( + initialCode: r''' +const a = 0 + 1; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 +''', + updatedCode: r''' +const a = 0 + 1; +const b = 0; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 + b: #M1 +''', + ); + } + + test_manifest_constInitializer_binaryExpression_left_change() async { + await _runLibraryManifestScenario( + initialCode: r''' +const a = 0; +const b = a + 2; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 + b: #M1 +''', + updatedCode: r''' +const a = 1; +const b = a + 2; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M2 + b: #M3 +''', + ); + } + + test_manifest_constInitializer_binaryExpression_left_token() async { + await _runLibraryManifestScenario( + initialCode: r''' +const a = 0 + 1; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 +''', + updatedCode: r''' +const a = 2 + 1; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M1 +''', + ); + } + + test_manifest_constInitializer_binaryExpression_operator() async { + await _runLibraryManifestScenario( + initialCode: r''' +class A { + const A(); + int operator+(_) {} +} +const a = A(); +const x = a + 1; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + A: #M0 + +: #M1 + a: #M2 + x: #M3 +''', + updatedCode: r''' +class A { + const A(); + double operator+(_) {} +} +const a = A(); +const x = a + 1; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + A: #M0 + +: #M4 + a: #M2 + x: #M5 +''', + ); + } + + test_manifest_constInitializer_binaryExpression_operator_token() async { + await _runLibraryManifestScenario( + initialCode: r''' +const a = 0 + 1; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 +''', + updatedCode: r''' +const a = 0 - 1; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M1 +''', + ); + } + + test_manifest_constInitializer_binaryExpression_right() async { + await _runLibraryManifestScenario( + initialCode: r''' +const a = 0; +const b = 2 + a; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 + b: #M1 +''', + updatedCode: r''' +const a = 1; +const b = 2 + a; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M2 + b: #M3 +''', + ); + } + + test_manifest_constInitializer_binaryExpression_right_add() async { configuration.withElementManifests = true; await _runLibraryManifestScenario( initialCode: r''' +const b = 0 + a; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + b: #M0 + returnType: double @ dart:core + constInitializer + tokenBuffer: 0+a + tokenLengthList: [1, 1, 1] + elements + [1] (dart:core, num, +) #M1 + elementIndexList: [1, 0] +''', + updatedCode: r''' +const a = 1; +const b = 0 + a; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M2 + returnType: int @ dart:core + constInitializer + tokenBuffer: 1 + tokenLengthList: [1] + b: #M3 + returnType: int @ dart:core + constInitializer + tokenBuffer: 0+a + tokenLengthList: [1, 1, 1] + elements + [1] (dart:core, num, +) #M1 + [2] (package:test/test.dart, a) + elementIndexList: [1, 2] +''', + ); + } + + test_manifest_constInitializer_binaryExpression_right_remove() async { + configuration.withElementManifests = true; + await _runLibraryManifestScenario( + initialCode: r''' +const a = 0; +const b = 1 + a; +''', + expectedInitialEvents: r''' +[operation] linkLibraryCycle SDK +[operation] linkLibraryCycle + package:test/test.dart + manifest + a: #M0 + returnType: int @ dart:core + constInitializer + tokenBuffer: 0 + tokenLengthList: [1] + b: #M1 + returnType: int @ dart:core + constInitializer + tokenBuffer: 1+a + tokenLengthList: [1, 1, 1] + elements + [1] (dart:core, num, +) #M2 + [2] (package:test/test.dart, a) + elementIndexList: [1, 2] +''', + updatedCode: r''' +const b = 1 + a; +''', + expectedUpdatedEvents: r''' +[operation] linkLibraryCycle + package:test/test.dart + manifest + b: #M3 + returnType: double @ dart:core + constInitializer + tokenBuffer: 1+a + tokenLengthList: [1, 1, 1] + elements + [1] (dart:core, num, +) #M2 + elementIndexList: [1, 0] +''', + ); + } + + test_manifest_constInitializer_integerLiteral() async { + await _runLibraryManifestScenario( + initialCode: r''' const a = 0; ''', expectedInitialEvents: r''' @@ -9550,9 +9811,6 @@ const a = 0; package:test/test.dart manifest a: #M0 - returnType: int @ dart:core - constInitializer: ManifestNodeIntegerLiteral - value: 0 ''', updatedCode: r''' const a = 0; @@ -9563,19 +9821,12 @@ const b = 1; package:test/test.dart manifest a: #M0 - returnType: int @ dart:core - constInitializer: ManifestNodeIntegerLiteral - value: 0 b: #M1 - returnType: int @ dart:core - constInitializer: ManifestNodeIntegerLiteral - value: 1 ''', ); } test_manifest_constInitializer_integerLiteral_value() async { - configuration.withElementManifests = true; await _runLibraryManifestScenario( initialCode: r''' const a = 0; @@ -9586,9 +9837,6 @@ const a = 0; package:test/test.dart manifest a: #M0 - returnType: int @ dart:core - constInitializer: ManifestNodeIntegerLiteral - value: 0 ''', updatedCode: r''' const a = 1; @@ -9598,9 +9846,6 @@ const a = 1; package:test/test.dart manifest a: #M1 - returnType: int @ dart:core - constInitializer: ManifestNodeIntegerLiteral - value: 1 ''', ); } diff --git a/pkg/analyzer/test/src/dart/analysis/result_printer.dart b/pkg/analyzer/test/src/dart/analysis/result_printer.dart index 784416be50b..b112b86f4da 100644 --- a/pkg/analyzer/test/src/dart/analysis/result_printer.dart +++ b/pkg/analyzer/test/src/dart/analysis/result_printer.dart @@ -15,6 +15,7 @@ import 'package:analyzer/src/dart/analysis/status.dart'; import 'package:analyzer/src/fine/library_manifest.dart'; import 'package:analyzer/src/fine/lookup_name.dart'; import 'package:analyzer/src/fine/manifest_ast.dart'; +import 'package:analyzer/src/fine/manifest_context.dart'; import 'package:analyzer/src/fine/manifest_id.dart'; import 'package:analyzer/src/fine/manifest_item.dart'; import 'package:analyzer/src/fine/manifest_type.dart'; @@ -794,6 +795,16 @@ class LibraryManifestPrinter { } } + void _writelnElement(ManifestElement element) { + var parts = [ + element.libraryUri, + element.topLevelName, + if (element.memberName case var memberName?) memberName, + ]; + var idStr = idProvider.manifestId(element.id); + sink.writeln('(${parts.join(', ')}) $idStr'); + } + void _writeNamedId(LookupName name, ManifestItemId id) { var idStr = idProvider.manifestId(id); sink.writelnWithIndent('$name: $idStr'); @@ -810,20 +821,25 @@ class LibraryManifestPrinter { void _writeNode(String name, ManifestNode? node) { if (node != null) { - sink.writeWithIndent('$name: '); - switch (node) { - case ManifestNodeAnnotation(): - // TODO(scheglov): Handle this case. - throw UnimplementedError(); - case ManifestNodeIntegerLiteral(): - sink.writeln('ManifestNodeIntegerLiteral'); + sink.writelnWithIndent(name); + sink.withIndent(() { + sink.writelnWithIndent('tokenBuffer: ${node.tokenBuffer}'); + sink.writelnWithIndent('tokenLengthList: ${node.tokenLengthList}'); + + if (node.elements.isNotEmpty) { + sink.writelnWithIndent('elements'); sink.withIndent(() { - sink.writelnWithIndent('value: ${node.value}'); + for (var (index, element) in node.elements.indexed) { + sink.writeWithIndent('[${1 + index}] '); + _writelnElement(element); + } }); - case ManifestNodeSimpleIdentifier(): - // TODO(scheglov): Handle this case. - throw UnimplementedError(); - } + } + + if (node.elementIndexList.isNotEmpty) { + sink.writelnWithIndent('elementIndexList: ${node.elementIndexList}'); + } + }); } } @@ -884,7 +900,7 @@ class LibraryManifestPrinter { }); case ManifestInterfaceType(): var element = type.element; - sink.write(element.name); + sink.write(element.topLevelName); writeNullabilitySuffix(); sink.write(' @ '); sink.writeln(element.libraryUri);