Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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`
Copy link
Contributor

Choose a reason for hiding this comment

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

We should mention the new API here

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 wrote something, but I'm not sure if this is exactly what you expected.

- `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
Copy link
Member

Choose a reason for hiding this comment

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

GeneratorForAnnotation should be extends-able but not implements-able.
This is base, right?

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.

Copy link
Member

Choose a reason for hiding this comment

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

I think we can skip this for now if checks is the only known usage that needs it. I can add it later if it becomes necessary.

We will need to be careful not to break internal uses of this and document carefully the impact when we publish externally since this is fairly subtle and it isn't clear in source code exactly when it will matter.

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:
Copy link
Member

Choose a reason for hiding this comment

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

Gotta drop all of these, right?

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
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