Skip to content
Merged
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
3 changes: 0 additions & 3 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ analyzer:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
# analyzer deprecations
deprecated_member_use: ignore

linter:
rules:
Expand Down
2 changes: 1 addition & 1 deletion example/lib/src/member_count_library_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MemberCountLibraryGenerator extends Generator {
final topLevelVarCount = topLevelNumVariables(library).length;

return '''
// Source library: ${library.element.source.uri}
// Source library: ${library.element.uri}
const topLevelNumVarCount = $topLevelVarCount;
''';
}
Expand Down
6 changes: 3 additions & 3 deletions example/lib/src/multiplier_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';

Expand All @@ -11,12 +11,12 @@ import '../annotations.dart';
class MultiplierGenerator extends GeneratorForAnnotation<Multiplier> {
@override
String generateForAnnotatedElement(
Element element,
Element2 element,
ConstantReader annotation,
BuildStep buildStep,
) {
final numValue = annotation.read('value').literalValue as num;

return 'num ${element.name}Multiplied() => ${element.name} * $numValue;';
return 'num ${element.name3}Multiplied() => ${element.name3} * $numValue;';
}
}
2 changes: 1 addition & 1 deletion example/lib/src/property_product_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class PropertyProductGenerator extends Generator {
String generate(LibraryReader library, BuildStep buildStep) {
final productNames = topLevelNumVariables(
library,
).map((element) => element.name).join(' * ');
).map((element) => element.name3).join(' * ');

return '''
num allProduct() => $productNames;
Expand Down
2 changes: 1 addition & 1 deletion example/lib/src/property_sum_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class PropertySumGenerator extends Generator {
String generate(LibraryReader library, BuildStep buildStep) {
final sumNames = topLevelNumVariables(
library,
).map((element) => element.name).join(' + ');
).map((element) => element.name3).join(' + ');

return '''
num allSum() => $sumNames;
Expand Down
8 changes: 4 additions & 4 deletions example/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:source_gen/source_gen.dart';

/// Returns all [TopLevelVariableElement] members in [reader]'s library that
/// Returns all [TopLevelVariableElement2] members in [reader]'s library that
/// have a type of [num].
Iterable<TopLevelVariableElement> topLevelNumVariables(LibraryReader reader) =>
reader.allElements.whereType<TopLevelVariableElement>().where(
Iterable<TopLevelVariableElement2> topLevelNumVariables(LibraryReader reader) =>
reader.allElements.whereType<TopLevelVariableElement2>().where(
(element) =>
element.type.isDartCoreNum ||
element.type.isDartCoreInt ||
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ environment:

dependencies:
analyzer: '>=6.9.0 <8.0.0'
build: ^2.0.0
build: ^3.0.0-dev
source_gen: any

dev_dependencies:
Expand Down
6 changes: 5 additions & 1 deletion source_gen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## 2.0.1-wip
## 3.0.0-dev

- **Breaking Change**: use the new `element2` APIs in `analyzer`. Builders that
do resolution need to switch to the new API, see
https://github.com/dart-lang/sdk/blob/main/pkg/analyzer/doc/element_model_migration_guide.md.
For questions please use https://github.com/dart-lang/build/discussions.
- Require Dart 3.7.0

## 2.0.0
Expand Down
8 changes: 4 additions & 4 deletions source_gen/lib/src/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import 'dart:convert';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:build/build.dart';
import 'package:dart_style/dart_style.dart';
import 'package:pub_semver/pub_semver.dart';
Expand Down Expand Up @@ -109,7 +109,7 @@ class _Builder extends Builder {
}

Future<void> _generateForLibrary(
LibraryElement library,
LibraryElement2 library,
BuildStep buildStep,
) async {
final generatedOutputs =
Expand Down Expand Up @@ -355,7 +355,7 @@ class LibraryBuilder extends _Builder {
}

Stream<GeneratedOutput> _generate(
LibraryElement library,
LibraryElement2 library,
List<Generator> generators,
BuildStep buildStep,
) async* {
Expand Down Expand Up @@ -426,7 +426,7 @@ const partIdRegExpLiteral = r'[A-Za-z_\d-]+';

final _partIdRegExp = RegExp('^$partIdRegExpLiteral\$');

String languageOverrideForLibrary(LibraryElement library) {
String languageOverrideForLibrary(LibraryElement2 library) {
final override = library.languageVersion.override;
return override == null
? ''
Expand Down
4 changes: 2 additions & 2 deletions source_gen/lib/src/constants/reader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';

import '../type_checker.dart';
Expand Down Expand Up @@ -268,7 +268,7 @@ class _DartObjectConstant extends ConstantReader {
ConstantReader read(String field) {
final reader = peek(field);
if (reader == null) {
assertHasField(objectValue.type!.element as InterfaceElement, field);
assertHasField(objectValue.type!.element3 as InterfaceElement2, field);
return const _NullConstant();
}
return reader;
Expand Down
43 changes: 23 additions & 20 deletions source_gen/lib/src/constants/revive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// ignore_for_file: deprecated_member_use

import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';
// ignore: implementation_imports
import 'package:analyzer/src/dart/constant/value.dart' show DartObjectImpl;
Expand All @@ -22,35 +22,37 @@ import '../utils.dart';
/// **NOTE**: Some returned [Revivable] instances are not representable as valid
/// Dart source code (such as referencing private constructors). It is up to the
/// build tool(s) using this library to surface error messages to the user.
Revivable reviveInstance(DartObject object, [LibraryElement? origin]) {
Revivable reviveInstance(DartObject object, [LibraryElement2? origin]) {
final objectType = object.type;
Element? element = objectType!.alias?.element;
Element2? element = objectType!.alias?.element2;
if (element == null) {
if (objectType is InterfaceType) {
element = objectType.element;
element = objectType.element3;
} else {
element = object.toFunctionValue();
element = object.toFunctionValue2();
}
}
origin ??= element!.library;
origin ??= element!.library2;
var url = Uri.parse(urlOfElement(element!));
if (element is FunctionElement) {
return Revivable._(source: url.removeFragment(), accessor: element.name);
if (element is TopLevelFunctionElement || element is LocalFunctionElement) {
return Revivable._(source: url.removeFragment(), accessor: element.name3!);
}
if (element is MethodElement && element.isStatic) {

if (element is MethodElement2 && element.isStatic) {
return Revivable._(
source: url.removeFragment(),
accessor: '${element.enclosingElement3.name}.${element.name}',
accessor:
'${element.firstFragment.enclosingFragment!.name2}.${element.name3}',
);
}

if (element is InterfaceElement) {
for (final e in element.fields.where(
if (element is InterfaceElement2) {
for (final e in element.fields2.where(
(f) => f.isPublic && f.isConst && f.computeConstantValue() == object,
)) {
return Revivable._(
source: url.removeFragment(),
accessor: '${element.name}.${e.name}',
accessor: '${element.name3}.${e.name3}',
);
}
}
Expand All @@ -64,13 +66,13 @@ Revivable reviveInstance(DartObject object, [LibraryElement? origin]) {
return !result.isPrivate;
}

for (final type in origin!.definingCompilationUnit.classes) {
for (final e in type.fields.where(
for (final type in origin!.classes) {
for (final e in type.fields2.where(
(f) => f.isConst && f.computeConstantValue() == object,
)) {
final result = Revivable._(
source: url.removeFragment(),
accessor: '${type.name}.${e.name}',
accessor: '${type.name3}.${e.name3}',
);
if (tryResult(result)) {
return result;
Expand All @@ -79,23 +81,24 @@ Revivable reviveInstance(DartObject object, [LibraryElement? origin]) {
}
final i = (object as DartObjectImpl).getInvocation();
if (i != null) {
url = Uri.parse(urlOfElement(i.constructor.enclosingElement3));
url = Uri.parse(urlOfElement(i.constructor2.enclosingElement2));
String newToEmpty(String string) => string == 'new' ? '' : string;
final result = Revivable._(
source: url,
accessor: i.constructor.name,
accessor: newToEmpty(i.constructor2.name3!),
namedArguments: i.namedArguments,
positionalArguments: i.positionalArguments,
);
if (tryResult(result)) {
return result;
}
}
for (final e in origin.definingCompilationUnit.topLevelVariables.where(
for (final e in origin.topLevelVariables.where(
(f) => f.isConst && f.computeConstantValue() == object,
)) {
final result = Revivable._(
source: Uri.parse(urlOfElement(origin)).replace(fragment: ''),
accessor: e.name,
accessor: e.name3!,
);
if (tryResult(result)) {
return result;
Expand Down
20 changes: 10 additions & 10 deletions source_gen/lib/src/constants/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';

/// Throws a [FormatException] if [root] does not have a given field [name].
///
/// Super types [InterfaceElement.supertype] are also checked before throwing.
void assertHasField(InterfaceElement root, String name) {
InterfaceElement? element = root;
/// Super types [InterfaceElement2.supertype] are also checked before throwing.
void assertHasField(InterfaceElement2 root, String name) {
InterfaceElement2? element = root;
while (element != null) {
final field = element.getField(name);
final field = element.getField2(name);
if (field != null) {
return;
}
element = element.supertype?.element;
element = element.supertype?.element3;
}
final allFields = {
...root.fields,
for (var t in root.allSupertypes) ...t.element.fields,
...root.fields2,
for (var t in root.allSupertypes) ...t.element3.fields2,
};

throw FormatException(
'Class ${root.name} does not have field "$name".',
'Fields: \n - ${allFields.map((e) => e.name).join('\n - ')}',
'Class ${root.name3} does not have field "$name".',
'Fields: \n - ${allFields.map((e) => e.name3).join('\n - ')}',
);
}

Expand Down
4 changes: 2 additions & 2 deletions source_gen/lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import 'dart:async';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:build/build.dart';

import 'library.dart';
Expand Down Expand Up @@ -49,7 +49,7 @@ class InvalidGenerationSource implements Exception {
///
/// May be `null` if the error had no associated element, or if the location
/// was passed with [node].
final Element? element;
final Element2? element;

/// The AST Node associated with this error.
///
Expand Down
49 changes: 45 additions & 4 deletions source_gen/lib/src/generator_for_annotation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import 'dart:async';

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:build/build.dart';

import 'constants/reader.dart';
Expand Down Expand Up @@ -38,7 +38,7 @@ import 'type_checker.dart';
/// Elements which are not at the top level, such as the members of a class or
/// extension, are not searched for annotations. To operate on, for instance,
/// annotated fields of a class ensure that the class itself is annotated with
/// [T] and use the [Element] to iterate over fields. The [TypeChecker] utility
/// [T] and use the [Element2] to iterate over fields. The [TypeChecker] utility
/// may be helpful to check which elements have a given annotation.
abstract class GeneratorForAnnotation<T> extends Generator {
final bool throwOnUnresolved;
Expand All @@ -54,6 +54,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 @@ -90,8 +105,34 @@ abstract class GeneratorForAnnotation<T> extends Generator {
/// Implementations should return `null` when no content is generated. Empty
/// or whitespace-only [String] instances are also ignored.
dynamic generateForAnnotatedElement(
Element element,
Element2 element,
ConstantReader annotation,
BuildStep buildStep,
) {}

/// Implement to return source code to generate for [directive]:
/// - [LibraryImport]
/// - [LibraryExport]
/// - [PartInclude]
///
/// 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(
ElementDirective directive,
ConstantReader annotation,
BuildStep buildStep,
);
) {}
}
Loading