Skip to content

Handle analyzer 8#1300

Merged
rrousselGit merged 1 commit intomasterfrom
analyzer8
Sep 9, 2025
Merged

Handle analyzer 8#1300
rrousselGit merged 1 commit intomasterfrom
analyzer8

Conversation

@rrousselGit
Copy link
Copy Markdown
Owner

@rrousselGit rrousselGit commented Sep 9, 2025

Summary by CodeRabbit

  • Breaking Changes

    • Requires analyzer ^8.0.0 and source_gen ^4.0.0; older versions are no longer supported.
    • Minor public API adjustments in analyzer-facing utilities (e.g., element/library types and error “diagnostics” naming).
  • Refactor

    • Migrated internals to the latest analyzer Element API for improved compatibility and future-proofing.
  • Chores

    • Updated dependencies; added pub_semver.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 9, 2025

Walkthrough

Migrates the codebase from analyzer Element2-era APIs to the current Element API. Updates imports, types, accessors, extensions, and several public signatures across core sources and templates. Adjusts error handling in tests to use diagnostics. Bumps dependencies (analyzer ^8, source_gen ^4) and adds pub_semver.

Changes

Cohort / File(s) Summary
Core AST and Models API migration
packages/freezed/lib/src/ast.dart, packages/freezed/lib/src/models.dart, packages/freezed/lib/src/parse_generator.dart
Switched imports to element.dart; replaced Element2/…2 types and members with Element-era equivalents (methods/getters/name, typeParameters, library). Updated extensions and public method signatures (e.g., ParserGenerator.generateForAnnotatedElement now takes Element).
Templates migration
packages/freezed/lib/src/templates/concrete_template.dart, packages/freezed/lib/src/templates/parameter_template.dart, packages/freezed/lib/src/templates/properties.dart, packages/freezed/lib/src/templates/prototypes.dart
Updated analyzer imports; migrated TypeParameterElement2/ConstructorElement2 to current types; adjusted metadata access (metadata.annotations); updated displayed strings and names; one public method signature change in Property.copyWith (TypeParameterElement?).
Tools migration
packages/freezed/lib/src/tools/imports.dart, packages/freezed/lib/src/tools/recursive_import_locator.dart, packages/freezed/lib/src/tools/type.dart
Migrated LibraryElement2/Element2 to new types; updated transitive import/export traversal APIs; revised type resolution to new alias/element accessors; changed public signatures (findTransitiveExportWhere, anyTransitiveExport, findAllAvailableTopLevelElements, resolveFullTypeStringFrom).
Dependency updates
packages/freezed/pubspec.yaml
analyzer constraint set to ^8.0.0; source_gen to ^4.0.0; added pub_semver ^2.2.0.
Tests updated for diagnostics and new element API
packages/freezed/test/*.dart
Replaced ErrorsResult.errors with .diagnostics; updated element API usages (name3→name, fields2→fields, getters, constructors, alias.element); adjusted expected diagnostic code access (diagnosticCode.name).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks (1 passed, 2 inconclusive)

❌ Failed checks (2 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The title “Handle analyzer 8” does reference the upgrade to analyzer version 8, but it is too generic and does not clearly summarize the extensive migration of APIs and signature updates performed across the codebase. Consider renaming the title to explicitly reflect the core change, for example “Migrate Freezed AST and models to Analyzer v8 API,” to make the scope and intent of the PR immediately clear.
Description Check ❓ Inconclusive The pull request currently lacks a descriptive summary of the changes in its description, making it difficult to verify alignment with the broad set of migrations applied. Please add or expand the PR description to include a concise overview of the key API migrations, signature changes, and updated dependencies introduced to support analyzer 8.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

In burrows of code I hop with delight,
From Element2’s dusk to Element’s bright light.
Diagnostics now whisper where errors once cried,
Imports all tidy, templates aligned.
Thump goes my paw—version eight in sight!
Carrot-shaped commits, and tests all right. 🥕✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch analyzer8

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rrousselGit rrousselGit marked this pull request as ready for review September 9, 2025 13:26
@rrousselGit rrousselGit merged commit 7ee3153 into master Sep 9, 2025
3 of 4 checks passed
@rrousselGit rrousselGit deleted the analyzer8 branch September 9, 2025 13:37
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/freezed/test/typedef_parameter_test.dart (1)

18-24: Fix wrong file path passed to getErrors (will cause false negatives/positives)

The generated file is typedef_parameter.freezed.dart, not typedef_parameter_test.freezed.dart. Current path will not match the resolved library and may yield spurious results.

Apply:

-    final errorResult =
-        await main.session.getErrors(
-              '/freezed/test/integration/typedef_parameter_test.freezed.dart',
-            )
+    final errorResult =
+        await main.session.getErrors(
+              '/freezed/test/integration/typedef_parameter.freezed.dart',
+            )
             as ErrorsResult;
packages/freezed/lib/src/parse_generator.dart (1)

66-70: Shadowing parameter ‘annotation’ causes a compile-time error.
A local variable redeclares the method parameter. Rename the local to avoid the collision.

Apply this diff:

-    final annotation = typeChecker.firstAnnotationOf(
+    final dartObject = typeChecker.firstAnnotationOf(
       element,
       throwOnUnresolved: false,
     );
-    if (annotation == null) return;
+    if (dartObject == null) return;
@@
-    final datas = <AnnotationMeta>[(declaration: ast, annotation: annotation)];
+    final datas = <AnnotationMeta>[(declaration: ast, annotation: dartObject)];

Also applies to: 90-91

packages/freezed/lib/src/tools/type.dart (1)

42-50: Guard against null imported libraries.
importedLibrary can be null on invalid imports; avoid a potential NPE.

Apply this diff:

-  final owner = originLibrary.firstFragment.prefixes.firstWhereOrNull((e) {
-    return e.imports.any((l) {
-      return l.importedLibrary!.anyTransitiveExport((library) {
-        return library.id == _getElementForType(type)?.library?.id;
-      });
-    });
-  });
+  final owner = originLibrary.firstFragment.prefixes.firstWhereOrNull((e) {
+    return e.imports.any((l) {
+      final imported = l.importedLibrary;
+      if (imported == null) return false;
+      return imported.anyTransitiveExport(
+        (library) => library.id == _getElementForType(type)?.library?.id,
+      );
+    });
+  });
🧹 Nitpick comments (12)
packages/freezed/lib/src/templates/concrete_template.dart (1)

525-542: Guard against null constant values when scanning annotations.
computeConstantValue() can return null; avoid ! to prevent crashes on unexpected/invalid annotations. Also minor tidy.

Apply this diff:

-    for (final meta in metadata.annotations) {
-      final obj = meta.computeConstantValue()!;
-      if (matcher.isExactlyType(obj.type!)) {
+    for (final meta in metadata.annotations) {
+      final obj = meta.computeConstantValue();
+      if (obj != null && matcher.isExactlyType(obj.type!)) {
         final source = meta.toSource();
         final res = source.substring('@Default('.length, source.length - 1);
 
-        var needsConstModifier =
+        final needsConstModifier =
             !baseElement.type.isDartCoreString &&
             !res.trimLeft().startsWith('const') &&
             (res.contains('(') || res.contains('[') || res.contains('{'));
 
-        if (needsConstModifier) {
-          return 'const $res';
-        } else {
-          return res;
-        }
+        return needsConstModifier ? 'const $res' : res;
       }
     }
packages/freezed/lib/src/templates/prototypes.dart (1)

44-46: Make default-constructor check robust (avoid relying solely on 'new')

Depending on analyzer versions, the unnamed constructor may surface as name == '' and/or as 'new' for tear-offs. Prefer handling both.

Apply:

-bool isDefaultConstructor(ConstructorElement constructor) {
-  return constructor.name == 'new';
-}
+bool isDefaultConstructor(ConstructorElement constructor) {
+  // Support both unnamed constructor ('') and tear-off surface ('new').
+  return constructor.name.isEmpty || constructor.name == 'new';
+}
packages/freezed/lib/src/templates/properties.dart (1)

117-118: Remove parameterElement from Property.copyWith. It’s unused in the body and no callers pass it.

packages/freezed/lib/src/templates/parameter_template.dart (1)

38-42: Avoid unnecessary null-assert on TypeParameterElement.name

name is non-null for type parameters; drop ! to reduce noise.

-    return GenericsParameterTemplate(generics.map((e) => e.name!).toList());
+    return GenericsParameterTemplate(generics.map((e) => e.name).toList());
packages/freezed/test/decorator_test.dart (2)

36-37: Prefer element.name for readability

LibraryElement.library.name equals LibraryElement.name. Use the direct property.

-          (element) => element.library.name == 'decorator',
+          (element) => element.name == 'decorator',

53-59: Make assertion order-insensitive; don’t rely on .last

Annotation order can change; assert presence instead.

-      expect(unmodifiableGetter.metadata.annotations.length, 2);
-      expect(unmodifiableGetter.metadata.annotations.last.toSource(), '@Foo()');
+      expect(unmodifiableGetter.metadata.annotations.length, 2);
+      expect(
+        unmodifiableGetter.metadata.annotations.map((a) => a.toSource()),
+        contains('@Foo()'),
+      );
packages/freezed/lib/src/ast.dart (2)

32-35: Ignore static methods when checking toString

Static toString shouldn’t count as a customized instance toString.

-      for (final method in type.methods) {
-        if (method.name == 'toString') {
+      for (final method in type.methods) {
+        if (!method.isStatic && method.name == 'toString') {
           return true;
         }
       }

88-89: Minor: unnecessary ! if ClassElement.name is non-null

If your minimum analyzer guarantees non-null ClassElement.name, you can drop !. Otherwise, keep as-is.

-    final escapedElementName = classElement.name!.replaceAll(r'$', r'\$');
+    final escapedElementName = classElement.name.replaceAll(r'$', r'\$');
packages/freezed/lib/src/parse_generator.dart (2)

76-80: Prefer matching elements by identity, not name.
Using name equality can misidentify in edge cases; identity is simpler and safer here.

Apply this diff:

-    final Object? ast = unit.unit.declarations.firstWhereOrNull(
-      (declaration) =>
-          declaration.declaredFragment?.element.name == element.name!,
+    final Object? ast = unit.unit.declarations.firstWhereOrNull(
+      (declaration) =>
+          identical(declaration.declaredFragment?.element, element),

83-89: Tighten types and drop redundant runtime check.
Casting the local to Declaration? simplifies the flow.

Apply this diff:

-    if (ast is! Declaration) {
-      throw InvalidGenerationSourceError(
-        'Ast is not a Declaration',
-        element: element,
-      );
-    }
+    // ast is already a Declaration? above when typed accordingly

And adjust the declaration above:

-    final Object? ast = unit.unit.declarations.firstWhereOrNull(
+    final Declaration? ast = unit.unit.declarations.firstWhereOrNull(
packages/freezed/lib/src/tools/imports.dart (1)

3-34: Migration to LibraryElement-based traversal looks good; minor naming nit.
Variable names export/import can be confusing; prefer non-keyword-ish identifiers for readability.

Apply this diff:

-    LibraryElement? visitLibrary(LibraryElement library) {
+    LibraryElement? visitLibrary(LibraryElement library) {
@@
-      for (final export in library.exportedLibraries) {
-        final result = visitLibrary(export);
+      for (final exported in library.exportedLibraries) {
+        final result = visitLibrary(exported);
         if (result != null) return result;
       }
@@
-    for (final import in exportedLibraries) {
-      final result = visitLibrary(import);
+    for (final exportedLibrary in exportedLibraries) {
+      final result = visitLibrary(exportedLibrary);
       if (result != null) return result;
     }
packages/freezed/lib/src/tools/type.dart (1)

64-73: Use display strings for typedef type arguments.
Joining DartType directly relies on toString; prefer getDisplayString() for consistency.

Apply this diff:

-    if (type.alias!.typeArguments.isNotEmpty) {
-      displayType += '<${type.alias!.typeArguments.join(', ')}>';
-    }
+    if (type.alias!.typeArguments.isNotEmpty) {
+      final args = type.alias!.typeArguments
+          .map((t) => t.getDisplayString())
+          .join(', ');
+      displayType += '<$args>';
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 03f180c and ff20326.

📒 Files selected for processing (25)
  • packages/freezed/lib/src/ast.dart (3 hunks)
  • packages/freezed/lib/src/models.dart (26 hunks)
  • packages/freezed/lib/src/parse_generator.dart (3 hunks)
  • packages/freezed/lib/src/templates/concrete_template.dart (2 hunks)
  • packages/freezed/lib/src/templates/parameter_template.dart (4 hunks)
  • packages/freezed/lib/src/templates/properties.dart (3 hunks)
  • packages/freezed/lib/src/templates/prototypes.dart (2 hunks)
  • packages/freezed/lib/src/tools/imports.dart (1 hunks)
  • packages/freezed/lib/src/tools/recursive_import_locator.dart (7 hunks)
  • packages/freezed/lib/src/tools/type.dart (4 hunks)
  • packages/freezed/pubspec.yaml (1 hunks)
  • packages/freezed/test/bidirectional_test.dart (1 hunks)
  • packages/freezed/test/common.dart (2 hunks)
  • packages/freezed/test/common_types_test.dart (1 hunks)
  • packages/freezed/test/decorator_test.dart (3 hunks)
  • packages/freezed/test/deep_copy_test.dart (3 hunks)
  • packages/freezed/test/generic_test.dart (1 hunks)
  • packages/freezed/test/generics_refs_test.dart (1 hunks)
  • packages/freezed/test/json_test.dart (1 hunks)
  • packages/freezed/test/map_test.dart (2 hunks)
  • packages/freezed/test/multiple_constructors_test.dart (10 hunks)
  • packages/freezed/test/optional_maybe_test.dart (1 hunks)
  • packages/freezed/test/single_class_constructor_test.dart (5 hunks)
  • packages/freezed/test/typedef_parameter_test.dart (2 hunks)
  • packages/freezed/test/when_test.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-01-07T20:51:22.701Z
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.

Applied to files:

  • packages/freezed/lib/src/templates/concrete_template.dart
  • packages/freezed/pubspec.yaml
  • packages/freezed/lib/src/templates/parameter_template.dart
  • packages/freezed/lib/src/templates/properties.dart
📚 Learning: 2025-01-07T20:51:22.701Z
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version upgrade in freezed_lint is blocked by invertase/dart_custom_lint#300 which handles the broader upgrade of analyzer, analyzer_plugin, and source_gen dependencies in custom_lint.

Applied to files:

  • packages/freezed/lib/src/templates/concrete_template.dart
  • packages/freezed/pubspec.yaml
  • packages/freezed/lib/src/templates/prototypes.dart
  • packages/freezed/lib/src/templates/properties.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: freezed (packages/freezed, stable, get)
🔇 Additional comments (55)
packages/freezed/test/map_test.dart (2)

306-306: Switch to diagnostics API looks correct.
Assertion updated to errorResult.diagnostics; matches analyzer v8.


427-427: Same here — diagnostics usage LGTM.
Keeps the intent of the test.

packages/freezed/pubspec.yaml (2)

13-13: Bump analyzer to ^8.0.0 — OK. Matches SDK constraint (>=3.8.0). Please verify locally by running

dart pub upgrade --major-versions
dart pub outdated --mode=null-safety

to ensure there are no transitive compatibility issues.


18-18: Approve source_gen and source_gen_test version updates
Both dependencies are declared (source_gen ^4.0.0 and source_gen_test ^1.2.0); no issues found. Run generator tests to confirm compatibility.

packages/freezed/test/bidirectional_test.dart (1)

23-23: Diagnostics assertion LGTM.
Keeps the zero-issues contract.

packages/freezed/test/when_test.dart (1)

305-305: Updated to diagnostics — good.
Maintains the “errors present” check under the new API.

packages/freezed/test/deep_copy_test.dart (3)

34-34: Diagnostics empty check — OK.
Matches analyzer v8.


52-52: Diagnostics empty check — OK (#2).
Consistent with above.


737-740: Use of diagnosticCode for name assertion looks correct.
Reads diagnostic identifiers reliably after API migration.

packages/freezed/test/json_test.dart (1)

755-755: Update lingering pre-v8 API usages

  • packages/freezed_lint/lib/src/tools/element_extensions.dart: remove import 'package:analyzer/dart/element/element2.dart' (line 1)
  • packages/freezed_lint/lib/src/missing_private_empty_ctor.dart: replace fields2 (line 33) and AnalysisError parameters (lines 61–62)
  • packages/freezed_lint/lib/src/missing_mixin.dart: replace AnalysisError parameters (lines 50–51)
  • packages/freezed/test/json_test.dart: replace definedNames2 usage (line 26)
⛔ Skipped due to learnings
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version upgrade in freezed_lint is blocked by invertase/dart_custom_lint#300 which handles the broader upgrade of analyzer, analyzer_plugin, and source_gen dependencies in custom_lint.
packages/freezed/test/generics_refs_test.dart (1)

24-24: Diagnostics empty check — OK.
Matches the rest of the suite.

packages/freezed/lib/src/templates/concrete_template.dart (1)

2-2: Import migrated to element.dart — good.
Consistent with Element API.

packages/freezed/test/optional_maybe_test.dart (1)

24-24: LGTM: switched to diagnostics

The API migration to use ErrorsResult.diagnostics looks correct here.

packages/freezed/test/common_types_test.dart (1)

28-28: LGTM: diagnostics assertion

Updated assertion to diagnostics is consistent with analyzer ^8.

packages/freezed/lib/src/templates/prototypes.dart (1)

1-1: LGTM: Element API import

element2 → element import aligns with analyzer ^8.

packages/freezed/lib/src/templates/properties.dart (2)

2-2: LGTM: Element API import

element2 → element import is correct.


55-62: Verify non-null element.name and metadata access

  • Confirm that every FormalParameterElement in your use cases has a non-null name. By language design, constructor parameters (including field‐formals) always carry a declared name. No further guarding is needed here.
  • Ensure element.metadata.annotations remains the correct API in analyzer ^8; update to element.metadata or element.annotations only if compilation errors surface.
packages/freezed/test/common.dart (2)

25-27: LGTM: diagnostics-based filtering

Collecting Severity.error diagnostics is the right mapping for throwsCompileError.


36-36: LGTM: CompileError now carries Diagnostic

Type update aligns with analyzer ^8 diagnostics.

packages/freezed/test/generic_test.dart (1)

55-55: LGTM: diagnostics assertion

Matches the new ErrorsResult API.

packages/freezed/test/single_class_constructor_test.dart (5)

3-3: LGTM: Element API import

element.dart import is correct for analyzer ^8.


28-28: LGTM: analyze() return type

Future matches the new API usage.


214-236: LGTM: PropertyAccessorElement API usage

name and documentationComment checks against PropertyAccessorElement work with analyzer ^8.


382-382: LGTM: diagnostics assertion

Consistent with ErrorsResult.diagnostics.


654-656: LGTM: diagnostic text assertion

Mapping diagnostics to strings for contains(...) is fine.

packages/freezed/test/typedef_parameter_test.dart (1)

24-24: LGTM: diagnostics assertion

Once the path is corrected, this assertion matches analyzer ^8.

packages/freezed/lib/src/templates/parameter_template.dart (1)

72-80: Confirm metadata adapter type: Element vs AST annotations

parseDecorators(e.metadata.annotations) assumes a wrapper exposing .annotations. For FormalParameterElement, analyzer exposes List<ElementAnnotation> metadata. Please verify your adapter normalizes both cases; otherwise pass e.metadata directly.

packages/freezed/test/multiple_constructors_test.dart (5)

5-5: Analyzer Element API import migration looks correct.


26-41: ClassElement/getField migration reads well.
Switch to ClassElement and getField plus InterfaceType assertions are consistent with analyzer 8.


66-117: Accessor/field expectations updated correctly.
Using PropertyAccessorElement/FieldElement with name/documentation checks aligns with the new API.


178-185: Diagnostics API update is correct.
ErrorsResult.diagnostics is the right property with analyzer 8.


576-596: Type display assertions look consistent.
The getDisplayString() expectations for nested collections match the migration elsewhere.

Also applies to: 602-621, 629-645

packages/freezed/lib/src/tools/type.dart (1)

85-91: Dynamic fallback for InvalidType looks correct.
Using element.library.typeProvider.dynamicType is the right provider with analyzer 8.

packages/freezed/lib/src/tools/recursive_import_locator.dart (6)

1-4: LGTM! Analyzer API migration is correctly implemented.

The migration from LibraryElement2 to LibraryElement aligns with the analyzer ^8 upgrade mentioned in the PR objectives.


14-14: Return type updated correctly.

The public API change from Iterable<Element2> to Iterable<Element> is consistent with the analyzer migration.


26-31: Internal helper signature and yield statement updated properly.

The migration to Element type and use of children accessor is appropriate for the new analyzer API.


35-35: Library directive accessors migrated correctly.

The change from libraryExports2/libraryImports2 to libraryExports/libraryImports follows the new analyzer API conventions.

Also applies to: 39-39


58-59: Element name accessor updated correctly.

The migration from element.name3 to element.name is consistent with the new analyzer API. The visibility filtering logic remains functionally equivalent.


73-73: Library resolution properties migrated successfully.

The changes from exportedLibrary2/importedLibrary2 to exportedLibrary/importedLibrary and the LibraryElement field type update are all correct for the analyzer ^8 migration.

Also applies to: 94-94, 116-116

packages/freezed/lib/src/models.dart (16)

7-7: Element import and extension target updated correctly.

The migration from Element2 to Element in the import and the extension definition is properly implemented.

Also applies to: 30-37


39-42: Constructor element extensions migrated properly.

The extension now correctly targets ConstructorElement instead of ConstructorElement2. The use of name property (line 41, 54) is appropriate for the new API.

Also applies to: 54-54


100-102: Type element handling updated correctly.

The migration properly handles:

  • typeElement being cast to ClassElement (lines 100-101)
  • Using parameter.name! and typeElement.name! (lines 119, 122)

These changes align with the new analyzer API structure.

Also applies to: 119-120, 122-122


272-272: Redirected constructor name access updated.

The change from redirectedConstructor?.type.name2.lexeme to redirectedConstructor?.type.name.lexeme is correct for the new API.


286-286: Parameter name access migrated correctly.

The change to element.name! is appropriate for accessing parameter names in the new API.


321-321: Library URI access updated correctly.

The change to element.baseElement.library?.uri properly accesses the library URI in the new analyzer API.


426-427: Public API signatures for annotations updated.

The migration of parseAll methods to accept ConstructorElement instead of ConstructorElement2 is implemented correctly for both ImplementsAnnotation and WithAnnotation.

Also applies to: 453-456


439-439: Library resolution in annotations updated.

Both uses of constructor.library (instead of constructor.library2) are correct for resolving type strings.

Also applies to: 466-466


525-525: Super mixin name comparison updated.

The change from name2 to name with .lexeme accessor is appropriate.


555-555: Library getter type updated correctly.

The return type change from LibraryElement2 to LibraryElement aligns with the analyzer migration.


573-573: Field and type parameter access migrated properly.

The changes correctly use:

  • element.fields instead of element.fields2
  • element.typeParameters instead of element.typeParameters2
  • Direct field name access with p.name!

All align with the new analyzer API.

Also applies to: 679-680, 683-684, 686-686


748-748: Type name extraction updated.

The use of name.lexeme to extract type names from NamedType elements is correct.


836-839: Metadata extraction pattern updated for new API.

The pattern matching for metadata with Fragment(metadata:) and Element(metadata:) cases properly handles the new analyzer API structure for accessing annotations.


868-870: Library and type system access updated.

The migration correctly uses:

  • element.library for accessing the library
  • library.typeSystem and library.typeProvider for type operations

These changes align with the new analyzer API conventions.

Also applies to: 924-924, 970-970


1067-1067: Field element API usage updated.

The migration properly handles:

  • FieldElement type (line 1067)
  • field.setter accessor (line 1072)
  • field.getter properties and methods (lines 1081-1083)

All changes are consistent with the analyzer ^8 API.

Also applies to: 1072-1072, 1081-1083


1135-1135: Library import checking extensions updated.

The extension now correctly:

  • Targets LibraryElement instead of LibraryElement2
  • Uses the updated findAllAvailableTopLevelElements() method
  • Accesses element.name and element.library with the new API patterns

The import checking logic for JsonSerializable and Diagnosticable remains functionally equivalent.

Also applies to: 1138-1138, 1363-1377

Comment on lines 63 to 76
String get fullName {
final classElement = declaredFragment!.element.enclosingElement2;
final classElement = declaredFragment!.element.enclosingElement;

var generics = classElement.typeParameters2
.map((e) => '\$${e.name3}')
var generics = classElement.typeParameters
.map((e) => '\$${e.name}')
.join(', ');
if (generics.isNotEmpty) {
generics = '<$generics>';
}

final className = classElement.enclosingElement2.name3;
final className = classElement.enclosingElement.name;

return name == null ? '$className$generics' : '$className$generics.$name';
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: fullName uses the library name instead of the class name

classElement.enclosingElement.name returns the library’s name. Use the class element’s name.

   String get fullName {
     final classElement = declaredFragment!.element.enclosingElement;
 
     var generics = classElement.typeParameters
         .map((e) => '\$${e.name}')
         .join(', ');
     if (generics.isNotEmpty) {
       generics = '<$generics>';
     }
 
-    final className = classElement.enclosingElement.name;
+    final className = classElement.name!;
 
     return name == null ? '$className$generics' : '$className$generics.$name';
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String get fullName {
final classElement = declaredFragment!.element.enclosingElement2;
final classElement = declaredFragment!.element.enclosingElement;
var generics = classElement.typeParameters2
.map((e) => '\$${e.name3}')
var generics = classElement.typeParameters
.map((e) => '\$${e.name}')
.join(', ');
if (generics.isNotEmpty) {
generics = '<$generics>';
}
final className = classElement.enclosingElement2.name3;
final className = classElement.enclosingElement.name;
return name == null ? '$className$generics' : '$className$generics.$name';
}
String get fullName {
final classElement = declaredFragment!.element.enclosingElement;
var generics = classElement.typeParameters
.map((e) => '\$${e.name}')
.join(', ');
if (generics.isNotEmpty) {
generics = '<$generics>';
}
final className = classElement.name!;
return name == null ? '$className$generics' : '$className$generics.$name';
}
🤖 Prompt for AI Agents
In packages/freezed/lib/src/ast.dart around lines 63 to 76, the code grabs the
enclosingElement (library) instead of the class element so className becomes the
library name; change the code so classElement refers to
declaredFragment!.element (the class element) and use classElement.name for the
className, keeping the existing handling of typeParameters/generics and adding a
null-safe fallback (e.g., empty string) if name is null to avoid crashes.

Comment on lines 13 to 18
factory GenericsDefinitionTemplate.fromGenericElement(
List<TypeParameterElement2> generics,
List<TypeParameterElement> generics,
) {
return GenericsDefinitionTemplate(
generics.map((e) => e.displayString2()).toList(),
generics.map((e) => e.displayString()).toList(),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Include type parameter bounds explicitly; displayString() can drop/alter them

Relying on TypeParameterElement.displayString() may omit or format bounds/nullability inconsistently. Build the string from name and bound for deterministic output.

Apply:

   factory GenericsDefinitionTemplate.fromGenericElement(
     List<TypeParameterElement> generics,
   ) {
     return GenericsDefinitionTemplate(
-      generics.map((e) => e.displayString()).toList(),
+      generics
+          .map((e) {
+            final name = e.name;
+            final bound = e.bound;
+            if (bound != null) {
+              final b = bound.getDisplayString(withNullability: false);
+              return '$name extends $b';
+            }
+            return name;
+          })
+          .toList(),
     );
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
factory GenericsDefinitionTemplate.fromGenericElement(
List<TypeParameterElement2> generics,
List<TypeParameterElement> generics,
) {
return GenericsDefinitionTemplate(
generics.map((e) => e.displayString2()).toList(),
generics.map((e) => e.displayString()).toList(),
);
factory GenericsDefinitionTemplate.fromGenericElement(
List<TypeParameterElement> generics,
) {
return GenericsDefinitionTemplate(
generics
.map((e) {
final name = e.name;
final bound = e.bound;
if (bound != null) {
final b = bound.getDisplayString(withNullability: false);
return '$name extends $b';
}
return name;
})
.toList(),
);
}
🤖 Prompt for AI Agents
In packages/freezed/lib/src/templates/parameter_template.dart around lines
13–18, the code uses TypeParameterElement.displayString(), which can omit or
alter bounds and nullability; change it to construct each type parameter string
deterministically from the element's name and its bound: use e.name, and if
e.bound is non-null append " extends " plus the bound's display string with
nullability preserved (e.g. getDisplayString(withNullability: true)); keep the
resulting list/ordering the same and return that list to the
GenericsDefinitionTemplate constructor.

Comment on lines +42 to 44
var constructor = freezedClass.constructors.firstWhere(
(element) => element.name == 'new',
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Sanity check: constructor selector uses name == 'new'

If analyzer exposes the unnamed constructor as 'new' in constructors, this is fine. Otherwise, consider also accepting name.isEmpty for robustness (mirrors suggestion in prototypes.dart).

You can confirm with:


🏁 Script executed:

#!/bin/bash
# Inspect constructors surfaced for the target class in the analyzed library (string-based quick check)
rg -nP -C2 'class\s+_ClassWithTypedef\s' test/integration/typedef_parameter.dart

Length of output: 79


🏁 Script executed:

#!/bin/bash
set -e
echo "Files matching typedef_parameter_test.dart:"
fd typedef_parameter_test.dart

Length of output: 93


🏁 Script executed:

#!/bin/bash
set -e
echo "Inspect occurrences of ClassWithTypedef in the test file:"
rg -nP -C3 'ClassWithTypedef' -n packages/freezed/test/typedef_parameter_test.dart

Length of output: 258


🏁 Script executed:

#!/bin/bash
set -e
echo "Directories matching 'integration':"
fd -t d '*integration*' || true

echo
echo "Search for 'integration' in Dart files:"
rg -n 'integration' --type dart || true

Length of output: 8311


#!/bin/bash
set -e
if [ -d "packages/freezed/test/integration" ]; then
  echo "Listing contents of packages/freezed/test/integration:"
  ls -1 packages/freezed/test/integration
else
  echo "Directory does not exist: packages/freezed/test/integration"
fi

#!/bin/bash
set -e
echo "Checking existence of integration file:"
if [ -f "packages/freezed/test/integration/typedef_parameter.dart" ]; then
  echo "Found typedef_parameter.dart, displaying first 200 lines:"
  sed -n '1,200p' packages/freezed/test/integration/typedef_parameter.dart
else
  echo "File not found: packages/freezed/test/integration/typedef_parameter.dart"
  exit 1
fi

🏁 Script executed:

#!/bin/bash
set -e
echo "Listing packages/freezed/test directory:"
ls -1 packages/freezed/test

Length of output: 674


#!/bin/bash
set -e
echo "Contents of packages/freezed/test/integration directory:"
ls -1 packages/freezed/test/integration

echo
echo "Display first 200 lines of typedef_parameter.dart if it exists:"
if [ -f packages/freezed/test/integration/typedef_parameter.dart ]; then
  sed -n '1,200p' packages/freezed/test/integration/typedef_parameter.dart
else
  echo "File not found: packages/freezed/test/integration/typedef_parameter.dart"
fi

🏁 Script executed:

#!/bin/bash
set -e
echo "Listing packages/freezed/test/integration directory:"
ls -1 packages/freezed/test/integration

echo
echo "Checking for typedef_parameter.dart:"
if [ -f packages/freezed/test/integration/typedef_parameter.dart ]; then
  echo "Displaying first 200 lines of typedef_parameter.dart:"
  sed -n '1,200p' packages/freezed/test/integration/typedef_parameter.dart
else
  echo "File not found: packages/freezed/test/integration/typedef_parameter.dart"
fi

Length of output: 1359


Support unnamed constructor detection
In typedef_parameter_test.dart, update the constructor selector to detect the unnamed constructor (whose name is an empty string) instead of—or in addition to—matching 'new'. e.g.:

var constructor = freezedClass.constructors.firstWhere(
  (element) => element.name.isEmpty, // unnamed constructor
);
🤖 Prompt for AI Agents
In packages/freezed/test/typedef_parameter_test.dart around lines 42 to 44, the
test currently selects a constructor by matching element.name == 'new' which
fails for unnamed constructors whose name is an empty string; update the
selector to detect unnamed constructors by checking element.name.isEmpty (or
allow both by checking name == 'new' || name.isEmpty) so the test finds the
unnamed constructor correctly.

rrousselGit added a commit that referenced this pull request Sep 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

freezed ^3.2.0 requires build ^3.0.0. build_runner ^2.8.0 requires build ^4.0.0. please update it to accept build ^4.0.0. Support source_gen 4

1 participant