visitClassElement method

  1. @override
void visitClassElement(
  1. ClassElement element
)
override

Implementation

@override
void visitClassElement(ClassElement element) {
  super.visitClassElement(element);

  if (!controllerChecker.hasAnnotationOf(element)) {
    return;
  }

  if (_controller != null) {
    throw Exception('Only one controller class per file is allowed');
  }

  final annotation = controllerChecker.annotationsOf(element);

  if (annotation.length > 1) {
    throw Exception('Only one controller annotation per class is allowed');
  }

  if (element.constructors.isEmpty) {
    throw Exception('No constructor found in ${element.name}');
  }

  if (element.constructors.every((e) => e.isPrivate)) {
    throw Exception('No public constructor found in ${element.name}');
  }

  _controller = element;
  _constructor = element.constructors.first;
  if (_constructor case ConstructorElement(:final formalParameters)) {
    _params.addAll(formalParameters.map(MetaParam.fromParam));
  }

  final controller = ControllerAnnotation.fromAnnotation(annotation.first);
  _path = controller.path;
  _type = controller.type;
  final controllerName = element.name ?? 'Unknown';
  final methodVisitor = MethodVisitor(controllerName);

  // The controller's own methods first, so an override beats the
  // annotation it inherits.
  element.accept(methodVisitor);

  for (final supertype in element.allSupertypes) {
    final superElement = supertype.element;

    final inherits =
        superElement.methods.any(methodChecker.hasAnnotationOf) ||
        superElement.methods.any(consumesChecker.hasAnnotationOf);

    if (!inherits) {
      continue;
    }

    if (supertype.typeArguments.isNotEmpty) {
      throw Exception(
        'Controller $controllerName inherits endpoints from generic type '
        '${superElement.name}<${supertype.typeArguments.join(', ')}>, which '
        'is not supported: the inherited signatures still refer to the type '
        'parameters, so the generated bindings would be wrong. Move the '
        'endpoints onto $controllerName, or make the base non-generic.',
      );
    }

    superElement.accept(methodVisitor);
  }

  _methods.addAll(methodVisitor.methods.values.expand((e) => e));
  _consumers.addAll(methodVisitor.consumers);
}