generateForAnnotatedElement method

  1. @override
dynamic generateForAnnotatedElement(
  1. Element element,
  2. ConstantReader annotation,
  3. BuildStep buildStep
)

Main entry point for CherryPick field injection code generation.

  • Only triggers for classes marked with @injectable().
  • Throws an error if used on non-class elements.
  • Scans all fields marked with @inject() and gathers qualifiers (if any).
  • Generates Dart code for a mixin that injects all dependencies into the target class instance.

Returns the Dart code as a String defining the new mixin.

Example input (user code):

@injectable()
class UserBloc with _$UserBloc {
  @inject() late final AuthRepository authRepository;
}

Example output (generated):

mixin _$UserBloc {
  void _inject(UserBloc instance) {
    instance.authRepository = CherryPick.openRootScope().resolve<AuthRepository>();
  }
}

Implementation

@override
dynamic generateForAnnotatedElement(
  Element element,
  ConstantReader annotation,
  BuildStep buildStep,
) {
  if (element is! ClassElement) {
    throw InvalidGenerationSourceError(
      '@injectable() can only be applied to classes.',
      element: element,
    );
  }

  final classElement = element;
  final className = classElement.name;
  final mixinName = '_\$$className';

  AnnotationValidator.validateClassAnnotations(classElement);

  final classType = TypeParser.parseType(classElement.thisType, classElement);

  // Collect and process all @inject fields
  final injectFields = classElement.fields
      .where((f) => _isInjectField(f))
      .map(_parseInjectField)
      .toList();

  final injectMethod = Method((b) {
    b
      ..name = '_inject'
      ..returns = refer('void')
      ..requiredParameters.add(
        Parameter((p) {
          p
            ..name = 'instance'
            ..type = CodeBuilderEmitters.resolveTypeRef(classType);
        }),
      )
      ..body = Block((body) {
        for (final field in injectFields) {
          final scopeExpr = CodeBuilderEmitters.openScope(
            scopeName: field.scopeName,
          );
          final resolveExpr = CodeBuilderEmitters.resolveCall(
            scopeExpr: scopeExpr,
            parsedType: field.parsedType,
            named: field.namedValue,
          );
          body.statements.add(
            refer(
              'instance',
            ).property(field.fieldName).assign(resolveExpr).statement,
          );
        }
      });
  });

  final mixin = Mixin((b) {
    b
      ..name = mixinName
      ..methods.add(injectMethod);
  });

  final library = Library((b) => b..body.add(mixin));
  final emitter = DartEmitter(useNullSafetySyntax: true);
  return '${library.accept(emitter)}';
}