private static void generateParametersForDelegateCall(
      GrChangeInfoImpl grInfo, GrMethod method, StringBuilder buffer) {
    buffer.append("(");

    final GrParameter[] oldParameters = method.getParameterList().getParameters();
    final JavaParameterInfo[] parameters = grInfo.getNewParameters();

    String[] params = new String[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
      JavaParameterInfo parameter = parameters[i];
      final int oldIndex = parameter.getOldIndex();
      if (oldIndex >= 0) {
        params[i] = oldParameters[oldIndex].getName();
      } else {
        params[i] = parameter.getDefaultValue();
      }
    }
    buffer.append(StringUtil.join(params, ","));
    buffer.append(");");
  }
  private static GrParameter createNewParameter(
      @NotNull PsiSubstitutor substitutor,
      @NotNull PsiMethod context,
      @NotNull GrParameterList parameterList,
      @NotNull JavaParameterInfo newParameter,
      @NotNull String newName) {
    GroovyPsiElementFactory factory =
        GroovyPsiElementFactory.getInstance(parameterList.getProject());
    String typeText = newParameter.getTypeText();
    if (newParameter instanceof GrParameterInfo && (typeText.isEmpty() || "def".equals(typeText))) {
      return factory.createParameter(newName, null, getInitializer(newParameter), parameterList);
    }

    PsiType type =
        substitutor.substitute(newParameter.createType(context, parameterList.getManager()));
    return factory.createParameter(
        newName,
        type == null ? null : type.getCanonicalText(),
        getInitializer(newParameter),
        parameterList);
  }
  @Nullable
  private static GrExpression createDefaultValue(
      GroovyPsiElementFactory factory,
      JavaChangeInfo changeInfo,
      JavaParameterInfo info,
      final GrArgumentList list) {
    if (info.isUseAnySingleVariable()) {
      final PsiResolveHelper resolveHelper =
          JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
      final PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager());
      final VariablesProcessor processor =
          new VariablesProcessor(false) {
            @Override
            protected boolean check(PsiVariable var, ResolveState state) {
              if (var instanceof PsiField
                  && !resolveHelper.isAccessible((PsiField) var, list, null)) return false;
              if (var instanceof GrVariable
                  && PsiUtil.isLocalVariable(var)
                  && list.getTextRange().getStartOffset() <= var.getTextRange().getStartOffset()) {
                return false;
              }
              if (PsiTreeUtil.isAncestor(var, list, false)) return false;
              final PsiType _type =
                  var instanceof GrVariable ? ((GrVariable) var).getTypeGroovy() : var.getType();
              final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(_type);
              return type.isAssignableFrom(varType);
            }

            @Override
            public boolean execute(@NotNull PsiElement pe, @NotNull ResolveState state) {
              super.execute(pe, state);
              return size() < 2;
            }
          };
      ResolveUtil.treeWalkUp(list, processor, false);
      if (processor.size() == 1) {
        final PsiVariable result = processor.getResult(0);
        return factory.createExpressionFromText(result.getName(), list);
      }
      if (processor.size() == 0) {
        final PsiClass parentClass = PsiTreeUtil.getParentOfType(list, PsiClass.class);
        if (parentClass != null) {
          PsiClass containingClass = parentClass;
          final Set<PsiClass> containingClasses = new HashSet<PsiClass>();
          final PsiElementFactory jfactory = JavaPsiFacade.getElementFactory(list.getProject());
          while (containingClass != null) {
            if (type.isAssignableFrom(jfactory.createType(containingClass, PsiSubstitutor.EMPTY))) {
              containingClasses.add(containingClass);
            }
            containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class);
          }
          if (containingClasses.size() == 1) {
            return factory.createThisExpression(
                containingClasses.contains(parentClass)
                    ? null
                    : containingClasses.iterator().next());
          }
        }
      }
    }

    final String value = info.getDefaultValue();
    return !StringUtil.isEmpty(value) ? factory.createExpressionFromText(value, list) : null;
  }
  private static void processMethodUsage(
      PsiElement element,
      JavaChangeInfo changeInfo,
      boolean toChangeArguments,
      boolean toCatchExceptions,
      GrClosureSignatureUtil.ArgInfo<PsiElement>[] map,
      PsiSubstitutor substitutor) {
    if (map == null) return;
    if (changeInfo.isNameChanged()) {
      if (element instanceof GrReferenceElement) {
        element = ((GrReferenceElement) element).handleElementRename(changeInfo.getNewName());
      }
    }
    if (toChangeArguments) {
      JavaParameterInfo[] parameters = changeInfo.getNewParameters();
      GrArgumentList argumentList = PsiUtil.getArgumentsList(element);
      GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(element.getProject());
      if (argumentList == null) {
        if (element instanceof GrEnumConstant) {
          argumentList = factory.createArgumentList();
          argumentList = (GrArgumentList) element.add(argumentList);
        } else {
          return;
        }
      }
      Set<PsiElement> argsToDelete = new HashSet<PsiElement>(map.length * 2);
      for (GrClosureSignatureUtil.ArgInfo<PsiElement> argInfo : map) {
        argsToDelete.addAll(argInfo.args);
      }

      for (JavaParameterInfo parameter : parameters) {
        int index = parameter.getOldIndex();
        if (index >= 0) {
          argsToDelete.removeAll(map[index].args);
        }
      }

      for (PsiElement arg : argsToDelete) {
        arg.delete();
      }

      boolean skipOptionals = false;
      PsiElement anchor = null; // PsiTreeUtil.getChildOfAnyType(argumentList, GrExpression.class,
      // GrNamedArgument.class);
      for (int i = 0; i < parameters.length; i++) {
        JavaParameterInfo parameter = parameters[i];
        int index = parameter.getOldIndex();
        if (index >= 0) {
          GrClosureSignatureUtil.ArgInfo<PsiElement> argInfo = map[index];
          List<PsiElement> arguments = argInfo.args;
          if (argInfo.isMultiArg) { // arguments for Map and varArg
            if ((i != 0
                    || !(!arguments.isEmpty()
                        && arguments.iterator().next() instanceof GrNamedArgument))
                && (i != parameters.length - 1 || !parameter.isVarargType())) {
              final PsiType type =
                  parameter.createType(
                      changeInfo.getMethod().getParameterList(), argumentList.getManager());
              final GrExpression arg =
                  GroovyRefactoringUtil.generateArgFromMultiArg(
                      substitutor, arguments, type, element.getProject());
              for (PsiElement argument : arguments) {
                argument.delete();
              }
              anchor = argumentList.addAfter(arg, anchor);
              JavaCodeStyleManager.getInstance(anchor.getProject()).shortenClassReferences(anchor);
            }
          } else { // arguments for simple parameters
            if (arguments.size() == 1) { // arg exists
              PsiElement arg = arguments.iterator().next();
              if (i == parameters.length - 1 && parameter.isVarargType()) {
                if (arg instanceof GrSafeCastExpression) {
                  PsiElement expr = ((GrSafeCastExpression) arg).getOperand();
                  if (expr instanceof GrListOrMap && !((GrListOrMap) expr).isMap()) {
                    final PsiElement copy = expr.copy();
                    PsiElement[] newVarargs = ((GrListOrMap) copy).getInitializers();
                    for (PsiElement vararg : newVarargs) {
                      anchor = argumentList.addAfter(vararg, anchor);
                    }
                    arg.delete();
                    continue;
                  }
                }
              }

              PsiElement curArg = getNextOfType(argumentList, anchor, GrExpression.class);
              if (curArg == arg) {
                anchor = arg;
              } else {
                final PsiElement copy = arg.copy();
                anchor = argumentList.addAfter(copy, anchor);
                arg.delete();
              }
            } else { // arg is skipped. Parameter is optional
              skipOptionals = true;
            }
          }
        } else {
          if (skipOptionals && isParameterOptional(parameter)) continue;

          if (forceOptional(parameter)) {
            skipOptionals = true;
            continue;
          }
          try {

            GrExpression value = createDefaultValue(factory, changeInfo, parameter, argumentList);
            if (i > 0 && (value == null || anchor == null)) {
              PsiElement comma =
                  Factory.createSingleLeafElement(
                          GroovyTokenTypes.mCOMMA,
                          ",",
                          0,
                          1,
                          SharedImplUtil.findCharTableByTree(argumentList.getNode()),
                          argumentList.getManager())
                      .getPsi();
              if (anchor == null) anchor = argumentList.getLeftParen();

              anchor = argumentList.addAfter(comma, anchor);
            }
            if (value != null) {
              anchor = argumentList.addAfter(value, anchor);
            }
          } catch (IncorrectOperationException e) {
            LOG.error(e.getMessage());
          }
        }
      }

      GrCall call = GroovyRefactoringUtil.getCallExpressionByMethodReference(element);
      if (argumentList.getText().trim().isEmpty()
          && (call == null || !PsiImplUtil.hasClosureArguments(call))) {
        argumentList = argumentList.replaceWithArgumentList(factory.createArgumentList());
      }
      CodeStyleManager.getInstance(argumentList.getProject()).reformat(argumentList);
    }

    if (toCatchExceptions) {
      final ThrownExceptionInfo[] exceptionInfos = changeInfo.getNewExceptions();
      PsiClassType[] exceptions = getExceptions(exceptionInfos, element, element.getManager());
      fixExceptions(element, exceptions);
    }
  }
  private static boolean processPrimaryMethodInner(
      JavaChangeInfo changeInfo, GrMethod method, @Nullable PsiMethod baseMethod) {
    if (changeInfo.isNameChanged()) {
      String newName =
          baseMethod == null
              ? changeInfo.getNewName()
              : RefactoringUtil.suggestNewOverriderName(
                  method.getName(), baseMethod.getName(), changeInfo.getNewName());
      if (newName != null && !newName.equals(method.getName())) {
        method.setName(changeInfo.getNewName());
      }
    }

    final GrModifierList modifierList = method.getModifierList();
    if (changeInfo.isVisibilityChanged()) {
      modifierList.setModifierProperty(changeInfo.getNewVisibility(), true);
    }

    PsiSubstitutor substitutor =
        baseMethod != null ? calculateSubstitutor(method, baseMethod) : PsiSubstitutor.EMPTY;

    final PsiMethod context = changeInfo.getMethod();
    GrTypeElement oldReturnTypeElement = method.getReturnTypeElementGroovy();
    if (changeInfo.isReturnTypeChanged()) {
      CanonicalTypes.Type newReturnType = changeInfo.getNewReturnType();
      if (newReturnType == null) {
        if (oldReturnTypeElement != null) {
          oldReturnTypeElement.delete();
          if (modifierList.getModifiers().length == 0) {
            modifierList.setModifierProperty(GrModifier.DEF, true);
          }
        }
      } else {
        PsiType type = newReturnType.getType(context, method.getManager());
        GrReferenceAdjuster.shortenAllReferencesIn(
            method.setReturnType(substitutor.substitute(type)));
        if (oldReturnTypeElement == null) {
          modifierList.setModifierProperty(GrModifier.DEF, false);
        }
      }
    }

    JavaParameterInfo[] newParameters = changeInfo.getNewParameters();
    final GrParameterList parameterList = method.getParameterList();
    GrParameter[] oldParameters = parameterList.getParameters();
    final PsiParameter[] oldBaseParams =
        baseMethod != null ? baseMethod.getParameterList().getParameters() : null;

    Set<GrParameter> toRemove = new HashSet<GrParameter>(oldParameters.length);
    ContainerUtil.addAll(toRemove, oldParameters);

    GrParameter anchor = null;
    final GrDocComment docComment = method.getDocComment();
    final GrDocTag[] tags = docComment == null ? null : docComment.getTags();

    for (JavaParameterInfo newParameter : newParameters) {
      // if old parameter name differs from base method parameter name we don't change it
      final String newName;
      final int oldIndex = newParameter.getOldIndex();
      if (oldIndex >= 0 && oldBaseParams != null) {
        final String oldName = oldParameters[oldIndex].getName();
        if (oldName.equals(oldBaseParams[oldIndex].getName())) {
          newName = newParameter.getName();
        } else {
          newName = oldName;
        }
      } else {
        newName = newParameter.getName();
      }

      final GrParameter oldParameter = oldIndex >= 0 ? oldParameters[oldIndex] : null;

      if (docComment != null && oldParameter != null) {
        final String oldName = oldParameter.getName();
        for (GrDocTag tag : tags) {
          if ("@param".equals(tag.getName())) {
            final GrDocParameterReference parameterReference = tag.getDocParameterReference();
            if (parameterReference != null && oldName.equals(parameterReference.getText())) {
              parameterReference.handleElementRename(newName);
            }
          }
        }
      }

      GrParameter grParameter =
          createNewParameter(substitutor, context, parameterList, newParameter, newName);
      if (oldParameter != null) {
        grParameter.getModifierList().replace(oldParameter.getModifierList());
      }

      if ("def".equals(newParameter.getTypeText())) {
        grParameter.getModifierList().setModifierProperty(GrModifier.DEF, true);
      } else if (StringUtil.isEmpty(newParameter.getTypeText())) {
        grParameter.getModifierList().setModifierProperty(GrModifier.DEF, false);
      }

      anchor = (GrParameter) parameterList.addAfter(grParameter, anchor);
    }

    for (GrParameter oldParameter : toRemove) {
      oldParameter.delete();
    }
    JavaCodeStyleManager.getInstance(parameterList.getProject())
        .shortenClassReferences(parameterList);
    CodeStyleManager.getInstance(parameterList.getProject()).reformat(parameterList);

    if (changeInfo.isExceptionSetOrOrderChanged()) {
      final ThrownExceptionInfo[] infos = changeInfo.getNewExceptions();
      PsiClassType[] exceptionTypes = new PsiClassType[infos.length];
      for (int i = 0; i < infos.length; i++) {
        ThrownExceptionInfo info = infos[i];
        exceptionTypes[i] = (PsiClassType) info.createType(method, method.getManager());
      }

      PsiReferenceList thrownList =
          GroovyPsiElementFactory.getInstance(method.getProject()).createThrownList(exceptionTypes);
      thrownList = (PsiReferenceList) method.getThrowsList().replace(thrownList);
      JavaCodeStyleManager.getInstance(thrownList.getProject()).shortenClassReferences(thrownList);
      CodeStyleManager.getInstance(method.getProject()).reformat(method.getThrowsList());
    }
    return true;
  }