public static FunctionType makeFunctionType(
     ResolutionErrorListener listener,
     ClassElement element,
     List<VariableElement> parameters,
     Type returnType) {
   List<Type> parameterTypes = new ArrayList<Type>(parameters.size());
   Map<String, Type> optionalParameterTypes = null;
   Map<String, Type> namedParameterTypes = null;
   Type restParameter = null;
   for (VariableElement parameter : parameters) {
     Type type = parameter.getType();
     // TODO(scheglov) one we will make optional parameter not named,
     // check isOptional() before isNamed()
     if (parameter.isNamed()) {
       if (namedParameterTypes == null) {
         namedParameterTypes = new LinkedHashMap<String, Type>();
       }
       namedParameterTypes.put(parameter.getName(), type);
     } else if (parameter.isOptional()) {
       if (optionalParameterTypes == null) {
         optionalParameterTypes = new LinkedHashMap<String, Type>();
       }
       optionalParameterTypes.put(parameter.getName(), type);
     } else {
       parameterTypes.add(type);
     }
   }
   return FunctionTypeImplementation.of(
       element,
       parameterTypes,
       optionalParameterTypes,
       namedParameterTypes,
       restParameter,
       returnType);
 }
 @Override
 public Change createChange(IProgressMonitor pm) throws CoreException {
   pm.beginTask("", 1 + occurrences.size()); // $NON-NLS-1$
   try {
     // configure Change
     {
       change = new CompilationUnitChange(unit.getElementName(), unit);
       change.setEdit(new MultiTextEdit());
       change.setKeepPreviewEdits(true);
     }
     // replace occurrences with method invocation
     for (Occurrence occurence : occurrences) {
       pm.worked(1);
       SourceRange range = occurence.range;
       // may be replacement of duplicates disabled
       if (!replaceAllOccurrences && !occurence.isSelection) {
         continue;
       }
       // prepare invocation source
       String invocationSource;
       {
         StringBuilder sb = new StringBuilder();
         // may be returns value
         if (returnVariable != null) {
           String varTypeName = ExtractUtils.getTypeSource(returnVariable.getType());
           String originalName = returnVariable.getName();
           String occurrenceName = occurence.parameterOldToOccurrenceName.get(originalName);
           if (varTypeName.equals("dynamic")) {
             sb.append("var ");
           } else {
             sb.append(varTypeName);
             sb.append(" ");
           }
           sb.append(occurrenceName);
           sb.append(" = ");
         }
         // invocation itself
         sb.append(methodName);
         sb.append("(");
         boolean firstParameter = true;
         for (ParameterInfo parameter : parameters) {
           // may be comma
           if (firstParameter) {
             firstParameter = false;
           } else {
             sb.append(", ");
           }
           // argument name
           {
             String parameterOldName = parameter.getOldName();
             String argumentName = occurence.parameterOldToOccurrenceName.get(parameterOldName);
             sb.append(argumentName);
           }
         }
         sb.append(")");
         invocationSource = sb.toString();
         // statements as extracted with their ";", so add new one after invocation
         if (selectionStatements != null) {
           invocationSource += ";";
         }
       }
       // add replace edit
       TextEdit edit = new ReplaceEdit(range.getOffset(), range.getLength(), invocationSource);
       change.addEdit(edit);
       String msg =
           Messages.format(
               occurence.isSelection
                   ? RefactoringCoreMessages.ExtractMethodRefactoring_substitute_with_call
                   : RefactoringCoreMessages.ExtractMethodRefactoring_duplicates_single,
               methodName);
       change.addTextEditGroup(new TextEditGroup(msg, edit));
     }
     // add method declaration
     {
       // prepare environment
       String prefix = utils.getNodePrefix(parentMember);
       String eol = utils.getEndOfLine();
       // prepare annotations
       String annotations = "";
       {
         // may be "static"
         if (staticContext) {
           annotations = "static ";
         }
       }
       // prepare declaration source
       String declarationSource = null;
       {
         String returnExpressionSource = getMethodBodySource();
         // expression
         if (selectionExpression != null) {
           // add return type
           String returnTypeName = ExtractUtils.getTypeSource(selectionExpression);
           if (returnTypeName != null && !returnTypeName.equals("dynamic")) {
             annotations += returnTypeName + " ";
           }
           // just return expression
           declarationSource =
               annotations + getSignature() + " => " + returnExpressionSource + ";";
         }
         // statements
         if (selectionStatements != null) {
           if (returnVariable != null) {
             String returnTypeName = ExtractUtils.getTypeSource(returnVariable.getType());
             if (returnTypeName != null && !returnTypeName.equals("dynamic")) {
               annotations += returnTypeName + " ";
             }
           } else {
             annotations += "void ";
           }
           declarationSource = annotations + getSignature() + " {" + eol;
           declarationSource += returnExpressionSource;
           if (returnVariable != null) {
             declarationSource += prefix + "  return " + returnVariable.getName() + ";" + eol;
           }
           declarationSource += prefix + "}";
         }
       }
       // insert declaration
       if (declarationSource != null) {
         int offset = parentMember.getSourceInfo().getEnd();
         TextEdit edit = new ReplaceEdit(offset, 0, eol + eol + prefix + declarationSource);
         change.addEdit(edit);
         change.addTextEditGroup(
             new TextEditGroup(
                 Messages.format(
                     selectionExpression != null
                         ? RefactoringCoreMessages.ExtractMethodRefactoring_add_method_expression
                         : RefactoringCoreMessages.ExtractMethodRefactoring_add_method,
                     methodName),
                 edit));
       }
     }
     pm.worked(1);
     // done
     return change;
   } finally {
     pm.done();
   }
 }