/**
  * @return a {@link JvmOperation} with common denominator argument types of all given operations
  */
 protected JvmOperation deriveGenericDispatchOperationSignature(
     List<JvmOperation> sortedOperations, JvmGenericType target) {
   if (sortedOperations.isEmpty()) return null;
   final Iterator<JvmOperation> iterator = sortedOperations.iterator();
   JvmOperation first = iterator.next();
   JvmOperation result = typesFactory.createJvmOperation();
   target.getMembers().add(result);
   for (int i = 0; i < first.getParameters().size(); i++) {
     JvmFormalParameter parameter = typesFactory.createJvmFormalParameter();
     result.getParameters().add(parameter);
     parameter.setParameterType(getTypeProxy(parameter));
     JvmFormalParameter parameter2 = first.getParameters().get(i);
     parameter.setName(parameter2.getName());
   }
   jvmTypesBuilder.setBody(result, compileStrategies.forDispatcher(result, sortedOperations));
   JvmVisibility commonVisibility = null;
   boolean isFirst = true;
   boolean allStatic = true;
   for (JvmOperation jvmOperation : sortedOperations) {
     Iterable<XtendFunction> xtendFunctions =
         filter(associations.getSourceElements(jvmOperation), XtendFunction.class);
     for (XtendFunction func : xtendFunctions) {
       JvmVisibility xtendVisibility =
           func.eIsSet(Xtend2Package.Literals.XTEND_FUNCTION__VISIBILITY)
               ? func.getVisibility()
               : null;
       if (isFirst) {
         commonVisibility = xtendVisibility;
         isFirst = false;
       } else if (commonVisibility != xtendVisibility) {
         commonVisibility = null;
       }
       associator.associate(func, result);
       if (!func.isStatic()) allStatic = false;
     }
     for (JvmTypeReference declaredException : jvmOperation.getExceptions())
       result.getExceptions().add(cloneWithProxies(declaredException));
   }
   if (commonVisibility == null) result.setVisibility(JvmVisibility.PUBLIC);
   else result.setVisibility(commonVisibility);
   result.setStatic(allStatic);
   return result;
 }
  protected void transform(XtendFunction source, JvmGenericType container) {
    JvmOperation operation = typesFactory.createJvmOperation();
    container.getMembers().add(operation);
    associator.associatePrimary(source, operation);
    String sourceName = source.getName();
    JvmVisibility visibility = source.getVisibility();
    if (source.isDispatch()) {
      if (!source.eIsSet(Xtend2Package.Literals.XTEND_FUNCTION__VISIBILITY))
        visibility = JvmVisibility.PROTECTED;
      sourceName = "_" + sourceName;
    }
    operation.setSimpleName(sourceName);
    operation.setVisibility(visibility);
    operation.setStatic(source.isStatic());
    for (XtendParameter parameter : source.getParameters()) {
      JvmFormalParameter jvmParam = typesFactory.createJvmFormalParameter();
      jvmParam.setName(parameter.getName());
      jvmParam.setParameterType(cloneWithProxies(parameter.getParameterType()));
      operation.getParameters().add(jvmParam);
      associator.associate(parameter, jvmParam);
      jvmTypesBuilder.translateAnnotationsTo(parameter.getAnnotations(), jvmParam);
    }
    JvmTypeReference returnType = null;
    if (source.getReturnType() != null) {
      returnType = cloneWithProxies(source.getReturnType());
    } else {
      returnType = getTypeProxy(operation);
    }
    operation.setReturnType(returnType);
    copyAndFixTypeParameters(source.getTypeParameters(), operation);
    for (JvmTypeReference exception : source.getExceptions()) {
      operation.getExceptions().add(cloneWithProxies(exception));
    }
    jvmTypesBuilder.translateAnnotationsTo(source.getAnnotationInfo().getAnnotations(), operation);
    CreateExtensionInfo createExtensionInfo = source.getCreateExtensionInfo();
    if (createExtensionInfo != null) {
      JvmTypeReference arrayList =
          typeReferences.getTypeForName(ArrayList.class, container, typeReferences.wildCard());
      JvmTypeReference hashMap =
          typeReferences.getTypeForName(
              HashMap.class, container, arrayList, cloneWithProxies(returnType));

      JvmField cacheVar =
          jvmTypesBuilder.toField(
              source, CREATE_CHACHE_VARIABLE_PREFIX + source.getName(), hashMap);
      cacheVar.setFinal(true);
      jvmTypesBuilder.setInitializer(cacheVar, compileStrategies.forCacheVariable(container));
      container.getMembers().add(cacheVar);

      JvmOperation initializer = typesFactory.createJvmOperation();
      container.getMembers().add(initializer);
      initializer.setSimpleName(CREATE_INITIALIZER_PREFIX + source.getName());
      initializer.setVisibility(JvmVisibility.PRIVATE);
      initializer.setReturnType(typeReferences.getTypeForName(Void.TYPE, source));
      for (JvmTypeReference exception : source.getExceptions()) {
        initializer.getExceptions().add(cloneWithProxies(exception));
      }

      jvmTypesBuilder.setBody(
          operation, compileStrategies.forCacheMethod(createExtensionInfo, cacheVar, initializer));

      // the first parameter is the created object
      JvmFormalParameter jvmParam = typesFactory.createJvmFormalParameter();
      jvmParam.setName(createExtensionInfo.getName());
      jvmParam.setParameterType(getTypeProxy(createExtensionInfo.getCreateExpression()));
      initializer.getParameters().add(jvmParam);
      associator.associate(createExtensionInfo, jvmParam);

      // add all others
      for (XtendParameter parameter : source.getParameters()) {
        jvmParam = typesFactory.createJvmFormalParameter();
        jvmParam.setName(parameter.getName());
        jvmParam.setParameterType(cloneWithProxies(parameter.getParameterType()));
        initializer.getParameters().add(jvmParam);
        associator.associate(parameter, jvmParam);
      }
      associator.associate(source, initializer);
      associator.associateLogicalContainer(createExtensionInfo.getCreateExpression(), operation);
      associator.associateLogicalContainer(source.getExpression(), initializer);
    } else {
      associator.associateLogicalContainer(source.getExpression(), operation);
    }
    jvmTypesBuilder.setDocumentation(operation, jvmTypesBuilder.getDocumentation(source));
  }