Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate for directive #738

Open
wants to merge 2 commits into
base: analyzer-element2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ environment:
sdk: ^3.6.0

dependencies:
analyzer: '>=5.2.0 <7.0.0'
analyzer: '>=6.9.0 <8.0.0'
build: ^2.0.0
source_gen: any

Expand Down
7 changes: 4 additions & 3 deletions source_gen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 2.0.0-wip
## 2.0.0

- **Breaking Change**: Change `formatOutput` function to accept a language
version parameter.
Expand All @@ -8,13 +8,14 @@
- Document deduplication behavior for the output of
`GeneratorForAnnotation.generateForAnnotatedElement`.
- Support all the glob quotes.
- Require `analyzer: ^6.9.0`
- Require Dart 3.6.0
- Require `analyzer: '>=6.9.0 <8.0.0'`
- Support the latest `package:dart_style`
- `LibraryBuilder`, `PartBuilder`, and `SharedPartBuilder` now take an optional
`writeDescriptions` boolean. When set to `false`, headers and generator
descriptions for the files will not be included in the builder output.
- Include `//dart format width=80` comments in files generated by a
`LibraryBuilder` or `PartBuilder` and formatted with the default callback.
- Require Dart 3.6.0

## 1.5.0

Expand Down
3 changes: 2 additions & 1 deletion source_gen/lib/source_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export 'src/constants/revive.dart' show Revivable;
export 'src/generator.dart'
show Generator, InvalidGenerationSource, InvalidGenerationSourceError;
export 'src/generator_for_annotation.dart' show GeneratorForAnnotation;
export 'src/library.dart' show AnnotatedElement, LibraryReader;
export 'src/library.dart'
show AnnotatedDirective, AnnotatedElement, LibraryReader;
export 'src/span_for_element.dart' show spanForElement, spanForElement2;
export 'src/type_checker.dart' show TypeChecker, UnresolvedAnnotationException;
export 'src/utils.dart' show typeNameOf;
38 changes: 38 additions & 0 deletions source_gen/lib/src/generator_for_annotation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ abstract class GeneratorForAnnotation<T> extends Generator {
FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async {
final values = <String>{};

for (var annotatedDirective in library.libraryDirectivesAnnotatedWith(
typeChecker,
throwOnUnresolved: throwOnUnresolved,
)) {
final generatedValue = generateForAnnotatedDirective(
annotatedDirective.directive,
annotatedDirective.annotation,
buildStep,
);
await for (var value in normalizeGeneratorOutput(generatedValue)) {
assert(value.length == value.trim().length);
values.add(value);
}
}

for (var annotatedElement in library.annotatedWith(
typeChecker,
throwOnUnresolved: throwOnUnresolved,
Expand Down Expand Up @@ -123,4 +138,27 @@ abstract class GeneratorForAnnotation<T> extends Generator {
ConstantReader annotation,
BuildStep buildStep,
) {}

/// Implement to return source code to generate for [directive].
///
/// This method is invoked based on finding directives annotated with an
/// instance of [T]. The [annotation] is provided as a [ConstantReader].
///
/// Supported return values include a single [String] or multiple [String]
/// instances within an [Iterable] or [Stream]. It is also valid to return a
/// [Future] of [String], [Iterable], or [Stream]. When multiple values are
/// returned through an iterable or stream they will be deduplicated.
/// Typically each value will be an independent unit of code and the
/// deduplication prevents re-defining the same member multiple times. For
/// example if multiple annotated elements may need a specific utility method
/// available it can be output for each one, and the single deduplicated
/// definition can be shared.
///
/// Implementations should return `null` when no content is generated. Empty
/// or whitespace-only [String] instances are also ignored.
dynamic generateForAnnotatedDirective(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the deal w/ this @scheglov ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, i don't understand the question.
This method is invoked at the line 62.

We cannot use the same method for elements and directive.

ElementDirective directive,
ConstantReader annotation,
BuildStep buildStep,
) {}
}
34 changes: 34 additions & 0 deletions source_gen/lib/src/library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ import 'constants/reader.dart';
import 'type_checker.dart';
import 'utils.dart';

/// Result of finding an [annotation] on [directive] through [LibraryReader].
class AnnotatedDirective {
final ConstantReader annotation;
final ElementDirective directive;

const AnnotatedDirective(this.annotation, this.directive);

Metadata? get metadata2 => directive.metadata2;
}

/// Result of finding an [annotation] on [element] through [LibraryReader].
class AnnotatedElement {
final ConstantReader annotation;
Expand Down Expand Up @@ -87,6 +97,30 @@ class LibraryReader {
}
}

/// All of the directives in this library annotated with [checker].
Iterable<AnnotatedDirective> libraryDirectivesAnnotatedWith(
TypeChecker checker, {
bool throwOnUnresolved = true,
}) sync* {
final firstFragment = element2.firstFragment;
final directives = [
...firstFragment.libraryImports2,
...firstFragment.libraryExports2,
...firstFragment.partIncludes,
];

for (final directive in directives) {
final annotation = checker.firstAnnotationOf2(
directive,
throwOnUnresolved: throwOnUnresolved,
);

if (annotation != null) {
yield AnnotatedDirective(ConstantReader(annotation), directive);
}
}
}

/// All of the declarations in this library annotated with exactly [checker].
Iterable<AnnotatedElement> annotatedWithExact(
TypeChecker checker, {
Expand Down
10 changes: 5 additions & 5 deletions source_gen/lib/src/type_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ abstract class TypeChecker {
///
/// Throws on unresolved annotations unless [throwOnUnresolved] is `false`.
DartObject? firstAnnotationOf2(
Element2 element, {
Object element, {
bool throwOnUnresolved = true,
}) {
if (element case final Annotatable annotatable) {
Expand Down Expand Up @@ -188,13 +188,13 @@ abstract class TypeChecker {
}

DartObject? _computeConstantValue2(
Element2 element,
Object element,
ElementAnnotation annotation,
int annotationIndex, {
bool throwOnUnresolved = true,
}) {
final result = annotation.computeConstantValue();
if (result == null && throwOnUnresolved) {
if (result == null && throwOnUnresolved && element is Element2) {
throw UnresolvedAnnotationException._from(element, annotationIndex);
}
return result;
Expand All @@ -219,7 +219,7 @@ abstract class TypeChecker {
/// Throws [UnresolvedAnnotationException] on unresolved annotations unless
/// [throwOnUnresolved] is explicitly set to `false` (default is `true`).
Iterable<DartObject> annotationsOf2(
Element2 element, {
Object element, {
bool throwOnUnresolved = true,
}) =>
_annotationsWhere2(
Expand All @@ -246,7 +246,7 @@ abstract class TypeChecker {
}

Iterable<DartObject> _annotationsWhere2(
Element2 element,
Object element,
bool Function(DartType) predicate, {
bool throwOnUnresolved = true,
}) sync* {
Expand Down
9 changes: 5 additions & 4 deletions source_gen/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: source_gen
version: 2.0.0-wip
version: 2.0.0
description: >-
Source code generation builders and utilities for the Dart build system
repository: https://github.com/dart-lang/source_gen/tree/master/source_gen
Expand All @@ -10,10 +10,10 @@ environment:
sdk: ^3.6.0

dependencies:
analyzer: ^6.9.0
analyzer: '>=6.9.0 <8.0.0'
async: ^2.5.0
build: ^2.1.0
dart_style: ^2.3.7
dart_style: '>=2.3.7 <4.0.0'
glob: ^2.0.0
path: ^1.8.0
pub_semver: ^2.1.4
Expand All @@ -29,7 +29,8 @@ dev_dependencies:
test: ^1.16.0

dependency_overrides:
analyzer: ^7.1.0
analyzer:
path: /Users/scheglov/Source/Dart/sdk.git/sdk/pkg/analyzer
build:
git:
url: https://github.com/dart-lang/build.git
Comment on lines 31 to 36
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should just delete this section, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, definitely need to use an actual published analyzer.
I need to know if the general approach looks good to you.
If it is, I will publish the analyzer, and update the dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I don't see any objections, so I will move forward with publishing the required analyzer version.
https://dart-review.googlesource.com/c/sdk/+/403264

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh...I haven't had time to reason about this change yet, honestly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is ETA for reviewing this?

Expand Down
Loading
Loading