Skip to content

Commit ee4960c

Browse files
authored
Generate for directive (#738)
Continue #735 Note that it restores applies to annotated directives test, as discussed in the previous PR. This functionality is indeed used, by package:checks generator. The first version uses analyzer dependency override, because I want want you to look at the code before I publish analyzer .
1 parent 117ab26 commit ee4960c

23 files changed

+347
-116
lines changed

.github/workflows/dart.yml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ jobs:
2121
runs-on: ubuntu-latest
2222
steps:
2323
- name: Cache Pub hosted dependencies
24-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
24+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
2525
with:
2626
path: "~/.pub-cache/hosted"
2727
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable"
2828
restore-keys: |
2929
os:ubuntu-latest;pub-cache-hosted
3030
os:ubuntu-latest
3131
- name: Setup Dart SDK
32-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
32+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
3333
with:
3434
sdk: stable
3535
- id: checkout
@@ -44,7 +44,7 @@ jobs:
4444
runs-on: ubuntu-latest
4545
steps:
4646
- name: Cache Pub hosted dependencies
47-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
47+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
4848
with:
4949
path: "~/.pub-cache/hosted"
5050
key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0;packages:source_gen;commands:analyze_1"
@@ -54,7 +54,7 @@ jobs:
5454
os:ubuntu-latest;pub-cache-hosted
5555
os:ubuntu-latest
5656
- name: Setup Dart SDK
57-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
57+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
5858
with:
5959
sdk: "3.6.0"
6060
- id: checkout
@@ -74,7 +74,7 @@ jobs:
7474
runs-on: ubuntu-latest
7575
steps:
7676
- name: Cache Pub hosted dependencies
77-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
77+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
7878
with:
7979
path: "~/.pub-cache/hosted"
8080
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:_test_annotations-example-example_usage-source_gen;commands:format-analyze_0"
@@ -84,7 +84,7 @@ jobs:
8484
os:ubuntu-latest;pub-cache-hosted
8585
os:ubuntu-latest
8686
- name: Setup Dart SDK
87-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
87+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
8888
with:
8989
sdk: dev
9090
- id: checkout
@@ -147,7 +147,7 @@ jobs:
147147
runs-on: ubuntu-latest
148148
steps:
149149
- name: Cache Pub hosted dependencies
150-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
150+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
151151
with:
152152
path: "~/.pub-cache/hosted"
153153
key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0;packages:example_usage;commands:test_0"
@@ -157,7 +157,7 @@ jobs:
157157
os:ubuntu-latest;pub-cache-hosted
158158
os:ubuntu-latest
159159
- name: Setup Dart SDK
160-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
160+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
161161
with:
162162
sdk: "3.6.0"
163163
- id: checkout
@@ -181,7 +181,7 @@ jobs:
181181
runs-on: ubuntu-latest
182182
steps:
183183
- name: Cache Pub hosted dependencies
184-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
184+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
185185
with:
186186
path: "~/.pub-cache/hosted"
187187
key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0;packages:source_gen;commands:test_1"
@@ -191,7 +191,7 @@ jobs:
191191
os:ubuntu-latest;pub-cache-hosted
192192
os:ubuntu-latest
193193
- name: Setup Dart SDK
194-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
194+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
195195
with:
196196
sdk: "3.6.0"
197197
- id: checkout
@@ -215,7 +215,7 @@ jobs:
215215
runs-on: ubuntu-latest
216216
steps:
217217
- name: Cache Pub hosted dependencies
218-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
218+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
219219
with:
220220
path: "~/.pub-cache/hosted"
221221
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:example_usage;commands:test_0"
@@ -225,7 +225,7 @@ jobs:
225225
os:ubuntu-latest;pub-cache-hosted
226226
os:ubuntu-latest
227227
- name: Setup Dart SDK
228-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
228+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
229229
with:
230230
sdk: dev
231231
- id: checkout
@@ -249,7 +249,7 @@ jobs:
249249
runs-on: ubuntu-latest
250250
steps:
251251
- name: Cache Pub hosted dependencies
252-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a
252+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf
253253
with:
254254
path: "~/.pub-cache/hosted"
255255
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:source_gen;commands:test_1"
@@ -259,7 +259,7 @@ jobs:
259259
os:ubuntu-latest;pub-cache-hosted
260260
os:ubuntu-latest
261261
- name: Setup Dart SDK
262-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
262+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
263263
with:
264264
sdk: dev
265265
- id: checkout
@@ -283,7 +283,7 @@ jobs:
283283
runs-on: windows-latest
284284
steps:
285285
- name: Setup Dart SDK
286-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
286+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
287287
with:
288288
sdk: "3.6.0"
289289
- id: checkout
@@ -307,7 +307,7 @@ jobs:
307307
runs-on: windows-latest
308308
steps:
309309
- name: Setup Dart SDK
310-
uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
310+
uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c
311311
with:
312312
sdk: dev
313313
- id: checkout

.github/workflows/no-response.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
runs-on: ubuntu-latest
2020
if: ${{ github.repository_owner == 'dart-lang' }}
2121
steps:
22-
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e
22+
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639
2323
with:
2424
# Don't automatically mark inactive issues+PRs as stale.
2525
days-before-stale: -1

analysis_options.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ analyzer:
88

99
linter:
1010
rules:
11-
- analyzer_use_new_elements
1211
- avoid_bool_literals_in_conditional_expressions
1312
- avoid_classes_with_only_static_members
1413
- avoid_private_typedef_functions

example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ environment:
66
sdk: ^3.6.0
77

88
dependencies:
9-
analyzer: '>=5.2.0 <7.0.0'
9+
analyzer: '>=6.9.0 <8.0.0'
1010
build: ^2.0.0
1111
source_gen: any
1212

example_usage/test/ensure_build_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ import 'package:test/test.dart';
1313
void main() {
1414
test(
1515
'ensure_build',
16-
() => expectBuildClean(packageRelativeDirectory: 'example_usage'),
16+
() async => expectBuildClean(packageRelativeDirectory: 'example_usage'),
1717
);
1818
}

source_gen/CHANGELOG.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
## 2.0.0-wip
1+
## 2.0.0
22

3+
- **DO NOT PUBLISH**: Only land into `analyzer-element2` branch.
4+
When all clients migrate, replace all APIs.
35
- **Breaking Change**: Change `formatOutput` function to accept a language
46
version parameter.
57
- **Formatting Change**: Generated code will no longer apply any fixes by
@@ -8,13 +10,17 @@
810
- Document deduplication behavior for the output of
911
`GeneratorForAnnotation.generateForAnnotatedElement`.
1012
- Support all the glob quotes.
11-
- Require `analyzer: ^6.9.0`
12-
- Require Dart 3.6.0
13+
- Require `analyzer: '>=7.2.0 <8.0.0'`
14+
- Support the latest `package:dart_style`
15+
- Add `generateForAnnotatedDirective`, which now must be used instead of
16+
`generateForAnnotatedElement` in order to support annotations on directives
17+
(imports, exports, parts).
1318
- `LibraryBuilder`, `PartBuilder`, and `SharedPartBuilder` now take an optional
1419
`writeDescriptions` boolean. When set to `false`, headers and generator
1520
descriptions for the files will not be included in the builder output.
1621
- Include `//dart format width=80` comments in files generated by a
1722
`LibraryBuilder` or `PartBuilder` and formatted with the default callback.
23+
- Require Dart 3.6.0
1824

1925
## 1.5.0
2026

source_gen/lib/source_gen.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export 'src/constants/revive.dart' show Revivable;
99
export 'src/generator.dart'
1010
show Generator, InvalidGenerationSource, InvalidGenerationSourceError;
1111
export 'src/generator_for_annotation.dart' show GeneratorForAnnotation;
12-
export 'src/library.dart' show AnnotatedElement, LibraryReader;
12+
export 'src/library.dart'
13+
show AnnotatedDirective, AnnotatedElement, LibraryReader;
1314
export 'src/span_for_element.dart' show spanForElement, spanForElement2;
1415
export 'src/type_checker.dart' show TypeChecker, UnresolvedAnnotationException;
1516
export 'src/utils.dart' show typeNameOf;

source_gen/lib/src/constants/reader.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analyzer/dart/constant/value.dart';
6-
import 'package:analyzer/dart/element/element.dart';
6+
import 'package:analyzer/dart/element/element2.dart';
77
import 'package:analyzer/dart/element/type.dart';
88

99
import '../type_checker.dart';
@@ -268,7 +268,7 @@ class _DartObjectConstant extends ConstantReader {
268268
ConstantReader read(String field) {
269269
final reader = peek(field);
270270
if (reader == null) {
271-
assertHasField(objectValue.type!.element as InterfaceElement, field);
271+
assertHasField2(objectValue.type!.element3 as InterfaceElement2, field);
272272
return const _NullConstant();
273273
}
274274
return reader;

source_gen/lib/src/constants/utils.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
import 'package:analyzer/dart/constant/value.dart';
66
import 'package:analyzer/dart/element/element.dart';
7+
import 'package:analyzer/dart/element/element2.dart';
78

89
/// Throws a [FormatException] if [root] does not have a given field [name].
910
///
1011
/// Super types [InterfaceElement.supertype] are also checked before throwing.
12+
@Deprecated('Use assertHasField2() instead')
1113
void assertHasField(InterfaceElement root, String name) {
1214
InterfaceElement? element = root;
1315
while (element != null) {
@@ -28,6 +30,29 @@ void assertHasField(InterfaceElement root, String name) {
2830
);
2931
}
3032

33+
/// Throws a [FormatException] if [root] does not have a given field [name].
34+
///
35+
/// Super types [InterfaceElement.supertype] are also checked before throwing.
36+
void assertHasField2(InterfaceElement2 root, String name) {
37+
InterfaceElement2? element = root;
38+
while (element != null) {
39+
final field = element.getField2(name);
40+
if (field != null) {
41+
return;
42+
}
43+
element = element.supertype?.element3;
44+
}
45+
final allFields = {
46+
...root.fields2,
47+
for (var t in root.allSupertypes) ...t.element3.fields2,
48+
};
49+
50+
throw FormatException(
51+
'Class ${root.name3} does not have field "$name".',
52+
'Fields: \n - ${allFields.map((e) => e.name3).join('\n - ')}',
53+
);
54+
}
55+
3156
/// Returns whether or not [object] is or represents a `null` value.
3257
bool isNullLike(DartObject? object) => object?.isNull != false;
3358

source_gen/lib/src/generator_for_annotation.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ abstract class GeneratorForAnnotation<T> extends Generator {
5555
FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async {
5656
final values = <String>{};
5757

58+
for (var annotatedDirective in library.libraryDirectivesAnnotatedWith(
59+
typeChecker,
60+
throwOnUnresolved: throwOnUnresolved,
61+
)) {
62+
final generatedValue = generateForAnnotatedDirective(
63+
annotatedDirective.directive,
64+
annotatedDirective.annotation,
65+
buildStep,
66+
);
67+
await for (var value in normalizeGeneratorOutput(generatedValue)) {
68+
assert(value.length == value.trim().length);
69+
values.add(value);
70+
}
71+
}
72+
5873
for (var annotatedElement in library.annotatedWith(
5974
typeChecker,
6075
throwOnUnresolved: throwOnUnresolved,
@@ -123,4 +138,30 @@ abstract class GeneratorForAnnotation<T> extends Generator {
123138
ConstantReader annotation,
124139
BuildStep buildStep,
125140
) {}
141+
142+
/// Implement to return source code to generate for [directive]:
143+
/// - [LibraryImport]
144+
/// - [LibraryExport]
145+
/// - [PartInclude]
146+
///
147+
/// This method is invoked based on finding directives annotated with an
148+
/// instance of [T]. The [annotation] is provided as a [ConstantReader].
149+
///
150+
/// Supported return values include a single [String] or multiple [String]
151+
/// instances within an [Iterable] or [Stream]. It is also valid to return a
152+
/// [Future] of [String], [Iterable], or [Stream]. When multiple values are
153+
/// returned through an iterable or stream they will be deduplicated.
154+
/// Typically each value will be an independent unit of code and the
155+
/// deduplication prevents re-defining the same member multiple times. For
156+
/// example if multiple annotated elements may need a specific utility method
157+
/// available it can be output for each one, and the single deduplicated
158+
/// definition can be shared.
159+
///
160+
/// Implementations should return `null` when no content is generated. Empty
161+
/// or whitespace-only [String] instances are also ignored.
162+
dynamic generateForAnnotatedDirective(
163+
ElementDirective directive,
164+
ConstantReader annotation,
165+
BuildStep buildStep,
166+
) {}
126167
}

0 commit comments

Comments
 (0)