Skip to content

Commit 2b82a40

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Fine. Initial metadata support.
Change-Id: I878a5352c17dd434486f36fec55d9cfacf967a3d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417660 Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Paul Berry <[email protected]>
1 parent e87200d commit 2b82a40

File tree

5 files changed

+321
-12
lines changed

5 files changed

+321
-12
lines changed

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4954,7 +4954,7 @@ mixin FragmentedAnnotatableElementMixin<E extends Fragment>
49544954
return result;
49554955
}
49564956

4957-
Metadata get metadata2 =>
4957+
MetadataImpl get metadata2 =>
49584958
MetadataImpl(-1, metadata.cast<ElementAnnotationImpl>());
49594959

49604960
Version? get sinceSdkVersion {
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/dart/ast/ast.dart';
6+
import 'package:analyzer/src/dart/ast/ast.dart';
7+
import 'package:analyzer/src/fine/manifest_context.dart';
8+
import 'package:analyzer/src/summary2/data_reader.dart';
9+
import 'package:analyzer/src/summary2/data_writer.dart';
10+
11+
class ManifestAnnotation extends ManifestNode {
12+
final ManifestSimpleIdentifier name;
13+
14+
ManifestAnnotation({
15+
required this.name,
16+
});
17+
18+
factory ManifestAnnotation.encode(
19+
EncodeContext context,
20+
Annotation node,
21+
) {
22+
if (node.name case SimpleIdentifier identifier) {
23+
return ManifestAnnotation(
24+
name: ManifestSimpleIdentifier.encode(context, identifier),
25+
);
26+
} else {
27+
throw UnimplementedError('(${node.runtimeType}) $node');
28+
}
29+
}
30+
31+
factory ManifestAnnotation.read(SummaryDataReader reader) {
32+
return ManifestAnnotation(
33+
name: ManifestSimpleIdentifier.read(reader),
34+
);
35+
}
36+
37+
@override
38+
bool match(MatchContext context, AstNode node) {
39+
if (node is! Annotation) {
40+
return false;
41+
}
42+
43+
if (!name.match(context, node.name)) {
44+
return false;
45+
}
46+
47+
return true;
48+
}
49+
50+
@override
51+
void write(BufferedSink sink) {
52+
sink.writeEnum(_ManifestNodeKind.annotation);
53+
name.write(sink);
54+
}
55+
}
56+
57+
sealed class ManifestNode {
58+
bool match(MatchContext context, AstNode node);
59+
60+
void write(BufferedSink sink);
61+
62+
static ManifestNode encode(EncodeContext context, AstNode node) {
63+
switch (node) {
64+
case Annotation():
65+
return ManifestAnnotation.encode(context, node);
66+
case SimpleIdentifier():
67+
return ManifestSimpleIdentifier.encode(context, node);
68+
default:
69+
throw UnimplementedError('(${node.runtimeType}) $node');
70+
}
71+
}
72+
73+
static ManifestNode read(SummaryDataReader reader) {
74+
var kind = reader.readEnum(_ManifestNodeKind.values);
75+
switch (kind) {
76+
case _ManifestNodeKind.annotation:
77+
return ManifestAnnotation.read(reader);
78+
case _ManifestNodeKind.simpleIdentifier:
79+
return ManifestSimpleIdentifier.read(reader);
80+
}
81+
}
82+
}
83+
84+
class ManifestSimpleIdentifier extends ManifestNode {
85+
final String name;
86+
final ManifestElement? element;
87+
88+
ManifestSimpleIdentifier({
89+
required this.name,
90+
required this.element,
91+
});
92+
93+
factory ManifestSimpleIdentifier.encode(
94+
EncodeContext context,
95+
SimpleIdentifier node,
96+
) {
97+
var element = node.element;
98+
return ManifestSimpleIdentifier(
99+
name: node.name,
100+
element:
101+
element != null ? ManifestElement.encode(context, element) : null,
102+
);
103+
}
104+
105+
factory ManifestSimpleIdentifier.read(SummaryDataReader reader) {
106+
return ManifestSimpleIdentifier(
107+
name: reader.readStringUtf8(),
108+
element: reader.readOptionalObject(
109+
() => ManifestElement.read(reader),
110+
),
111+
);
112+
}
113+
114+
@override
115+
bool match(MatchContext context, AstNode node) {
116+
if (node is! SimpleIdentifier) {
117+
return false;
118+
}
119+
120+
if (node.name != name) {
121+
return false;
122+
}
123+
124+
var element = this.element;
125+
var nodeElement = node.element;
126+
if (element == null && nodeElement == null) {
127+
} else if (element == null || nodeElement == null) {
128+
return false;
129+
} else if (!element.match(context, nodeElement)) {
130+
return false;
131+
}
132+
133+
return true;
134+
}
135+
136+
@override
137+
void write(BufferedSink sink) {
138+
sink.writeEnum(_ManifestNodeKind.simpleIdentifier);
139+
sink.writeStringUtf8(name);
140+
sink.writeOptionalObject(element, (it) => it.write(sink));
141+
}
142+
}
143+
144+
enum _ManifestNodeKind {
145+
annotation,
146+
simpleIdentifier,
147+
}

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,20 @@ final class ManifestElement {
105105

106106
/// If [element] matches this description, records the reference and id.
107107
/// If not, returns `false`, it is a mismatch anyway.
108-
bool match(MatchContext context, InstanceElement2 element) {
109-
if (element.library2.uri == libraryUri && element.name3 == name) {
110-
context.elements.add(element);
111-
if (id case var id?) {
112-
context.externalIds[element] = id;
108+
bool match(MatchContext context, Element2 element) {
109+
var enclosingElement = element.enclosingElement2;
110+
if (enclosingElement case LibraryElement2 library) {
111+
if (library.uri == libraryUri && element.name3 == name) {
112+
context.elements.add(element);
113+
if (id case var id?) {
114+
context.externalIds[element] = id;
115+
}
116+
return true;
113117
}
114-
return true;
118+
return false;
115119
}
120+
121+
// TODO(scheglov): support also not top-level elements.
116122
return false;
117123
}
118124

@@ -124,10 +130,11 @@ final class ManifestElement {
124130

125131
static ManifestElement encode(
126132
EncodeContext context,
127-
InstanceElement2 element,
133+
Element2 element,
128134
) {
135+
// TODO(scheglov): support also not top-level elements.
129136
return ManifestElement(
130-
libraryUri: element.library2.uri,
137+
libraryUri: element.library2!.uri,
131138
name: element.name3!,
132139
id: context.getElementId(element),
133140
);

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

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
import 'package:analyzer/src/dart/element/element.dart';
66
import 'package:analyzer/src/fine/lookup_name.dart';
7+
import 'package:analyzer/src/fine/manifest_ast.dart';
78
import 'package:analyzer/src/fine/manifest_context.dart';
89
import 'package:analyzer/src/fine/manifest_id.dart';
910
import 'package:analyzer/src/fine/manifest_type.dart';
1011
import 'package:analyzer/src/summary2/data_reader.dart';
1112
import 'package:analyzer/src/summary2/data_writer.dart';
13+
import 'package:analyzer/src/utilities/extensions/collection.dart';
1214

1315
class ClassItem extends TopLevelItem {
1416
final List<ManifestTypeParameter> typeParameters;
@@ -242,6 +244,37 @@ class InstanceMethodItem extends InstanceMemberItem {
242244
}
243245
}
244246

247+
class ManifestAnnotation {
248+
final ManifestNode ast;
249+
250+
ManifestAnnotation({
251+
required this.ast,
252+
});
253+
254+
factory ManifestAnnotation.read(SummaryDataReader reader) {
255+
return ManifestAnnotation(
256+
ast: ManifestNode.read(reader),
257+
);
258+
}
259+
260+
bool match(MatchContext context, ElementAnnotationImpl annotation) {
261+
var annotationAst = annotation.annotationAst;
262+
if (!ast.match(context, annotationAst)) {
263+
return false;
264+
}
265+
return true;
266+
}
267+
268+
static ManifestAnnotation encode(
269+
EncodeContext context,
270+
ElementAnnotationImpl annotation,
271+
) {
272+
return ManifestAnnotation(
273+
ast: ManifestNode.encode(context, annotation.annotationAst),
274+
);
275+
}
276+
}
277+
245278
sealed class ManifestItem {
246279
void write(BufferedSink sink);
247280
}
@@ -301,12 +334,14 @@ class TopLevelFunctionItem extends TopLevelItem {
301334
}
302335

303336
class TopLevelGetterItem extends TopLevelItem {
337+
final List<ManifestAnnotation> metadata;
304338
final ManifestType returnType;
305339

306340
TopLevelGetterItem({
307341
required super.libraryUri,
308342
required super.name,
309343
required super.id,
344+
required this.metadata,
310345
required this.returnType,
311346
});
312347

@@ -320,6 +355,9 @@ class TopLevelGetterItem extends TopLevelItem {
320355
libraryUri: element.library2.uri,
321356
name: name,
322357
id: id,
358+
metadata: element.metadata2.annotations.map((annotation) {
359+
return ManifestAnnotation.encode(context, annotation);
360+
}).toFixedList(),
323361
returnType: element.returnType.encode(context),
324362
);
325363
}
@@ -329,16 +367,29 @@ class TopLevelGetterItem extends TopLevelItem {
329367
libraryUri: reader.readUri(),
330368
name: LookupName.read(reader),
331369
id: ManifestItemId.read(reader),
370+
metadata: reader.readTypedList(() => ManifestAnnotation.read(reader)),
332371
returnType: ManifestType.read(reader),
333372
);
334373
}
335374

336375
MatchContext? match(GetterElementImpl element) {
337376
var context = MatchContext(parent: null);
338-
if (returnType.match(context, element.returnType)) {
339-
return context;
377+
378+
var annotations = element.metadata2.annotations;
379+
if (annotations.length != metadata.length) {
380+
return null;
340381
}
341-
return null;
382+
for (var i = 0; i < metadata.length; i++) {
383+
if (!metadata[i].match(context, annotations[i])) {
384+
return null;
385+
}
386+
}
387+
388+
if (!returnType.match(context, element.returnType)) {
389+
return null;
390+
}
391+
392+
return context;
342393
}
343394

344395
@override

0 commit comments

Comments
 (0)