Skip to content

matchAnnotation and instantiateAnnotation break on extended classes #155

@thosakwe

Description

@thosakwe

Hi, I'm experiencing an error that is blocking my progress using package:source_gen. I am more than happy to submit a PR to fix it, but I'd need clearance first.

Anyways, I'm building a PostgreSQL ORM generator, driven by a few annotations. I chose to model relations the following way:

class Relationship {
  final String localKey;
  final String foreignKey;
  final String foreignTable;
  final bool cascadeOnDelete;

  const Relationship._(
      {this.localKey,
      this.foreignKey,
      this.foreignTable,
      this.cascadeOnDelete});
}

class HasMany extends Relationship {
  const HasMany(
      {String localKey,
      String foreignKey,
      String foreignTable,
      bool cascadeOnDelete: false})
      : super._(
            localKey: localKey,
            foreignKey: foreignKey,
            foreignTable: foreignTable,
            cascadeOnDelete: cascadeOnDelete == true);
}

const HasMany hasMany = const HasMany();  
// HasOne and BelongsTo (omitted here) are virtually identical to HasMany

I've written a helper findAnnotation<T> function that calls matchAnnotation and instantiateAnnotation in one go.

import 'package:analyzer/dart/element/element.dart';
import 'package:source_gen/src/annotation.dart';

T findAnnotation<T>(FieldElement field, Type outType) {
  var first = field.metadata
      .firstWhere((ann) => matchAnnotation(outType, ann), orElse: () => null);
  return first == null ? null : instantiateAnnotation(first);
}

Firstly, matchAnnotation is not able to tell that @hasMany is an instance of Relationship.
I hacked around this by instead searching for a HasMany or HasOne, etc.

But instantiateAnnotation crashes with the following error when encountering a child class:

PS C:\Users\thosa\Source\Angel\postgres> dart tool/build.dart
[INFO] Build: Reading cached dependency graph...
[INFO] Build: Reading cached dependency graph completed, took 15ms
[INFO] Build: Finalizing build setup...
[INFO] Build: Updating dependency graph with changes since last build.
[INFO] Build: Initializing inputs
[INFO] Build: Deleting previous outputs
[INFO] Build: Deleting 3 declared outputs which already existed on disk.
[INFO] Build: Finalizing build setup completed, took 192ms
[INFO] Build: Running build...
[INFO] runBuilder: Hm: make
[INFO] runBuilder: Hm: description
[INFO] runBuilder: Hm: familyFriendly
[INFO] runBuilder: Hm: recalledAt
[SEVERE] runBuilder: Error running PostgresORMGenerator for class _Car extends Model.
type 'SuperConstructorInvocationImpl' is not a subtype of type 'ConstructorFieldInitializer' in type cast where
  SuperConstructorInvocationImpl is from package:analyzer/src/dart/ast/ast.dart
  ConstructorFieldInitializer is from package:analyzer/dart/ast/ast.dart

#0      Object._as (dart:core-patch/object_patch.dart:73)
#1      _createFromConstructor.<anonymous closure> (package:source_gen/src/annotation.dart:153:30)
#2      Object&ListMixin.singleWhere (dart:collection/list.dart:155)
#3      _createFromConstructor (package:source_gen/src/annotation.dart:152:51)
#4      instantiateAnnotation (package:source_gen/src/annotation.dart:44:12)
#5      findAnnotation (package:angel_orm/src/builder/find_annotation.dart:7:33)
#6      buildContext (package:angel_orm/src/builder/postgres/build_context.dart:27:11)
#7      PostgresORMGenerator.generateForAnnotatedElement (package:angel_orm/src/builder/postgres/postgres.dart:31:9)
#8      GeneratorForAnnotation.generate (package:source_gen/src/generator_for_annotation.dart:34:12)
#9      _processUnitMember (package:source_gen/src/builder.dart:119:35)
<asynchronous suspension>
#10     _generate (package:source_gen/src/builder.dart:110:12)
<asynchronous suspension>
#11     GeneratorBuilder._generateForLibrary (package:source_gen/src/builder.dart:55:15)
<asynchronous suspension>
#12     GeneratorBuilder.build (package:source_gen/src/builder.dart:40:11)
<asynchronous suspension>
#13     runBuilder.buildForInput (package:build/src/generate/run_builder.dart:35:21)
<asynchronous suspension>
#14     MappedListIterable.elementAt (dart:_internal/iterable.dart:413)
#15     ListIterator.moveNext (dart:_internal/iterable.dart:342)
#16     Future.wait (dart:async/future.dart:355)
#17     runBuilder.<anonymous closure> (package:build/src/generate/run_builder.dart:41:31)
#18     _rootRun (dart:async/zone.dart:1120)
#19     _CustomZone.run (dart:async/zone.dart:1001)
#20     runZoned (dart:async/zone.dart:1467)
#21     scopeLog (package:build/src/builder/logging.dart:12:38)
#22     runBuilder (package:build/src/generate/run_builder.dart:41:9)
<asynchronous suspension>
#23     BuildImpl._runBuilder (package:build_runner/src/generate/build_impl.dart:554:13)
<asynchronous suspension>
#24     BuildImpl._runPhases.<anonymous closure> (package:build_runner/src/generate/build_impl.dart:442:34)
<asynchronous suspension>
#25     MappedListIterable.elementAt (dart:_internal/iterable.dart:413)
#26     ListIterator.moveNext (dart:_internal/iterable.dart:342)
#27     Future.wait (dart:async/future.dart:355)
#28     BuildImpl._runPhases (package:build_runner/src/generate/build_impl.dart:440:20)
<asynchronous suspension>
#29     logWithTime (package:build_runner/src/logging/logging.dart:19:28)
<asynchronous suspension>
#30     BuildImpl.runBuild.<anonymous closure> (package:build_runner/src/generate/build_impl.dart:146:26)
<asynchronous suspension>
#31     Chain.capture.<anonymous closure> (package:stack_trace/src/chain.dart:93:24)
#32     _rootRun (dart:async/zone.dart:1120)
#33     _CustomZone.run (dart:async/zone.dart:1001)
#34     runZoned (dart:async/zone.dart:1467)
#35     Chain.capture (package:stack_trace/src/chain.dart:91:12)
#36     BuildImpl.runBuild (package:build_runner/src/generate/build_impl.dart:78:11)
<asynchronous suspension>
#37     build (package:build_runner/src/generate/build.dart:65:32)
<asynchronous suspension>
#38     main (file:///C:/Users/thosa/Source/Angel/postgres/tool/build.dart:4:11)
#39     _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:265)
#40     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:151)

[INFO] Build: Running build completed, took 2420ms
[INFO] Build: Caching finalized dependency graph...
[INFO] Build: Caching finalized dependency graph completed, took 14ms
[INFO] Build: Succeeded after 2659ms with 3 outputs

Is there any way to support annotations that are extended from other classes, or is this currently impossible?

Thanks in advance for your response, and thanks for all the hard work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions