Skip to content

Commit 65a5ed2

Browse files
scheglovCommit Queue
authored andcommitted
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 <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 8bfe452 commit 65a5ed2

File tree

5 files changed

+512
-203
lines changed

5 files changed

+512
-203
lines changed

pkg/analyzer/lib/src/fine/manifest_ast.dart

Lines changed: 134 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -2,203 +2,191 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:typed_data';
6+
57
import 'package:analyzer/dart/ast/ast.dart';
8+
import 'package:analyzer/dart/ast/visitor.dart';
9+
import 'package:analyzer/dart/element/element2.dart';
610
import 'package:analyzer/src/dart/ast/ast.dart';
711
import 'package:analyzer/src/fine/manifest_context.dart';
812
import 'package:analyzer/src/summary2/data_reader.dart';
913
import 'package:analyzer/src/summary2/data_writer.dart';
10-
11-
sealed class ManifestNode {
12-
bool match(MatchContext context, AstNode node);
13-
14-
void write(BufferedSink sink);
15-
16-
static ManifestNode encode(EncodeContext context, AstNode node) {
17-
switch (node) {
18-
case Annotation():
19-
return ManifestNodeAnnotation.encode(context, node);
20-
case IntegerLiteral():
21-
return ManifestNodeIntegerLiteral.encode(node);
22-
case SimpleIdentifier():
23-
return ManifestNodeSimpleIdentifier.encode(context, node);
24-
default:
25-
throw UnimplementedError('(${node.runtimeType}) $node');
14+
import 'package:analyzer/src/utilities/extensions/collection.dart';
15+
import 'package:collection/collection.dart';
16+
17+
/// Enough information to decide if the node is the same.
18+
///
19+
/// We don't store ASTs, instead we rely on the fact that the same tokens
20+
/// are parsed into the same AST (when the same language features, which is
21+
/// ensured outside).
22+
///
23+
/// In addition we record all referenced elements.
24+
class ManifestNode {
25+
/// The concatenated lexemes of all tokens.
26+
final String tokenBuffer;
27+
28+
/// The length of each token in [tokenBuffer].
29+
final Uint32List tokenLengthList;
30+
31+
/// All unique elements referenced by this node.
32+
final List<ManifestElement> elements;
33+
34+
/// For each property in the AST structure summarized by this manifest that
35+
/// might point to an element, `0` if the element pointer is `null`; otherwise
36+
/// one plus the index of the associated manifest element in [elements].
37+
///
38+
/// The order of this list reflects the AST structure, according to the
39+
/// behavior of [_ElementCollector].
40+
final Uint32List elementIndexList;
41+
42+
factory ManifestNode.encode(EncodeContext context, AstNode node) {
43+
var buffer = StringBuffer();
44+
var lengthList = <int>[];
45+
46+
var token = node.beginToken;
47+
while (true) {
48+
buffer.write(token.lexeme);
49+
lengthList.add(token.lexeme.length);
50+
if (token == node.endToken) {
51+
break;
52+
}
53+
token = token.next ?? (throw StateError('endToken not found'));
2654
}
27-
}
2855

29-
static ManifestNode read(SummaryDataReader reader) {
30-
var kind = reader.readEnum(_ManifestNodeKind.values);
31-
switch (kind) {
32-
case _ManifestNodeKind.annotation:
33-
return ManifestNodeAnnotation.read(reader);
34-
case _ManifestNodeKind.integerLiteral:
35-
return ManifestNodeIntegerLiteral.read(reader);
36-
case _ManifestNodeKind.simpleIdentifier:
37-
return ManifestNodeSimpleIdentifier.read(reader);
38-
}
39-
}
56+
var collector = _ElementCollector();
57+
node.accept(collector);
4058

41-
static ManifestNode? readOptional(SummaryDataReader reader) {
42-
return reader.readOptionalObject(() => ManifestNode.read(reader));
59+
return ManifestNode._(
60+
tokenBuffer: buffer.toString(),
61+
tokenLengthList: Uint32List.fromList(lengthList),
62+
elements: collector.map.keys
63+
.map((element) => ManifestElement.encode(context, element))
64+
.toFixedList(),
65+
elementIndexList: Uint32List.fromList(collector.elementIndexList),
66+
);
4367
}
44-
}
4568

46-
class ManifestNodeAnnotation extends ManifestNode {
47-
final ManifestNodeSimpleIdentifier name;
69+
factory ManifestNode.read(SummaryDataReader reader) {
70+
return ManifestNode._(
71+
tokenBuffer: reader.readStringUtf8(),
72+
tokenLengthList: reader.readUInt30List(),
73+
elements: ManifestElement.readList(reader),
74+
elementIndexList: reader.readUInt30List(),
75+
);
76+
}
4877

49-
ManifestNodeAnnotation({
50-
required this.name,
78+
ManifestNode._({
79+
required this.tokenBuffer,
80+
required this.tokenLengthList,
81+
required this.elements,
82+
required this.elementIndexList,
5183
});
5284

53-
factory ManifestNodeAnnotation.encode(
54-
EncodeContext context,
55-
Annotation node,
56-
) {
57-
if (node.name case SimpleIdentifier identifier) {
58-
return ManifestNodeAnnotation(
59-
name: ManifestNodeSimpleIdentifier.encode(context, identifier),
60-
);
61-
} else {
62-
throw UnimplementedError('(${node.runtimeType}) $node');
85+
bool match(MatchContext context, AstNode node) {
86+
var tokenIndex = 0;
87+
var tokenOffset = 0;
88+
var token = node.beginToken;
89+
while (true) {
90+
var tokenLength = token.lexeme.length;
91+
if (tokenLengthList[tokenIndex++] != tokenLength) {
92+
return false;
93+
}
94+
95+
if (!tokenBuffer.startsWith(token.lexeme, tokenOffset)) {
96+
return false;
97+
}
98+
tokenOffset += tokenLength;
99+
100+
if (token == node.endToken) {
101+
break;
102+
}
103+
token = token.next ?? (throw StateError('endToken not found'));
63104
}
64-
}
65105

66-
factory ManifestNodeAnnotation.read(SummaryDataReader reader) {
67-
return ManifestNodeAnnotation(
68-
name: ManifestNodeSimpleIdentifier.read(reader),
69-
);
70-
}
106+
var collector = _ElementCollector();
107+
node.accept(collector);
71108

72-
@override
73-
bool match(MatchContext context, AstNode node) {
74-
if (node is! Annotation) {
109+
// Must reference the same elements.
110+
if (collector.map.length != elements.length) {
75111
return false;
76112
}
113+
for (var (index, element) in collector.map.keys.indexed) {
114+
if (!elements[index].match(context, element)) {
115+
return false;
116+
}
117+
}
77118

78-
if (!name.match(context, node.name)) {
119+
// Must reference elements in the same order.
120+
if (!const ListEquality<int>().equals(
121+
collector.elementIndexList,
122+
elementIndexList,
123+
)) {
79124
return false;
80125
}
81126

82127
return true;
83128
}
84129

85-
@override
86130
void write(BufferedSink sink) {
87-
sink.writeEnum(_ManifestNodeKind.annotation);
88-
name.writeNoTag(sink);
89-
}
90-
}
91-
92-
class ManifestNodeIntegerLiteral extends ManifestNode {
93-
final int? value;
94-
95-
ManifestNodeIntegerLiteral({
96-
required this.value,
97-
});
98-
99-
factory ManifestNodeIntegerLiteral.encode(IntegerLiteral node) {
100-
return ManifestNodeIntegerLiteral(
101-
value: node.value,
102-
);
103-
}
104-
105-
factory ManifestNodeIntegerLiteral.read(SummaryDataReader reader) {
106-
return ManifestNodeIntegerLiteral(
107-
value: reader.readOptionalInt64(),
108-
);
131+
sink.writeStringUtf8(tokenBuffer);
132+
sink.writeUint30List(tokenLengthList);
133+
sink.writeList(elements, (e) => e.write(sink));
134+
sink.writeUint30List(elementIndexList);
109135
}
110136

111-
@override
112-
bool match(MatchContext context, AstNode node) {
113-
return node is IntegerLiteral && node.value == value;
114-
}
115-
116-
@override
117-
void write(BufferedSink sink) {
118-
sink.writeEnum(_ManifestNodeKind.integerLiteral);
119-
sink.writeOptionalInt64(value);
137+
static ManifestNode? readOptional(SummaryDataReader reader) {
138+
return reader.readOptionalObject(() => ManifestNode.read(reader));
120139
}
121140
}
122141

123-
class ManifestNodeSimpleIdentifier extends ManifestNode {
124-
final String name;
125-
final ManifestElement? element;
142+
class _ElementCollector extends ThrowingAstVisitor<void> {
143+
static const int _nullIndex = 0;
126144

127-
ManifestNodeSimpleIdentifier({
128-
required this.name,
129-
required this.element,
130-
});
145+
final Map<Element2, int> map = Map.identity();
146+
final List<int> elementIndexList = [];
131147

132-
factory ManifestNodeSimpleIdentifier.encode(
133-
EncodeContext context,
134-
SimpleIdentifier node,
135-
) {
136-
var element = node.element;
137-
return ManifestNodeSimpleIdentifier(
138-
name: node.name,
139-
element:
140-
element != null ? ManifestElement.encode(context, element) : null,
141-
);
148+
@override
149+
void visitAnnotation(Annotation node) {
150+
// TODO(scheglov): implement visitAnnotation
142151
}
143152

144-
factory ManifestNodeSimpleIdentifier.read(SummaryDataReader reader) {
145-
return ManifestNodeSimpleIdentifier(
146-
name: reader.readStringUtf8(),
147-
element: reader.readOptionalObject(
148-
() => ManifestElement.read(reader),
149-
),
150-
);
153+
@override
154+
void visitBinaryExpression(BinaryExpression node) {
155+
node.leftOperand.accept(this);
156+
_addElement(node.element);
157+
node.rightOperand.accept(this);
151158
}
152159

153160
@override
154-
bool match(MatchContext context, AstNode node) {
155-
if (node is! SimpleIdentifier) {
156-
return false;
157-
}
161+
void visitIntegerLiteral(IntegerLiteral node) {}
158162

159-
if (node.name != name) {
160-
return false;
161-
}
162-
163-
var element = this.element;
164-
var nodeElement = node.element;
165-
if (element == null && nodeElement == null) {
166-
} else if (element == null || nodeElement == null) {
167-
return false;
168-
} else if (!element.match(context, nodeElement)) {
169-
return false;
170-
}
171-
172-
return true;
163+
@override
164+
void visitParenthesizedExpression(ParenthesizedExpression node) {
165+
node.visitChildren(this);
173166
}
174167

175168
@override
176-
void write(BufferedSink sink) {
177-
sink.writeEnum(_ManifestNodeKind.simpleIdentifier);
178-
writeNoTag(sink);
169+
void visitSimpleIdentifier(SimpleIdentifier node) {
170+
_addElement(node.element);
179171
}
180172

181-
void writeNoTag(BufferedSink sink) {
182-
sink.writeStringUtf8(name);
183-
sink.writeOptionalObject(element, (it) => it.write(sink));
173+
void _addElement(Element2? element) {
174+
if (element == null) {
175+
elementIndexList.add(_nullIndex);
176+
} else {
177+
var index = map[element] ??= 1 + map.length;
178+
elementIndexList.add(index);
179+
}
184180
}
185181
}
186182

187-
enum _ManifestNodeKind {
188-
annotation,
189-
integerLiteral,
190-
simpleIdentifier,
191-
}
192-
193183
extension ManifestNodeOrNullExtension on ManifestNode? {
194184
bool match(MatchContext context, AstNode? node) {
195185
var self = this;
196-
if (self == null && node == null) {
197-
return true;
198-
} else if (self == null || node == null) {
199-
return false;
200-
} else {
186+
if (self != null && node != null) {
201187
return self.match(context, node);
188+
} else {
189+
return self == null && node == null;
202190
}
203191
}
204192

0 commit comments

Comments
 (0)