private static <T> void processConstructor(CtConstructor<T> c, CtClass<T> toMerge) {
    CtStatement firstStmt = c.getBody().getStatements().get(0);
    if (firstStmt instanceof CtInvocation) {
      CtInvocation<?> superConstructorCall = (CtInvocation) firstStmt;
      if (!(superConstructorCall.getExecutable().getDeclaration() instanceof CtConstructor)) return;
      CtConstructor superConstructor =
          (CtConstructor) superConstructorCall.getExecutable().getDeclaration();
      if (superConstructor.getDeclaringType() == toMerge) {
        CtBlock superConstructorBody = c.getFactory().Core().clone(superConstructor.getBody());
        superConstructorBody.accept(
            new CtScanner() {
              @Override
              public <T> void visitCtParameterReference(CtParameterReference<T> ref) {
                int parameterOrder = superConstructor.getParameters().indexOf(ref.getDeclaration());
                ref.setDeclaringExecutable(c.getReference());
                CtExpression<?> arg = superConstructorCall.getArguments().get(parameterOrder);
                if (!(arg instanceof CtVariableAccess))
                  throw sgce("super() should be directly called in " + c);
                CtVariable param = ((CtVariableAccess) arg).getVariable().getDeclaration();
                if (!(param instanceof CtParameter))
                  throw sgce("super() should be directly called in " + c);
                ref.setSimpleName(param.getSimpleName());

                super.visitCtParameterReference(ref);
              }
            });
        c.getBody().removeStatement(firstStmt);
        List<CtStatement> superConstructorBodyStatements = superConstructorBody.getStatements();
        for (int i = superConstructorBodyStatements.size() - 1; i >= 0; i--) {
          c.getBody().insertBegin(superConstructorBodyStatements.get(i));
        }
      }
    }
  }
  private static <T> void processOverridden(
      CtClass<?> mergeInto, CtClass<?> toMerge, final CtMethod<T> methodToMerge) {
    List<CtInvocation<T>> superInvocations =
        mergeInto.getElements(
            new Filter<CtInvocation<T>>() {
              @Override
              public boolean matches(CtInvocation<T> invocation) {
                if (!(invocation.getTarget() instanceof CtSuperAccess)) return false;
                CtExecutable<?> m = invocation.getExecutable().getDeclaration();
                return m != null && MethodNode.overrides((CtMethod<?>) m, methodToMerge);
              }
            });

    methodToMerge.setSimpleName(classPrefixedName(toMerge, methodToMerge));
    methodToMerge.setVisibility(PRIVATE);
    removeAnnotation(methodToMerge, Override.class);

    for (CtInvocation<T> superInvocation : superInvocations) {
      superInvocation.setTarget(null);
      superInvocation.setExecutable(methodToMerge.getReference());
    }
    add(mergeInto, methodToMerge, mergeInto::addMethod);
  }