diff --git a/analysis_options.yaml b/analysis_options.yaml index 808e60ab..421c3ad6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -5,9 +5,6 @@ analyzer: strict-casts: true strict-inference: true strict-raw-types: true - errors: - # analyzer deprecations - deprecated_member_use: ignore linter: rules: diff --git a/example/lib/src/member_count_library_generator.dart b/example/lib/src/member_count_library_generator.dart index 110b3ac6..b5e7afaf 100644 --- a/example/lib/src/member_count_library_generator.dart +++ b/example/lib/src/member_count_library_generator.dart @@ -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; '''; } diff --git a/example/lib/src/multiplier_generator.dart b/example/lib/src/multiplier_generator.dart index c6ec4aed..d061e59f 100644 --- a/example/lib/src/multiplier_generator.dart +++ b/example/lib/src/multiplier_generator.dart @@ -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'; @@ -11,12 +11,12 @@ import '../annotations.dart'; class MultiplierGenerator extends GeneratorForAnnotation { @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;'; } } diff --git a/example/lib/src/property_product_generator.dart b/example/lib/src/property_product_generator.dart index d2fdd582..5317e0c4 100644 --- a/example/lib/src/property_product_generator.dart +++ b/example/lib/src/property_product_generator.dart @@ -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; diff --git a/example/lib/src/property_sum_generator.dart b/example/lib/src/property_sum_generator.dart index c73e9768..cc4b297a 100644 --- a/example/lib/src/property_sum_generator.dart +++ b/example/lib/src/property_sum_generator.dart @@ -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; diff --git a/example/lib/src/utils.dart b/example/lib/src/utils.dart index 06d2cbfb..aad73b91 100644 --- a/example/lib/src/utils.dart +++ b/example/lib/src/utils.dart @@ -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 topLevelNumVariables(LibraryReader reader) => - reader.allElements.whereType().where( +Iterable topLevelNumVariables(LibraryReader reader) => + reader.allElements.whereType().where( (element) => element.type.isDartCoreNum || element.type.isDartCoreInt || diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 05e715e3..d7b97fd3 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -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: diff --git a/source_gen/CHANGELOG.md b/source_gen/CHANGELOG.md index 7faa6a51..bdfba01d 100644 --- a/source_gen/CHANGELOG.md +++ b/source_gen/CHANGELOG.md @@ -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 diff --git a/source_gen/lib/src/builder.dart b/source_gen/lib/src/builder.dart index 0bf126f2..1bcbfbdd 100644 --- a/source_gen/lib/src/builder.dart +++ b/source_gen/lib/src/builder.dart @@ -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'; @@ -109,7 +109,7 @@ class _Builder extends Builder { } Future _generateForLibrary( - LibraryElement library, + LibraryElement2 library, BuildStep buildStep, ) async { final generatedOutputs = @@ -355,7 +355,7 @@ class LibraryBuilder extends _Builder { } Stream _generate( - LibraryElement library, + LibraryElement2 library, List generators, BuildStep buildStep, ) async* { @@ -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 ? '' diff --git a/source_gen/lib/src/constants/reader.dart b/source_gen/lib/src/constants/reader.dart index bf53938c..6e6501c4 100644 --- a/source_gen/lib/src/constants/reader.dart +++ b/source_gen/lib/src/constants/reader.dart @@ -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'; @@ -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; diff --git a/source_gen/lib/src/constants/revive.dart b/source_gen/lib/src/constants/revive.dart index 499e4471..fa83436b 100644 --- a/source_gen/lib/src/constants/revive.dart +++ b/source_gen/lib/src/constants/revive.dart @@ -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; @@ -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}', ); } } @@ -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; @@ -79,10 +81,11 @@ 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, ); @@ -90,12 +93,12 @@ Revivable reviveInstance(DartObject object, [LibraryElement? origin]) { 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; diff --git a/source_gen/lib/src/constants/utils.dart b/source_gen/lib/src/constants/utils.dart index e1846fe4..a557f1fb 100644 --- a/source_gen/lib/src/constants/utils.dart +++ b/source_gen/lib/src/constants/utils.dart @@ -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 - ')}', ); } diff --git a/source_gen/lib/src/generator.dart b/source_gen/lib/src/generator.dart index b29121c4..72483a92 100644 --- a/source_gen/lib/src/generator.dart +++ b/source_gen/lib/src/generator.dart @@ -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'; @@ -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. /// diff --git a/source_gen/lib/src/generator_for_annotation.dart b/source_gen/lib/src/generator_for_annotation.dart index e3728c56..7b41f133 100644 --- a/source_gen/lib/src/generator_for_annotation.dart +++ b/source_gen/lib/src/generator_for_annotation.dart @@ -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'; @@ -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 extends Generator { final bool throwOnUnresolved; @@ -54,6 +54,21 @@ abstract class GeneratorForAnnotation extends Generator { FutureOr generate(LibraryReader library, BuildStep buildStep) async { final values = {}; + 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, @@ -90,8 +105,34 @@ abstract class GeneratorForAnnotation 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, - ); + ) {} } diff --git a/source_gen/lib/src/library.dart b/source_gen/lib/src/library.dart index f13b13e5..f25a0e1d 100644 --- a/source_gen/lib/src/library.dart +++ b/source_gen/lib/src/library.dart @@ -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:path/path.dart' as p; @@ -10,37 +10,41 @@ 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; - final Element element; + final Element2 element; const AnnotatedElement(this.annotation, this.element); } -/// A high-level wrapper API with common functionality for [LibraryElement]. +/// A high-level wrapper API with common functionality for [LibraryElement2]. class LibraryReader { - final LibraryElement element; + final LibraryElement2 element; LibraryReader(this.element); - /// Returns a top-level [ClassElement] publicly visible in by [name]. + /// Returns a top-level [ClassElement2] publicly visible in by [name]. /// - /// Unlike [LibraryElement.getClass], this also correctly traverses + /// Unlike [LibraryElement2.getClass2], this also correctly traverses /// identifiers that are accessible via one or more `export` directives. - ClassElement? findType(String name) { - final type = element.exportNamespace.get(name); - return type is ClassElement ? type : null; + ClassElement2? findType(String name) { + final type = element.exportNamespace.get2(name); + return type is ClassElement2 ? type : null; } /// All of the declarations in this library. - Iterable get allElements => [ - element, - ...element.topLevelElements, - ...element.definingCompilationUnit.libraryImports, - ...element.definingCompilationUnit.libraryExports, - ...element.definingCompilationUnit.parts, - ]; + Iterable get allElements => [element, ...element.children2]; /// All of the declarations in this library annotated with [checker]. Iterable annotatedWith( @@ -58,6 +62,30 @@ class LibraryReader { } } + /// All of the directives in this library annotated with [checker]. + Iterable libraryDirectivesAnnotatedWith( + TypeChecker checker, { + bool throwOnUnresolved = true, + }) sync* { + final firstFragment = element.firstFragment; + final directives = [ + ...firstFragment.libraryImports2, + ...firstFragment.libraryExports2, + ...firstFragment.partIncludes, + ]; + + for (final directive in directives) { + final annotation = checker.firstAnnotationOf( + directive, + throwOnUnresolved: throwOnUnresolved, + ); + + if (annotation != null) { + yield AnnotatedDirective(ConstantReader(annotation), directive); + } + } + } + /// All of the declarations in this library annotated with exactly [checker]. Iterable annotatedWithExact( TypeChecker checker, { @@ -84,7 +112,7 @@ class LibraryReader { /// /// This is a typed convenience function for using [pathToUrl], and the same /// API restrictions hold around supported schemes and relative paths. - Uri pathToElement(Element element) => pathToUrl(element.source!.uri); + Uri pathToElement(Element2 element) => pathToUrl(element.library2!.uri); /// Returns a [Uri] from the current library to the one provided. /// @@ -122,7 +150,7 @@ class LibraryReader { if (to.pathSegments.length > 1 && to.pathSegments[1] == 'lib') { return assetToPackageUrl(to); } - var from = element.source.uri; + var from = element.uri; // Normalize (convert to an asset: URL). from = normalizeUrl(from); if (_isRelative(from, to)) { @@ -160,9 +188,8 @@ class LibraryReader { } /// All of the elements representing classes in this library. - Iterable get classes => - element.units.expand((cu) => cu.classes); + Iterable get classes => element.classes; /// All of the elements representing enums in this library. - Iterable get enums => element.units.expand((cu) => cu.enums); + Iterable get enums => element.enums; } diff --git a/source_gen/lib/src/span_for_element.dart b/source_gen/lib/src/span_for_element.dart index ec2292a2..a0dd38ef 100644 --- a/source_gen/lib/src/span_for_element.dart +++ b/source_gen/lib/src/span_for_element.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:source_span/source_span.dart'; import 'utils.dart'; @@ -19,40 +19,47 @@ import 'utils.dart'; /// /// Not all results from the analyzer API may return source information as part /// of the element, so [file] may need to be manually provided in those cases. -SourceSpan spanForElement(Element element, [SourceFile? file]) { - final url = assetToPackageUrl(element.source!.uri); +SourceSpan spanForElement(Element2 element, [SourceFile? file]) { + final fragment = element.firstFragment; + final url = assetToPackageUrl(fragment.libraryFragment!.source.uri); if (file == null) { - final contents = element.source?.contents; + final contents = fragment.libraryFragment?.source.contents; if (contents == null) { return SourceSpan( - SourceLocation(element.nameOffset, sourceUrl: url), - SourceLocation(element.nameOffset + element.nameLength, sourceUrl: url), - element.name!, + SourceLocation(fragment.nameOffset2!, sourceUrl: url), + SourceLocation( + fragment.nameOffset2! + fragment.name2!.length, + sourceUrl: url, + ), + fragment.name2!, ); } file = SourceFile.fromString(contents.data, url: url); } - if (element.nameOffset < 0) { - if (element is PropertyInducingElement) { - if (element.getter != null) { - return spanForElement(element.getter!); + if (fragment.nameOffset2 == null) { + if (element is PropertyInducingElement2) { + if (element.getter2 != null) { + return spanForElement(element.getter2!); } - if (element.setter != null) { - return spanForElement(element.setter!); + if (element.setter2 != null) { + return spanForElement(element.setter2!); } } } - return file.span(element.nameOffset, element.nameOffset + element.nameLength); + return file.span( + fragment.nameOffset2!, + fragment.nameOffset2! + fragment.name2!.length, + ); } /// Returns a source span that spans the location where [node] is written. SourceSpan spanForNode(AstNode node) { final unit = node.thisOrAncestorOfType()!; - final element = unit.declaredElement!; - final contents = element.source.contents.data; - final url = assetToPackageUrl(element.source.uri); + final unitFragment = unit.declaredFragment!; + final contents = unitFragment.source.contents.data; + final url = assetToPackageUrl(unitFragment.source.uri); final file = SourceFile.fromString(contents, url: url); return file.span(node.offset, node.offset + node.length); } diff --git a/source_gen/lib/src/type_checker.dart b/source_gen/lib/src/type_checker.dart index 496430c0..8b6617c0 100644 --- a/source_gen/lib/src/type_checker.dart +++ b/source_gen/lib/src/type_checker.dart @@ -7,7 +7,7 @@ import 'dart:mirrors' hide SourceLocation; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/ast/ast.dart'; 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 'package:build/build.dart'; import 'package:source_span/source_span.dart'; @@ -62,11 +62,14 @@ abstract class TypeChecker { /// /// Throws on unresolved annotations unless [throwOnUnresolved] is `false`. DartObject? firstAnnotationOf( - Element element, { + Object element, { bool throwOnUnresolved = true, }) { - if (element.metadata.isEmpty) { - return null; + if (element case final Annotatable annotatable) { + final annotations = annotatable.metadata2.annotations; + if (annotations.isEmpty) { + return null; + } } final results = annotationsOf( element, @@ -78,7 +81,7 @@ abstract class TypeChecker { /// Returns if a constant annotating [element] is assignable to this type. /// /// Throws on unresolved annotations unless [throwOnUnresolved] is `false`. - bool hasAnnotationOf(Element element, {bool throwOnUnresolved = true}) => + bool hasAnnotationOf(Element2 element, {bool throwOnUnresolved = true}) => firstAnnotationOf(element, throwOnUnresolved: throwOnUnresolved) != null; /// Returns the first constant annotating [element] that is exactly this type. @@ -86,35 +89,42 @@ abstract class TypeChecker { /// Throws [UnresolvedAnnotationException] on unresolved annotations unless /// [throwOnUnresolved] is explicitly set to `false` (default is `true`). DartObject? firstAnnotationOfExact( - Element element, { + Element2 element, { bool throwOnUnresolved = true, }) { - if (element.metadata.isEmpty) { - return null; + if (element case final Annotatable annotatable) { + final annotations = annotatable.metadata2.annotations; + if (annotations.isEmpty) { + return null; + } + final results = annotationsOfExact( + element, + throwOnUnresolved: throwOnUnresolved, + ); + return results.isEmpty ? null : results.first; } - final results = annotationsOfExact( - element, - throwOnUnresolved: throwOnUnresolved, - ); - return results.isEmpty ? null : results.first; + return null; } /// Returns if a constant annotating [element] is exactly this type. /// /// Throws [UnresolvedAnnotationException] on unresolved annotations unless /// [throwOnUnresolved] is explicitly set to `false` (default is `true`). - bool hasAnnotationOfExact(Element element, {bool throwOnUnresolved = true}) => + bool hasAnnotationOfExact( + Element2 element, { + bool throwOnUnresolved = true, + }) => firstAnnotationOfExact(element, throwOnUnresolved: throwOnUnresolved) != null; DartObject? _computeConstantValue( - Element element, + Object element, + ElementAnnotation annotation, int annotationIndex, { bool throwOnUnresolved = true, }) { - final annotation = element.metadata[annotationIndex]; final result = annotation.computeConstantValue(); - if (result == null && throwOnUnresolved) { + if (result == null && throwOnUnresolved && element is Element2) { throw UnresolvedAnnotationException._from(element, annotationIndex); } return result; @@ -125,7 +135,7 @@ abstract class TypeChecker { /// Throws [UnresolvedAnnotationException] on unresolved annotations unless /// [throwOnUnresolved] is explicitly set to `false` (default is `true`). Iterable annotationsOf( - Element element, { + Object element, { bool throwOnUnresolved = true, }) => _annotationsWhere( element, @@ -134,18 +144,22 @@ abstract class TypeChecker { ); Iterable _annotationsWhere( - Element element, + Object element, bool Function(DartType) predicate, { bool throwOnUnresolved = true, }) sync* { - for (var i = 0; i < element.metadata.length; i++) { - final value = _computeConstantValue( - element, - i, - throwOnUnresolved: throwOnUnresolved, - ); - if (value?.type != null && predicate(value!.type!)) { - yield value; + if (element case final Annotatable annotatable) { + final annotations = annotatable.metadata2.annotations; + for (var i = 0; i < annotations.length; i++) { + final value = _computeConstantValue( + element, + annotations[i], + i, + throwOnUnresolved: throwOnUnresolved, + ); + if (value?.type != null && predicate(value!.type!)) { + yield value; + } } } } @@ -155,7 +169,7 @@ abstract class TypeChecker { /// Throws [UnresolvedAnnotationException] on unresolved annotations unless /// [throwOnUnresolved] is explicitly set to `false` (default is `true`). Iterable annotationsOfExact( - Element element, { + Element2 element, { bool throwOnUnresolved = true, }) => _annotationsWhere( element, @@ -164,25 +178,26 @@ abstract class TypeChecker { ); /// Returns `true` if the type of [element] can be assigned to this type. - bool isAssignableFrom(Element element) => + bool isAssignableFrom(Element2 element) => isExactly(element) || - (element is InterfaceElement && element.allSupertypes.any(isExactlyType)); + (element is InterfaceElement2 && + element.allSupertypes.any(isExactlyType)); /// Returns `true` if [staticType] can be assigned to this type. bool isAssignableFromType(DartType staticType) { - final element = staticType.element; + final element = staticType.element3; return element != null && isAssignableFrom(element); } /// Returns `true` if representing the exact same class as [element]. - bool isExactly(Element element); + bool isExactly(Element2 element); /// Returns `true` if representing the exact same type as [staticType]. /// /// This will always return false for types without a backingclass such as /// `void` or function types. bool isExactlyType(DartType staticType) { - final element = staticType.element; + final element = staticType.element3; if (element != null) { return isExactly(element); } else { @@ -194,8 +209,8 @@ abstract class TypeChecker { /// /// This check only takes into account the *extends* hierarchy. If you wish /// to check mixins and interfaces, use [isAssignableFrom]. - bool isSuperOf(Element element) { - if (element is InterfaceElement) { + bool isSuperOf(Element2 element) { + if (element is InterfaceElement2) { var theSuper = element.supertype; do { @@ -214,7 +229,7 @@ abstract class TypeChecker { /// /// This only takes into account the *extends* hierarchy. If you wish /// to check mixins and interfaces, use [isAssignableFromType]. - bool isSuperTypeOf(DartType staticType) => isSuperOf(staticType.element!); + bool isSuperTypeOf(DartType staticType) => isSuperOf(staticType.element3!); } // Checks a static type against another static type; @@ -224,11 +239,11 @@ class _LibraryTypeChecker extends TypeChecker { const _LibraryTypeChecker(this._type) : super._(); @override - bool isExactly(Element element) => - element is InterfaceElement && element == _type.element; + bool isExactly(Element2 element) => + element is InterfaceElement2 && element == _type.element3; @override - String toString() => urlOfElement(_type.element!); + String toString() => urlOfElement(_type.element3!); } // Checks a runtime type against a static type. @@ -248,7 +263,7 @@ class _MirrorTypeChecker extends TypeChecker { _cache[this] ??= TypeChecker.fromUrl(_uriOf(reflectClass(_type))); @override - bool isExactly(Element element) => _computed.isExactly(element); + bool isExactly(Element2 element) => _computed.isExactly(element); @override String toString() => _computed.toString(); @@ -278,7 +293,7 @@ class _UriTypeChecker extends TypeChecker { (url is String ? url : normalizeUrl(url as Uri).toString()); @override - bool isExactly(Element element) => hasSameUrl(urlOfElement(element)); + bool isExactly(Element2 element) => hasSameUrl(urlOfElement(element)); @override String toString() => '$uri'; @@ -290,7 +305,8 @@ class _AnyChecker extends TypeChecker { const _AnyChecker(this._checkers) : super._(); @override - bool isExactly(Element element) => _checkers.any((c) => c.isExactly(element)); + bool isExactly(Element2 element) => + _checkers.any((c) => c.isExactly(element)); } /// Exception thrown when [TypeChecker] fails to resolve a metadata annotation. @@ -301,24 +317,23 @@ class _AnyChecker extends TypeChecker { /// defined (for build systems such as Bazel). class UnresolvedAnnotationException implements Exception { /// Element that was annotated with something we could not resolve. - final Element annotatedElement; + final Element2 annotatedElement; /// Source span of the annotation that was not resolved. /// /// May be `null` if the import library was not found. final SourceSpan? annotationSource; - static SourceSpan? _findSpan(Element annotatedElement, int annotationIndex) { + static SourceSpan? _findSpan(Element2 annotatedElement, int annotationIndex) { try { final parsedLibrary = - annotatedElement.session!.getParsedLibraryByElement( - annotatedElement.library!, + annotatedElement.session!.getParsedLibraryByElement2( + annotatedElement.library2!, ) as ParsedLibraryResult; - ElementDeclarationResult? declaration; - try { - declaration = parsedLibrary.getElementDeclaration(annotatedElement); - } catch (_) {} + final declaration = parsedLibrary.getFragmentDeclaration( + annotatedElement.firstFragment, + ); if (declaration == null) { return null; } @@ -360,9 +375,9 @@ the version of `package:source_gen`, `package:analyzer` from `pubspec.lock`. } /// Creates an exception from an annotation ([annotationIndex]) that was not - /// resolvable while traversing [Element.metadata] on [annotatedElement]. + /// resolvable while traversing `metadata2` on [annotatedElement]. factory UnresolvedAnnotationException._from( - Element annotatedElement, + Element2 annotatedElement, int annotationIndex, ) { final sourceSpan = _findSpan(annotatedElement, annotationIndex); diff --git a/source_gen/lib/src/utils.dart b/source_gen/lib/src/utils.dart index 1a847426..a94ed91b 100644 --- a/source_gen/lib/src/utils.dart +++ b/source_gen/lib/src/utils.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:build/build.dart'; import 'package:path/path.dart' as p; @@ -20,20 +20,20 @@ import 'package:yaml/yaml.dart'; /// typedef VoidFunc = void Function(); /// ``` /// -/// This function will return `'VoidFunc'`, unlike [DartType.element]`.name`. +/// This function will return `'VoidFunc'`, unlike [DartType.element3]`.name3`. String typeNameOf(DartType type) { - final aliasElement = type.alias?.element; + final aliasElement = type.alias?.element2; if (aliasElement != null) { - return aliasElement.name; + return aliasElement.name3!; } if (type is DynamicType) { return 'dynamic'; } if (type is InterfaceType) { - return type.element.name; + return type.element3.name3!; } if (type is TypeParameterType) { - return type.element.name; + return type.element3.name3!; } throw UnimplementedError('(${type.runtimeType}) $type'); } @@ -44,7 +44,7 @@ bool hasExpectedPartDirective(CompilationUnit unit, String part) => unit .any((e) => e.uri.stringValue == part); /// Returns a uri suitable for `part of "..."` when pointing to [element]. -String uriOfPartial(LibraryElement element, AssetId source, AssetId output) { +String uriOfPartial(LibraryElement2 element, AssetId source, AssetId output) { assert(source.package == output.package); return p.url.relative(source.path, from: p.url.dirname(output.path)); } @@ -57,13 +57,13 @@ String computePartUrl(AssetId input, AssetId output) => p.url.joinAll( ); /// Returns a URL representing [element]. -String urlOfElement(Element element) => +String urlOfElement(Element2 element) => element.kind == ElementKind.DYNAMIC ? 'dart:core#dynamic' // using librarySource.uri – in case the element is in a part : normalizeUrl( - element.librarySource!.uri, - ).replace(fragment: element.name).toString(); + element.library2!.uri, + ).replace(fragment: element.name3).toString(); Uri normalizeUrl(Uri url) => switch (url.scheme) { 'dart' => normalizeDartUrl(url), diff --git a/source_gen/pubspec.yaml b/source_gen/pubspec.yaml index 1fcc21c0..3e3c68f7 100644 --- a/source_gen/pubspec.yaml +++ b/source_gen/pubspec.yaml @@ -1,5 +1,5 @@ name: source_gen -version: 2.0.1-wip +version: 3.0.0-dev description: >- Source code generation builders and utilities for the Dart build system repository: https://github.com/dart-lang/source_gen/tree/master/source_gen @@ -11,7 +11,7 @@ environment: dependencies: analyzer: '>=6.9.0 <8.0.0' async: ^2.5.0 - build: ^2.5.0 + build: ^3.0.0-dev dart_style: '>=2.3.7 <4.0.0' glob: ^2.0.0 path: ^1.8.0 @@ -22,7 +22,7 @@ dependencies: dev_dependencies: _test_annotations: path: ../_test_annotations - build_test: ^3.1.1 + build_test: ^3.3.0-dev dart_flutter_team_lints: ^3.1.0 logging: ^1.0.0 term_glyph: ^1.2.0 diff --git a/source_gen/test/constants/utils_test.dart b/source_gen/test/constants/utils_test.dart index e08c0101..563109af 100644 --- a/source_gen/test/constants/utils_test.dart +++ b/source_gen/test/constants/utils_test.dart @@ -3,14 +3,14 @@ // 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:build_test/build_test.dart'; import 'package:source_gen/src/constants/utils.dart'; import 'package:test/test.dart'; void main() { group('assertHasField', () { - late LibraryElement testLib; + late LibraryElement2 testLib; setUpAll(() async { testLib = await resolveSource( @@ -34,17 +34,17 @@ void main() { }); test('should not throw when a class contains a field', () { - final $A = testLib.getClass('A')!; + final $A = testLib.getClass2('A')!; expect(() => assertHasField($A, 'a'), returnsNormally); }); test('should not throw when a super class contains a field', () { - final $B = testLib.getClass('B')!; + final $B = testLib.getClass2('B')!; expect(() => assertHasField($B, 'a'), returnsNormally); }); test('should throw when a class does not contain a field', () { - final $C = testLib.getClass('C')!; + final $C = testLib.getClass2('C')!; expect(() => assertHasField($C, 'a'), throwsFormatException); }); }); @@ -84,8 +84,9 @@ void main() { ); objects = testLib - .getClass('Example')! - .metadata + .getClass2('Example')! + .metadata2 + .annotations .map((e) => e.computeConstantValue()!) .toList(); }); diff --git a/source_gen/test/constants_test.dart b/source_gen/test/constants_test.dart index bd9fc430..f9196b56 100644 --- a/source_gen/test/constants_test.dart +++ b/source_gen/test/constants_test.dart @@ -59,8 +59,9 @@ void main() { ''', (resolver) async => (await resolver.findLibraryByName('test_lib'))!); constants = library - .getClass('Example')! - .metadata + .getClass2('Example')! + .metadata2 + .annotations .map((e) => ConstantReader(e.computeConstantValue()!)) .toList(); }); @@ -154,7 +155,7 @@ void main() { test('should read a Type', () { expect(constants[11].isType, isTrue); - expect(constants[11].typeValue.element!.name, 'DateTime'); + expect(constants[11].typeValue.element3!.name3, 'DateTime'); expect(constants[11].isLiteral, isFalse); expect(() => constants[11].literalValue, throwsFormatException); }); @@ -297,8 +298,9 @@ void main() { ''', (resolver) async => (await resolver.findLibraryByName('test_lib'))!); constants = library - .getClass('Example')! - .metadata + .getClass2('Example')! + .metadata2 + .annotations .map((e) => ConstantReader(e.computeConstantValue())) .toList(); }); diff --git a/source_gen/test/external_only_type_checker_test.dart b/source_gen/test/external_only_type_checker_test.dart index f527b3f4..7499856e 100644 --- a/source_gen/test/external_only_type_checker_test.dart +++ b/source_gen/test/external_only_type_checker_test.dart @@ -56,7 +56,7 @@ void main() { expect( checkNonPublic().isExactlyType(staticNonPublic), isTrue, - reason: '${checkNonPublic()} != ${staticNonPublic.element.name}', + reason: '${checkNonPublic()} != ${staticNonPublic.element3.name3}', ); }); @@ -66,7 +66,7 @@ void main() { isTrue, reason: '${checkNonPublic()} is not assignable from ' - '${staticNonPublic.element.name}', + '${staticNonPublic.element3.name3}', ); }); }); diff --git a/source_gen/test/generator_for_annotation_test.dart b/source_gen/test/generator_for_annotation_test.dart index 85082a10..3e00181d 100644 --- a/source_gen/test/generator_for_annotation_test.dart +++ b/source_gen/test/generator_for_annotation_test.dart @@ -8,7 +8,7 @@ library; import 'package:analyzer/dart/analysis/utilities.dart'; 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:build_test/build_test.dart'; import 'package:source_gen/source_gen.dart'; @@ -28,7 +28,7 @@ void main() { test(entry.key, () async { final generator = _StubGenerator( 'Value', - (_) => entry.value, + elementBehavior: (_) => entry.value, ); final builder = LibraryBuilder(generator); await testBuilder(builder, _inputMap, outputs: {}); @@ -37,10 +37,13 @@ void main() { }); test('Supports and dedupes multiple return values', () async { - final generator = _StubGenerator('Repeating', (element) sync* { - yield '// There are deprecated values in this library!'; - yield '// ${element.name}'; - }); + final generator = _StubGenerator( + 'Repeating', + elementBehavior: (element) sync* { + yield '// There are deprecated values in this library!'; + yield '// ${element.name3}'; + }, + ); final builder = LibraryBuilder(generator); await testBuilder( builder, @@ -69,15 +72,19 @@ $dartFormatWidth group('handles errors correctly', () { for (var entry in { - 'sync errors': _StubGenerator('Failing', (_) { - throw StateError('not supported!'); - }), - 'from iterable': _StubGenerator('FailingIterable', ( - _, - ) sync* { - yield '// There are deprecated values in this library!'; - throw StateError('not supported!'); - }), + 'sync errors': _StubGenerator( + 'Failing', + elementBehavior: (_) { + throw StateError('not supported!'); + }, + ), + 'from iterable': _StubGenerator( + 'FailingIterable', + elementBehavior: (_) sync* { + yield '// There are deprecated values in this library!'; + throw StateError('not supported!'); + }, + ), }.entries) { test(entry.key, () async { final builder = LibraryBuilder(entry.value); @@ -96,7 +103,7 @@ $dartFormatWidth 'Does not resolve the library if there are no top level annotations', () async { final builder = LibraryBuilder( - _StubGenerator('Deprecated', (_) => null), + _StubGenerator('Deprecated', elementBehavior: (_) => null), ); final input = AssetId('a', 'lib/a.dart'); final assets = {input: 'main() {}'}; @@ -123,7 +130,7 @@ $dartFormatWidth final builder = LibraryBuilder( _StubGenerator( 'Deprecated', - (element) => '// ${element.displayName}', + elementBehavior: (element) => '// ${element.displayName}', ), ); await testBuilder( @@ -153,7 +160,13 @@ $dartFormatWidth final builder = LibraryBuilder( _StubGenerator( 'Deprecated', - (element) => '// ${element.runtimeType}', + directiveBehavior: + (element) => switch (element) { + LibraryImport() => '// LibraryImport', + LibraryExport() => '// LibraryExport', + PartInclude() => '// PartInclude', + }, + elementBehavior: (element) => '// ${element.runtimeType}', ), ); await testBuilder( @@ -180,11 +193,11 @@ $dartFormatWidth // Generator: Deprecated // ************************************************************************** -// LibraryImportElementImpl +// LibraryImport -// LibraryExportElementImpl +// LibraryExport -// PartElementImpl +// PartInclude ''', }, ); @@ -195,7 +208,7 @@ $dartFormatWidth final builder = LibraryBuilder( _StubGenerator( 'Deprecated', - (element) => '// ${element.displayName}', + elementBehavior: (element) => '// ${element.displayName}', ), ); final logs = []; @@ -225,7 +238,7 @@ $dartFormatWidth final builder = LibraryBuilder( _StubGenerator( 'Deprecated', - (element) => '// ${element.displayName}', + elementBehavior: (element) => '// ${element.displayName}', throwOnUnresolved: false, ), ); @@ -244,19 +257,34 @@ $dartFormatWidth class _StubGenerator extends GeneratorForAnnotation { final String _name; - final Object? Function(Element) _behavior; + final Object? Function(ElementDirective) directiveBehavior; + final Object? Function(Element2) elementBehavior; + + const _StubGenerator( + this._name, { + this.directiveBehavior = _returnNull, + required this.elementBehavior, + super.throwOnUnresolved, + }); - const _StubGenerator(this._name, this._behavior, {super.throwOnUnresolved}); + @override + Object? generateForAnnotatedDirective( + ElementDirective directive, + ConstantReader annotation, + BuildStep buildStep, + ) => directiveBehavior(directive); @override Object? generateForAnnotatedElement( - Element element, + Element2 element, ConstantReader annotation, BuildStep buildStep, - ) => _behavior(element); + ) => elementBehavior(element); @override String toString() => _name; + + static Null _returnNull(Object _) => null; } const _inputMap = { @@ -295,7 +323,7 @@ class _TestingResolver implements ReleasableResolver { } @override - Future libraryFor( + Future libraryFor( AssetId assetId, { bool allowSyntaxErrors = false, }) async { diff --git a/source_gen/test/library/find_type_test.dart b/source_gen/test/library/find_type_test.dart index 8fdf376a..4095d8a0 100644 --- a/source_gen/test/library/find_type_test.dart +++ b/source_gen/test/library/find_type_test.dart @@ -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:build_test/build_test.dart'; import 'package:source_gen/source_gen.dart'; @@ -44,11 +44,11 @@ void main() { }); test('class count', () { - expect(library.classes.map((c) => c.name), ['Example', 'PartClass']); + expect(library.classes.map((c) => c.name3), ['Example', 'PartClass']); }); test('enum count', () { - expect(library.enums.map((e) => e.name), ['Enum', 'PartEnum']); + expect(library.enums.map((e) => e.name3), ['Enum', 'PartEnum']); }); test('should return a type not exported', () { @@ -72,4 +72,4 @@ void main() { }); } -const _isClassElement = TypeMatcher(); +const _isClassElement = TypeMatcher(); diff --git a/source_gen/test/library/path_to_url_test.dart b/source_gen/test/library/path_to_url_test.dart index a8d77c50..c94e8415 100644 --- a/source_gen/test/library/path_to_url_test.dart +++ b/source_gen/test/library/path_to_url_test.dart @@ -3,8 +3,7 @@ // BSD-style license that can be found in the LICENSE file. // Increase timeouts on this test which resolves source code and can be slow. -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/source/source.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:source_gen/source_gen.dart'; import 'package:test/test.dart'; @@ -158,24 +157,14 @@ void main() { }); } -class _FakeLibraryElement implements LibraryElement { - final Uri _sourceUri; +class _FakeLibraryElement implements LibraryElement2 { + final Uri _uri; - _FakeLibraryElement(this._sourceUri); + _FakeLibraryElement(this._uri); @override dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); @override - Source get source => _FakeSource(_sourceUri); -} - -class _FakeSource implements Source { - @override - final Uri uri; - - const _FakeSource(this.uri); - - @override - dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); + Uri get uri => _uri; } diff --git a/source_gen/test/span_for_element_test.dart b/source_gen/test/span_for_element_test.dart index 11a6b426..f85eb138 100644 --- a/source_gen/test/span_for_element_test.dart +++ b/source_gen/test/span_for_element_test.dart @@ -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:build_test/build_test.dart'; import 'package:source_gen/src/span_for_element.dart'; @@ -11,7 +11,7 @@ import 'package:test/test.dart'; void main() { glyph.ascii = true; - late LibraryElement library; + late LibraryElement2 library; late Resolver resolver; setUpAll(() async { @@ -39,7 +39,7 @@ abstract class Example implements List { test('should highlight the use of "class Example"', () async { expect( - spanForElement(library.getClass('Example')!).message('Here it is'), + spanForElement(library.getClass2('Example')!).message('Here it is'), r""" line 3, column 16 of package:test_lib/test_lib.dart: Here it is , @@ -52,7 +52,7 @@ line 3, column 16 of package:test_lib/test_lib.dart: Here it is test('should correctly highlight getter', () async { expect( spanForElement( - library.getClass('Example')!.getField('getter')!, + library.getClass2('Example')!.getField2('getter')!, ).message('Here it is'), r""" line 4, column 15 of package:test_lib/test_lib.dart: Here it is @@ -66,7 +66,7 @@ line 4, column 15 of package:test_lib/test_lib.dart: Here it is test('should correctly highlight setter', () async { expect( spanForElement( - library.getClass('Example')!.getField('setter')!, + library.getClass2('Example')!.getField2('setter')!, ).message('Here it is'), r""" line 5, column 7 of package:test_lib/test_lib.dart: Here it is @@ -80,7 +80,7 @@ line 5, column 7 of package:test_lib/test_lib.dart: Here it is test('should correctly highlight field', () async { expect( spanForElement( - library.getClass('Example')!.getField('field')!, + library.getClass2('Example')!.getField2('field')!, ).message('Here it is'), r""" line 6, column 7 of package:test_lib/test_lib.dart: Here it is @@ -94,7 +94,7 @@ line 6, column 7 of package:test_lib/test_lib.dart: Here it is test('highlight getter with getter/setter property', () async { expect( spanForElement( - library.getClass('Example')!.getField('fieldProp')!, + library.getClass2('Example')!.getField2('fieldProp')!, ).message('Here it is'), r""" line 7, column 11 of package:test_lib/test_lib.dart: Here it is @@ -106,7 +106,8 @@ line 7, column 11 of package:test_lib/test_lib.dart: Here it is }); test('highlights based on AstNode source location', () async { - final element = library.getClass('Example')!.getField('field')!.declaration; + final element = + library.getClass2('Example')!.getField2('field')!.firstFragment; final node = (await resolver.astNodeFor(element, resolve: true))!; expect(spanForNode(node).message('Here it is'), r""" line 6, column 7 of package:test_lib/test_lib.dart: Here it is diff --git a/source_gen/test/src/comment_generator.dart b/source_gen/test/src/comment_generator.dart index c37c2150..b85605b5 100644 --- a/source_gen/test/src/comment_generator.dart +++ b/source_gen/test/src/comment_generator.dart @@ -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:source_gen/source_gen.dart'; /// Generates a single-line comment for each class @@ -15,14 +15,14 @@ class CommentGenerator extends Generator { Future generate(LibraryReader library, _) async { final output = []; if (forLibrary) { - var name = library.element.name; + var name = library.element.name3!; if (name.isEmpty) { - name = library.element.source.uri.pathSegments.last; + name = library.element.uri.pathSegments.last; } output.add('// Code for "$name"'); } if (forClasses) { - for (var classElement in library.allElements.whereType()) { + for (var classElement in library.classes) { if (classElement.displayName.contains('GoodError')) { throw InvalidGenerationSourceError( "Don't use classes with the word 'Error' in the name", @@ -41,6 +41,6 @@ class CommentGenerator extends Generator { class DeprecatedGeneratorForAnnotation extends GeneratorForAnnotation { @override - String generateForAnnotatedElement(Element element, _, _) => + String generateForAnnotatedElement(Element2 element, _, _) => '// "$element" is deprecated!'; } diff --git a/source_gen/test/type_checker_test.dart b/source_gen/test/type_checker_test.dart index bb7a137d..f5307b63 100644 --- a/source_gen/test/type_checker_test.dart +++ b/source_gen/test/type_checker_test.dart @@ -10,7 +10,7 @@ library; import 'dart:collection'; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:build/build.dart'; @@ -31,7 +31,7 @@ void main() { late TypeChecker staticMapMixinChecker; late TypeChecker staticHashMapChecker; late TypeChecker staticEnumChecker; - late LibraryElement core; + late LibraryElement2 core; // Resolved top-level types from package:source_gen. late InterfaceType staticGenerator; @@ -46,9 +46,9 @@ void main() { late InterfaceType staticMyEnumWithMixin; setUpAll(() async { - late LibraryElement collection; + late LibraryElement2 collection; late LibraryReader sourceGen; - late LibraryElement testSource; + late LibraryElement2 testSource; await resolveSources( { 'source_gen|test/example.dart': r''' @@ -76,20 +76,20 @@ void main() { ); final staticIterable = core - .getClass('Iterable')! + .getClass2('Iterable')! .instantiate( typeArguments: [core.typeProvider.dynamicType], nullabilitySuffix: NullabilitySuffix.none, ); staticIterableChecker = TypeChecker.fromStatic(staticIterable); staticUri = core - .getClass('Uri')! + .getClass2('Uri')! .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ); staticMap = core - .getClass('Map')! + .getClass2('Map')! .instantiate( typeArguments: [ core.typeProvider.dynamicType, @@ -99,41 +99,41 @@ void main() { ); staticMapChecker = TypeChecker.fromStatic(staticMap); staticEnum = core - .getClass('Enum')! + .getClass2('Enum')! .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ); staticEnumChecker = TypeChecker.fromStatic(staticEnum); - staticEnumMixin = (testSource.exportNamespace.get('MyEnumMixin')! - as InterfaceElement) + staticEnumMixin = (testSource.exportNamespace.get2('MyEnumMixin')! + as InterfaceElement2) .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ); staticEnumMixinChecker = TypeChecker.fromStatic(staticEnumMixin); - staticMapMixin = (testSource.exportNamespace.get('MyMapMixin')! - as InterfaceElement) + staticMapMixin = (testSource.exportNamespace.get2('MyMapMixin')! + as InterfaceElement2) .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ); staticMapMixinChecker = TypeChecker.fromStatic(staticMapMixin); - staticMyEnum = (testSource.exportNamespace.get('MyEnum')! - as InterfaceElement) + staticMyEnum = (testSource.exportNamespace.get2('MyEnum')! + as InterfaceElement2) .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ); - staticMyEnumWithMixin = (testSource.exportNamespace.get('MyEnumWithMixin')! - as InterfaceElement) + staticMyEnumWithMixin = (testSource.exportNamespace.get2('MyEnumWithMixin')! + as InterfaceElement2) .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ); staticHashMap = collection - .getClass('HashMap')! + .getClass2('HashMap')! .instantiate( typeArguments: [ core.typeProvider.dynamicType, @@ -143,7 +143,7 @@ void main() { ); staticHashMapChecker = TypeChecker.fromStatic(staticHashMap); staticUnmodifiableListView = collection - .getClass('UnmodifiableListView')! + .getClass2('UnmodifiableListView')! .instantiate( typeArguments: [core.typeProvider.dynamicType], nullabilitySuffix: NullabilitySuffix.none, @@ -222,7 +222,7 @@ void main() { () { test('should equal MapMixin class', () { expect(checkMapMixin().isExactlyType(staticMapMixin), isTrue); - expect(checkMapMixin().isExactly(staticMapMixin.element), isTrue); + expect(checkMapMixin().isExactly(staticMapMixin.element3), isTrue); }); }, onPlatform: const { @@ -235,7 +235,7 @@ void main() { expect( checkMap().isExactlyType(staticMap), isTrue, - reason: '${checkMap()} != ${staticMap.element.name}', + reason: '${checkMap()} != ${staticMap.element3.name3}', ); }); @@ -267,7 +267,7 @@ void main() { test('should be assignable from Map', () { // Using Uri.queryParameters to get a Map final stringStringMapType = - staticUri.getGetter('queryParameters')!.returnType; + staticUri.getGetter2('queryParameters')!.returnType; expect(checkMap().isAssignableFromType(stringStringMapType), isTrue); expect(checkMap().isExactlyType(stringStringMapType), isTrue); @@ -297,7 +297,7 @@ void main() { expect( checkGenerator().isExactlyType(staticGenerator), isTrue, - reason: '${checkGenerator()} != ${staticGenerator.element.name}', + reason: '${checkGenerator()} != ${staticGenerator.element3.name3}', ); }); @@ -307,7 +307,7 @@ void main() { isFalse, reason: '${checkGenerator()} is super of ' - '${staticGenerator.element.name}', + '${staticGenerator.element3.name3}', ); }); @@ -317,7 +317,7 @@ void main() { isTrue, reason: '${checkGenerator()} is not super of ' - '${staticGeneratorForAnnotation.element.name}', + '${staticGeneratorForAnnotation.element3.name3}', ); }); @@ -327,7 +327,7 @@ void main() { isTrue, reason: '${checkGenerator()} is not assignable from ' - '${staticGeneratorForAnnotation.element.name}', + '${staticGeneratorForAnnotation.element3.name3}', ); }); }); @@ -392,7 +392,7 @@ void main() { @depracated // Intentionally mispelled. class X {} ''', (resolver) async => (await resolver.findLibraryByName('_test'))!); - final classX = library.getClass('X')!; + final classX = library.getClass2('X')!; const $deprecated = TypeChecker.fromRuntime(Deprecated); expect( @@ -423,10 +423,10 @@ void main() { late TypeChecker $B; late TypeChecker $C; - late ClassElement $ExampleOfA; - late ClassElement $ExampleOfMultiA; - late ClassElement $ExampleOfAPlusB; - late ClassElement $ExampleOfBPlusC; + late ClassElement2 $ExampleOfA; + late ClassElement2 $ExampleOfMultiA; + late ClassElement2 $ExampleOfAPlusB; + late ClassElement2 $ExampleOfBPlusC; setUpAll(() async { final library = await resolveSource(r''' @@ -462,7 +462,7 @@ void main() { $A = TypeChecker.fromStatic( library - .getClass('A')! + .getClass2('A')! .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, @@ -470,7 +470,7 @@ void main() { ); $B = TypeChecker.fromStatic( library - .getClass('B')! + .getClass2('B')! .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, @@ -478,56 +478,56 @@ void main() { ); $C = TypeChecker.fromStatic( library - .getClass('C')! + .getClass2('C')! .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ), ); - $ExampleOfA = library.getClass('ExampleOfA')!; - $ExampleOfMultiA = library.getClass('ExampleOfMultiA')!; - $ExampleOfAPlusB = library.getClass('ExampleOfAPlusB')!; - $ExampleOfBPlusC = library.getClass('ExampleOfBPlusC')!; + $ExampleOfA = library.getClass2('ExampleOfA')!; + $ExampleOfMultiA = library.getClass2('ExampleOfMultiA')!; + $ExampleOfAPlusB = library.getClass2('ExampleOfAPlusB')!; + $ExampleOfBPlusC = library.getClass2('ExampleOfBPlusC')!; }); test('of a single @A', () { expect($A.hasAnnotationOf($ExampleOfA), isTrue); final aAnnotation = $A.firstAnnotationOf($ExampleOfA)!; - expect(aAnnotation.type!.element!.name, 'A'); + expect(aAnnotation.type!.element3!.name3, 'A'); expect($B.annotationsOf($ExampleOfA), isEmpty); expect($C.annotationsOf($ExampleOfA), isEmpty); }); test('of a multiple @A', () { final aAnnotations = $A.annotationsOf($ExampleOfMultiA); - expect(aAnnotations.map((a) => a.type!.element!.name), ['A', 'A']); + expect(aAnnotations.map((a) => a.type!.element3!.name3), ['A', 'A']); expect($B.annotationsOf($ExampleOfA), isEmpty); expect($C.annotationsOf($ExampleOfA), isEmpty); }); test('of a single @A + single @B', () { final aAnnotations = $A.annotationsOf($ExampleOfAPlusB); - expect(aAnnotations.map((a) => a.type!.element!.name), ['A']); + expect(aAnnotations.map((a) => a.type!.element3!.name3), ['A']); final bAnnotations = $B.annotationsOf($ExampleOfAPlusB); - expect(bAnnotations.map((a) => a.type!.element!.name), ['B']); + expect(bAnnotations.map((a) => a.type!.element3!.name3), ['B']); expect($C.annotationsOf($ExampleOfAPlusB), isEmpty); }); test('of a single @B + single @C', () { final cAnnotations = $C.annotationsOf($ExampleOfBPlusC); - expect(cAnnotations.map((a) => a.type!.element!.name), ['C']); + expect(cAnnotations.map((a) => a.type!.element3!.name3), ['C']); final bAnnotations = $B.annotationsOf($ExampleOfBPlusC); - expect(bAnnotations.map((a) => a.type!.element!.name), ['B', 'C']); + expect(bAnnotations.map((a) => a.type!.element3!.name3), ['B', 'C']); expect($B.hasAnnotationOfExact($ExampleOfBPlusC), isTrue); final bExact = $B.annotationsOfExact($ExampleOfBPlusC); - expect(bExact.map((a) => a.type!.element!.name), ['B']); + expect(bExact.map((a) => a.type!.element3!.name3), ['B']); }); }); group('unresolved annotations', () { late TypeChecker $A; - late ClassElement $ExampleOfA; - late ParameterElement $annotatedParameter; + late ClassElement2 $ExampleOfA; + late FormalParameterElement $annotatedParameter; setUpAll(() async { final library = await resolveSource(r''' @@ -546,18 +546,17 @@ void main() { ''', (resolver) async => (await resolver.findLibraryByName('_test'))!); $A = TypeChecker.fromStatic( library - .getClass('A')! + .getClass2('A')! .instantiate( typeArguments: [], nullabilitySuffix: NullabilitySuffix.none, ), ); - $ExampleOfA = library.getClass('ExampleOfA')!; + $ExampleOfA = library.getClass2('ExampleOfA')!; $annotatedParameter = - library.topLevelElements - .whereType() - .firstWhere((f) => f.name == 'annotatedParameter') - .parameters + library.topLevelFunctions + .firstWhere((f) => f.name3 == 'annotatedParameter') + .formalParameters .single; }); @@ -601,28 +600,28 @@ void main() { $A .firstAnnotationOf($ExampleOfA, throwOnUnresolved: false)! .type! - .element! - .name, + .element3! + .name3, 'A', ); expect( $A .annotationsOf($ExampleOfA, throwOnUnresolved: false) - .map((a) => a.type!.element!.name), + .map((a) => a.type!.element3!.name3), ['A'], ); expect( $A .firstAnnotationOfExact($ExampleOfA, throwOnUnresolved: false)! .type! - .element! - .name, + .element3! + .name3, 'A', ); expect( $A .annotationsOfExact($ExampleOfA, throwOnUnresolved: false) - .map((a) => a.type!.element!.name), + .map((a) => a.type!.element3!.name3), ['A'], ); }); diff --git a/source_gen/test/utils_test.dart b/source_gen/test/utils_test.dart index 0fbe359b..d2e4d91b 100644 --- a/source_gen/test/utils_test.dart +++ b/source_gen/test/utils_test.dart @@ -6,13 +6,13 @@ @Timeout.factor(2.0) library; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:build_test/build_test.dart'; import 'package:source_gen/src/utils.dart'; import 'package:test/test.dart'; void main() { - late ClassElement example; + late ClassElement2 example; setUpAll(() async { const source = r''' @@ -30,17 +30,17 @@ void main() { source, (resolver) => resolver .findLibraryByName('example') - .then((e) => e!.getClass('Example')!), + .then((e) => e!.getClass2('Example')!), ); }); test('should return the name of a class type', () { - final classType = example.methods.first.returnType; + final classType = example.methods2.first.returnType; expect(typeNameOf(classType), 'ClassType'); }); test('should return the name of a function type', () { - final functionType = example.methods.last.returnType; + final functionType = example.methods2.last.returnType; expect(typeNameOf(functionType), 'FunctionType'); });