docs: public void visit(ASTNode[] nodes, SourceUnit source) {
          if (!(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
              throw new RuntimeException("Internal error: wrong types: $node.class / $parent.class");
          }
          AnnotationNode node = (AnnotationNode) nodes[0];
          AnnotatedNode parent = (AnnotatedNode) nodes[1];
  
          if (VetoableASTTransformation.hasVetoableAnnotation(parent)) {
              // VetoableASTTransformation will handle both @Bindable and @Vetoable
              return;
          }
  
          ClassNode declaringClass = parent.getDeclaringClass();
          if (parent instanceof FieldNode) {
              if ((((FieldNode) parent).getModifiers() & Opcodes.ACC_FINAL) != 0) {
                  source.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage(
                          new SyntaxException("@groovy.beans.Bindable cannot annotate a final property.",
                                  node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()),
                          source));
              }
  
              if (VetoableASTTransformation.hasVetoableAnnotation(parent.getDeclaringClass())) {
                  // VetoableASTTransformation will handle both @Bindable and @Vetoable
                  return;
              }
              addListenerToProperty(source, node, declaringClass, (FieldNode) parent);
          } else if (parent instanceof ClassNode) {
              addListenerToClass(source, (ClassNode) parent);
          }
      }