Fine. Use tokens and elements for constant expressions.
Extends `ManifestElement` to support not only top-level elements, but also members. Change-Id: Ia714c4f23113883bac6d6b44ede3c1dfecbbb80d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419989 Reviewed-by: Paul Berry <paulberry@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
8bfe452ffd
commit
65a5ed2c09
@@ -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<ManifestElement> 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 = <int>[];
|
||||
|
||||
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<int>().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<void> {
|
||||
static const int _nullIndex = 0;
|
||||
|
||||
ManifestNodeAnnotation({
|
||||
required this.name,
|
||||
});
|
||||
final Map<Element2, int> map = Map.identity();
|
||||
final List<int> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ManifestElement> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,6 +717,7 @@ extension _GetterElementImplExtension on GetterElementImpl {
|
||||
|
||||
// TODO(scheglov): support all expressions
|
||||
switch (constInitializer) {
|
||||
case BinaryExpression():
|
||||
case IntegerLiteral():
|
||||
case SimpleIdentifier():
|
||||
break;
|
||||
|
||||
@@ -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) <null>
|
||||
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) <null>
|
||||
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
|
||||
''',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user